메서드의 이름은 같지만 매개변수의 수나 타입이 달라야 한다. 오버로딩은 메서드의 서명을 다르게 하여, 메서드를 호출할 때 전달된 인자에 맞는 메서드를 자동으로 선택할 수 있게 한다.
메서드 서명 다름: 메서드 이름은 같지만 매개변수의 수, 타입, 순서가 달라야 한다.
컴파일 타임 다형성: 컴파일 타임에 어떤 메서드가 호출될지 결정된다.
반환 타입은 영향 없음: 반환 타입만으로는 오버로딩을 구분할 수 없다. 매개변수의 차이만로 구분된다.
public class Calculator {
// 정수 두 개를 더하는 메서드
public int add(int a, int b) {
return a + b;
}
// 실수 두 개를 더하는 메서드
public double add(double a, double b) {
return a + b;
}
// 정수 세 개를 더하는 메서드
public int add(int a, int b, int c) {
return a + b + c;
}
}
오버라이딩 (Overriding)
오버라이딩은 상속받은 클래스에서 부모 클래스의 메서드를 재정의하는 것을 의미한다
오버라이딩을 통해 자식 클래스에서 부모 클래스의 메서드를 자신에게 맞게 구현할 수 있다
메서드 서명 동일: 부모 클래스와 자식 클래스의 메서드는 이름, 반환 타입, 매개변수 리스트가 모두 동일해야 한다.
런타임 다형성: 런타임에 어떤 메서드가 호출될지 결정된다.
@Override 어노테이션 사용: 메서드가 오버라이딩되고 있음을 명시하기 위해
@Override 어노테이션을 사용할 수 있다
public class Animal {
// 부모 클래스 메서드
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
public class Dog extends Animal {
// 부모 클래스의 메서드를 오버라이딩
@Override
public void makeSound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.makeSound(); // "Dog barks" 출력
}
}
@WebServlet("/user")
public class UserController extends HttpServlet {
private UserService userService = new UserService();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int userId = Integer.parseInt(request.getParameter("id"));
User user = userService.getUserById(userId);
request.setAttribute("user", user);
RequestDispatcher dispatcher = request.getRequestDispatcher("/user.jsp");
dispatcher.forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 사용자 정보 업데이트 로직
User user = new User();
user.setName(request.getParameter("name"));
user.setAge(Integer.parseInt(request.getParameter("age")));
userService.updateUser(user);
response.sendRedirect("/user");
}
}
Service:
public class UserService {
public User getUserById(int id) {
// 데이터베이스에서 사용자 정보를 조회하고 반환
// 예를 들어, UserDAO를 사용하여 데이터베이스 쿼리
User user = userDAO.findById(id);
return user;
}
public void updateUser(User user) {
// 사용자 정보를 업데이트
userDAO.update(user);
}
}
java에서 Map 인터페이스의 구현체는 HashMap, TreeMap, LinkedHashMap 이 있다.
주요 메서드
A put(K key, V value)
지정된 key와 value를 매핑하여 Map에 추가한다
V get(Object key)
지정된 key에 매핑된 value 반환. key가 존재하지 않으면 null을 반환한
boolean containsKey (object Key)
지정된 key가 Map에 있는가
boolean containsValue(object value)
지정된 value가 Map에 있는가
V remove(object key)
지정된 key와 그에 매핑된 value를 Map에서 제거하여 value 반환
int size()
Map에 저장된 key-value 쌍의 개수 반환
void clear()
Map의 모든 요소 제거
주요 구현 클래스
HashMap<K, V>
해시 테이블을 기반으로 key-value쌍 저장. O(1)의 시간 복잡도를 가진다
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
// HashMap 생성
Map<String, Integer> hashMap = new HashMap<>();
// 요소 추가
hashMap.put("apple", 10);
hashMap.put("banana", 20);
hashMap.put("cherry", 15);
// 요소 접근
System.out.println("Value of apple: " + hashMap.get("apple")); // 10
// 요소 수정
hashMap.put("banana", 25); // banana의 value를 25로 수정
// 요소 제거
hashMap.remove("cherry");
// 모든 key와 value 출력
System.out.println("HashMap:");
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// HashMap 크기 확인
System.out.println("Size of HashMap: " + hashMap.size());
}
}
Value of apple: 10
HashMap:
Key: apple, Value: 10
Key: banana, Value: 25
Size of HashMap: 2
TreeMap<K, V>
Red-Black 트리를 사용하여 key-value 쌍을 정렬된 상태로 저장 key에 대해 정렬된 순서를 유지하며 O(log n)의 시간 복잡도를 가짐
import java.util.Map;
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
// TreeMap 생성
Map<String, Integer> treeMap = new TreeMap<>();
// 요소 추가
treeMap.put("apple", 10);
treeMap.put("banana", 20);
treeMap.put("cherry", 15);
// 요소 접근
System.out.println("Value of banana: " + treeMap.get("banana")); // 20
// 요소 수정
treeMap.put("banana", 25); // banana의 value를 25로 수정
// 요소 제거
treeMap.remove("cherry");
// 모든 key와 value 출력
System.out.println("TreeMap:");
for (Map.Entry<String, Integer> entry : treeMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// TreeMap 크기 확인
System.out.println("Size of TreeMap: " + treeMap.size());
}
}
Value of banana: 20
TreeMap:
Key: apple, Value: 10 //사전 순으로 정렬된다
Key: banana, Value: 25
Size of TreeMap: 2
Hashtable<K, V>
해시맵을 기반으로 인덱스를 주어 빠른 검색속도를 보장한다. 평균 시간복잡도는 O(1) 이다.
import java.util.Hashtable;
import java.util.Map;
public class HashtableExample {
public static void main(String[] args) {
// Hashtable 생성
Map<String, Integer> hashtable = new Hashtable<>();
// 요소 추가
hashtable.put("apple", 10);
hashtable.put("banana", 20);
hashtable.put("cherry", 15);
// 요소 접근
System.out.println("Value of banana: " + hashtable.get("banana")); // 20
// 요소 수정
hashtable.put("banana", 25); // banana의 value를 25로 수정
// 요소 제거
hashtable.remove("cherry");
// 모든 key와 value 출력
System.out.println("Hashtable:");
for (Map.Entry<String, Integer> entry : hashtable.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// Hashtable 크기 확인
System.out.println("Size of Hashtable: " + hashtable.size());
}
}
Value of banana: 20
Hashtable:
Key: banana, Value: 25
Key: apple, Value: 10
Size of Hashtable: 2
IoC컨테이너에 Bean으로 등록해주며 이 클래스가 Controller로 사용된다는 것을 알려준다.
@Controller
public class HomeController {
@GetMapping("/home")
public String home(Model model) {
model.addAttribute("message", "Welcome to the home page!");
return "home"; // "home"은 View의 이름을 나타냅니다.
}
}
1. 구체화된 @Component
Component는 스프링에서 관리하는 컴포넌트를 나타내는 어노테이션으로 해당 클래스가 스프링 IOC 컨테이너에서 관리되어야 함을 정의한다.
@Controller는 @Component의 구체화된 형태로 스프링 MVC에서 웹 어플리케이션의 요청을 처리하는 컨트롤러 역할이다.
2. Bean으로 등록
스프링 IOC 컨테이너는 애플리케이션을 구성하는 여러 객체들을 관리하고 이를 Bean이라고 한다.
@Controller 어노테이션이 붙은 클래스는 컨트롤러로 사용될 것임을 명시하며, 이를 스프링에 등록하여 관리하도록 요청한다.
3. Controller로 사용
Controller로 지정된 클래스 웹 애플리케이션에서 HTTP 요청을 처리하고 응답을 반환하는 역할을 한다. 주로 HTML 뷰를 렌더링 하거나 JSON 형태의 데이터를 반환하는데 사용된다.
그 종류에는 View를 리턴하는 @Controller와 Json 데이터를 리턴하는 @RestController가 있다.
@Controller
@Controller 어노테이션은 스프링 MVC 패턴에서 사용되며 주로 View 기반의 애플리케이션에서 요청을 처리하고
화면을 반환한다.
@Controller
public class HomeController {
@GetMapping("/home")
public String home(Model model) {
model.addAttribute("message", "Welcome to the home page!");
return "home"; // "home"은 View의 이름을 나타냅니다.
}
}
/home 경로로 들어오는 Get 요청을 처리하고 home 문자열을 반환하여
View Resolver가 실제 View를 찾아 렌더링한다.
즉, @Controller로 지정된 클래스의 메서드들은 HTML 페이지를 반환하거나
View의 값을 지정하여 이를 랜더링하는 역할을 수행한다.
@RestController
@RestController 어노테이션은 @Controller의 확장 형태이다.
JSON 또는 XML 형식의 데이터를 반환하는 RESTful 서비스의 컨트롤러에 사용된다.
@RestController로 지정된 클래스의 모든 메서드는 @ResponseBody가 적용된 것으로 간주된다.
메서드가 반환하는 객체를 문자열 형태로 변환하여 클라이언트에게 전송한다.
@RestController
@RequestMapping("/api")
public class ProductController {
@GetMapping("/products/{id}")
public ResponseEntity<Product> getProductById(@PathVariable Long id) {
// id에 해당하는 제품 정보를 조회하여 반환
Product product = productService.getProductById(id);
if (product != null) {
return ResponseEntity.ok(product);
} else {
return ResponseEntity.notFound().build();
}
}
}
/api/products/{id} 경로로 들어오는 GET 요청을 처리하고
Product 객체를 JSON 형식으로 변환하여 클라이언트에게 반환한다.
컨트롤러에 사용되는 Mapping 어노테이션 (HTTP 요청)
@RequestMapping
클라이언트의 HTTP 요청 (URL)이 올 때 어떤 메소드로 처리할지 연결하는 어노테이션이다.
주로 컨트롤러 클래스나 메서드 위에 붙여서 사용되며 옵션을 설정해 주소나 매핑의 방식을 정할 수 있다.
옵션
설명
value
연결할 URL을 설정한다. 다른 옵션이 없다면 생략 가능하다.
method
RequestMethod를 통해 사용되는데 주로 GET, POST, PUT, DELETE를 많이 사용한다.
쿼리 스트링: URL의 끝 부분에 위치하며 ? 문자로 시작하여 키와 값의 쌍으로 구성된 데이터를 포함한다.
주로 웹에서 GET방식의 요청 시 데이터를 전달하는 데 사용된다.
예를 들어 클라이언트가 http://localhost:8080/api/user?username=johndoe&password=12345 와 같은 쿼리 스트링을 포함하는 요청을 보낼 때
메서드는 username=johndoe와 password=12345를 @RequestParam 어노테이션을 통해 받는다.
쿼리문의 파라미터 이름과 메소드에 적힌 이름이 같다면 굳이 어노테이션을 적어주지 않아도 된다.
@RequestBody
HTTP POST 요청의 본문(body) 데이터를 자바 객체로 변환하여 받을 때 사용되는 어노테이션이다.
주로 JSON이나 plain text형식의 데이터를 컨트롤러에서 처리할 때 사용된다.
이 어노테이션을 사용하면 클라이언트가 전송한 데이터를 자바 객체로 변환하는 과정을 자동으로 처리할 수 있다.
HTTP POST 요청 처리
@RequestBody 어노테이션은 POST 요청의 본문(body)에 포함된 데이터를 읽어와서 자바 객체로 변환한다.
주로 JSON 형식의 데이터를 자바 객체로 변환하여 컨트롤러에서 사용할 수 있도록 한다.
메서드 전체를 문자열 형식으로 읽기 때문에 때문에 redirect시 클라이언트에서 처리해주어야 한다.
MessageConverter
스프링은 @RequestBody 어노테이션이 적용된 메서드에 대해 HttpMessageConverter 인터페이스를 사용하여 HTTP 요청의 본문을 자바 객체로 변환한다.
예를 들어, JSON 데이터를 처리하기 위해 MappingJackson2HttpMessageConverter가 사용되는데 이 Converter는 JSON 데이터를 자바 객체로 변환할 수 있다.
지원하는 데이터 타입
주로 text/plain 또는 application/json 타입의 데이터를 처리할 때 사용된다.
text/plain은 단순한 문자열 형식의 데이터를 받을 때 사용된다.
application/json은 JSON 형식의 데이터를 받을 때 주로 사용된다.
Ajax 통신과의 관련
Ajax를 통해 JSON 형식으로 데이터를 서버에 전송할 때 @RequestBody 어노테이션이 주로 사용된다.
클라이언트 측 JavaScript에서 JSON 형식으로 데이터를 생성하여 POST 요청을 보내면, 스프링 MVC는 @RequestBody를 통해 이 데이터를 자바 객체로 변환하여 컨트롤러에서 사용할 수 있다.
@RestController
@RequestMapping("/api")
public class UserController {
@PostMapping("/user")
public ResponseEntity<String> createUser(@RequestBody User user) {
// @RequestBody를 통해 전송된 JSON 데이터가 User 객체로 자동 변환됩니다.
// User 객체를 이용한 로직 처리 (예시에서는 단순히 사용자 정보 출력)
String response = "Received user: " + user.toString();
return ResponseEntity.ok(response);
}
}
위 예시에서 /api/user 경로로 POST 요청이 들어오면 createUser 메서드가 실행된다.
이 메서드의 매개변수 @RequestBody User user는 클라이언트가 전송한 JSON 데이터를
자동으로 User 객체로 변환하여 받는다.
@PathVariable
URL 경로에서 변수 값을 추출하여 메서드의 매개변수로 전달받을 때 사용된다.
주로 RESTful 웹 서비스에서 URL 경로에 동적인 값을 넣어 요청을 처리할 때 활용된다.
URL 경로에서 변수 값 추출
@PathVariable 어노테이션은 URL 경로에 포함된 {변수이름} 부분의 값을 추출하여 메서드의 매개변수로 전달받는다.
예를 들어, /api/user/{userId}와 같은 경로에서 userId라는 변수 값을 추출할 수 있다.
변수 이름 매칭:
기본적으로 {변수이름}과 메서드의 매개변수 이름이 동일해야한다. 이 경우 스프링은 자동으로 경로 변수 값을 매핑한다.
예를 들어, /api/user/{userId}라는 경로에서 userId라는 매개변수를 가진 메서드가 있으면, 스프링은 {userId}의 값을 userId 매개변수에 할당한다.
변수 이름 지정:
경우에 따라 URL 경로 변수의 이름과 메서드의 매개변수 이름이 다를 수 있다. 이 때는 @PathVariable("변수이름")과 같이 명시적으로 변수 이름을 지정한다.
예를 들어, /api/user/{id}라는 경로에서 메서드의 매개변수 이름이 userId일 경우 @PathVariable("id")로 명시하여 매핑할 수 있다.
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/user/{userId}")
public ResponseEntity<String> getUserInfo(@PathVariable Long userId) {
// @PathVariable을 통해 {userId} 값이 Long 타입으로 자동 변환되어 매개변수 userId에 전달됩니다.
// userId를 이용한 사용자 정보 조회 로직 (예시에서는 단순히 userId 출력)
String response = "User ID: " + userId;
return ResponseEntity.ok(response);
}
}
위 예시에서 /api/user/{userId} 경로로 GET 요청이 들어오면, getUserInfo 메서드가 실행된다.
{userId}는 클라이언트가 전송한 실제 사용자 ID 값으로 대체되고,
이 값을 @PathVariable Long userId를 통해 자동으로 userId 매개변수로 받아서 사용할 수 있다.
@ModelAttribute
클라이언트가 전달한 파라미터를 자바 객체의 필드에 할당한다.
주로 HTML 폼에서 입력된 데이터를 컨트롤러로 전송할 때 활용되며
여러 개의 파라미터를 한 번에 객체로 받아올 수 있다.
클라이언트 데이터 바인딩:
@ModelAttribute 어노테이션을 사용하면 클라이언트가 전송한 파라미터를 자바 객체에 할당한다.
클라이언트가 전송한 데이터는 자동으로 해당 객체의 Setter를 통해 필드에 설정된다. 생성자를 통해 초기화도 가능하다.
HTML 폼 데이터 처리
주로 HTML 폼에서 사용자가 입력한 데이터를 서버로 전송할 때 사용된다. 폼의 각 입력 필드의 이름과 자바 객체의 필드 이름이 일치해야 자동으로 할당된다.
@RequestParam과의 차이점
@RequestParam은 URL 쿼리 스트링이나 POST 요청의 특정 파라미터 값을 매개변수로 받아온다.
@ModelAttribute는 여러 개의 파라미터를 하나의 객체로 받아올 수 있다. 주로 HTML 폼에서 여러 입력 값을 한 번에 받아와야 할 때 유용하다.
Setter 메서드와 생성자 필요
@ModelAttribute를 사용할 때는 해당 객체에 값을 설정할 수 있는 Setter 메서드가 필요하다. 생성자도 있으면 좋다.
스프링은 Setter 메서드를 통해 입력된 데이터를 객체에 할당한다.
@Controller
@RequestMapping("/user")
public class UserController {
@PostMapping("/add")
public String addUser(@ModelAttribute UserForm userForm, Model model) {
// @ModelAttribute를 통해 userForm 객체에 클라이언트가 전송한 데이터가 자동으로 바인딩됩니다.
// UserForm 클래스는 폼에서 전송된 데이터를 받기 위한 DTO(Data Transfer Object)입니다.
// 예시에서는 받은 데이터를 모델에 추가하여 뷰로 전달합니다.
model.addAttribute("userForm", userForm);
return "userDetail"; // userDetail이라는 뷰를 반환
}
}
UserForm은 HTML 폼에서 입력된 데이터를 받기 위한 클래스이다.
@ModelAttribute 어노테이션을 사용하여
addUser메서드의 매개변수로 UserForm 객체를 받아와 클라이언트가 입력한 데이터를 자동으로 설정한다.
리다이렉션
클라이언트의 요청을 다른 URL로 전환한다.
스프링 MVC에서는 redirect:/주소 형식을 사용하여 리다이렉션을 수행할 수 있다.
이를 통해 다른 메서드나 경로를 재사용하고 클라이언트를 다른 페이지로 보낼 수 있다.
HTTP 상태 코드: 리다이렉션은 클라이언트에게 HTTP 상태 코드 302를 반환하여 임시적으로 리소스가 이동되었음을 알려준다.
리다이렉션 과정
리다이렉션 요청: 클라이언트가 요청한 작업이 완료되었을 때, 그 결과를 보여주기 위해 다른 페이지로 이동시키고 싶을 때 사용한다.
redirect:/주소지 형식: redirect: 다음에는 이동할 URL을 지정한다. 이 URL은 애플리케이션의 상대 경로일 수도 있고, 절대 경로일 수도 있다. 보통은 상대 경로를 사용하여 다른 컨트롤러 메서드나 정적 리소스 경로로 이동한다.
@Controller
public class LoginController {
@Autowired
private UserService userService;
@GetMapping("/loginForm")
public String loginForm() {
return "loginForm"; // 로그인 폼을 보여주는 뷰 이름
}
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password, HttpSession session) {
// 로그인 로직 처리
boolean isAuthenticated = userService.authenticate(username, password);
if (isAuthenticated) {
session.setAttribute("username", username);
return "redirect:/home"; // 로그인 성공 후 /home으로 리다이렉션
} else {
return "redirect:/loginForm?error=true"; // 로그인 실패 시 다시 로그인 폼으로 리다이렉션
}
}
@GetMapping("/home")
public String home() {
return "home"; // 홈 페이지 뷰 이름
}
}
1. /loginForm 경로에서는 로그인 폼을 보여주는 loginForm 뷰를 반환한다.
2. /login 경로에서는 POST 요청을 받아 로그인 정보를 검증하고, 성공 시 redirect:/home으로 홈 페이지로 리다이렉션한다.
3. 로그인 실패 시 redirect:/loginForm?error=true으로 다시 로그인 폼으로 리다이렉션하며, error=true 쿼리 파라미터를 추가하여 실패 상태를 알려준다.
4. /home 경로에서는 로그인 성공 후 리다이렉션되어 보여질 홈 페이지를 나타내는 home 뷰를 반환한다.
데이터베이스에서 데이터를 가져올 때 특정 테이블과 매핑되어 데이터를 가져오는 역할을 하는 클래스를 만든 후
Getter Setter는 데이터 클래스에서 데이터를 읽고 쓰는 역할을 한다.
Getter/Setter의 사용 예시
1. 데이터베이스의 특정 테이블에 대응되는 클래스를 만든다
예를 들어, 사용자 정보를 관리하는 User 클래스를 만든다고 가정한다.
public class User {
private Long id;
private String username;
private String email;
// Getter for id
public Long getId() {
return id;
}
// Setter for id
public void setId(Long id) {
this.id = id;
}
// Getter for username
public String getUsername() {
return username;
}
// Setter for username
public void setUsername(String username) {
this.username = username;
}
// Getter for email
public String getEmail() {
return email;
}
// Setter for email
public void setEmail(String email) {
this.email = email;
}
}
user 클래스는 사용자의 id, username, email을 나타내는 변수를 가지고 있다.
각 변수에 getter setter 메소드가 정의되어 있어 이 클래스의 데이터를 읽고 쓸 수 있다.
Setter를 사용하여 데이터 설정 및 가공
Setter 메소드를 사용하여 객체의 데이터를 설정하거나 가공할 수 있다.
Setter을 호출하여 객체의 상태를 변경한다.
예를 들어, User 객체의 setEmail 메소드를 사용하여 이메일을 설정할 수 있다.
public class UserController {
// ... (다른 필드와 메소드는 생략)
public void updateUserEmail(Long userId, String newEmail) {
User user = userService.getUserById(userId);
if (user != null) {
// 예: 이메일 형식 검사
if (isValidEmail(newEmail)) {
user.setEmail(newEmail); // Setter를 통해 이메일 설정
userService.updateUser(user); // 사용자 정보 업데이트
} else {
throw new IllegalArgumentException("유효하지 않은 이메일 형식입니다.");
}
} else {
throw new IllegalArgumentException("해당 ID에 해당하는 사용자가 없습니다.");
}
}
private boolean isValidEmail(String email) {
// 이메일 형식 검사 로직 (정규 표현식 등)
return email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
}
}
1. userService.getUserById(userId) 를 통해 주어진 userId에 해당하는 User객체를 가져온다
2. 가져온 user 객체가 null이 아닐 경우 새로운 이메일 주소인 newEmail을 user.setEmail(newEmail)을 통해 할당한다
3.userService.updateUser(user)을 호출하여 변경된 사용자 정보를 DB에 업데이트 한다