하나의 Servlet이 혼자 모든 것을 처리하던 문제를 해결하기 위해
애플리케이션의 코드를 세 가지 역할로 명확하게 나누는 설계 방식
데이터와 비즈니스 로직을 담당 (예: 영화 데이터, 추천 로직)화면(UI)을 담당 (예: HTML 페이지)중간 다리 역할사용자의 요청(URL)을 받아서 무슨 작업을 할지 결정
필요한 비즈니스 로직 호출 후 결과를 Model에 담고 View로 넘김
Controller가 처리한 결과 데이터를 저장하는 공간
View에 전달할 데이터 (Key-Value 형태)
Model에 담긴 데이터를 이용해서 HTML 화면을 만들어 사용자에게 보여줌
들어온 요청 URL을 분석하여 해당 요청을 처리할 적절한 Handler(Controller)를 찾아주는 인터페이스
동작원리 :
@RequestMapping("/users")
public class UserController {
@GetMapping
public String getUserList() { ... }
}

① 요청
클라이언트가 웹 애플리케이션에 요청(Request)을 보내고, 가장 먼저 DispatcherServlet에 도달
② 핸들러 조회
DispatcherServlet은 HandlerMapping에게 요청을 처리할 Handler(=Controller)를 찾아달라고 요청
③ 핸들러 실행
DispatcherServlet은 HandlerMapping으로부터 받은 정보를 이용해 해당 Controller에게 요청 처리 위임
④ ModelAndView 반환
Controller는 비즈니스 로직을 수행한 후, 결과 데이터(Model)와 뷰의 논리적 이름(View Name)을 담은 ModelAndView 객체를 DispatcherServlet에 반환
⑤ 뷰 해석
DispatcherServlet은 ModelAndView에서 뷰 이름을 추출하여 ViewResolver에게 전달하고, 해당하는 실제 View 객체를 찾아달라고 요청
⑥ 뷰 렌더링
DispatcherServlet은 ViewResolver로부터 받은 View 객체에게 모델 데이터를 전달하여 뷰를 렌더링하도록 요청
⑦ 응답
렌더링된 View의 결과물이 DispatcherServlet을 통해 클라이언트에게 최종적으로 응답(Response)

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@RequestMapping(value = "/users", method = RequestMethod.GET)
@ResponseBody
public User getUser() {
// ...
}
}
-----------------------------------------------------------------
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // @Controller와 @ResponseBody가 합쳐졌다!
public class UserRestController {
@RequestMapping(value = "/users", method = RequestMethod.GET)
public User getUser() {
// ...
}
}
특정 URL로 Request를 보내면 들어온 요청을 Controller 내부의 특정 Method와 Mapping 하기 위해 사용
사용법 1. 해당 컨트롤러의 전체 경로 prefix 설정
@RestController
@RequestMapping("/hello")
public class HelloController {
// ...
}
사용법 2. 특정 API 전체 경로 허용
해당 방법으론 거의 ❌ -> HTTP 메서드별 전용 어노테이션으로 대체
@RestController
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public void getHello() {
// ...
}
@RequestMapping(value = "/hello", method = RequestMethod.POST)
public void postHello() {
// ...
}
@RequestMapping(value = "/hello", method = RequestMethod.PUT)
public void putHello() {
// ...
}
@RequestMapping(value = "/hello", method = RequestMethod.PATCH)
public void patchHello() {
// ...
}
@RequestMapping(value = "/hello", method = RequestMethod.DELETE)
public void deleteHello() {
// ...
}
}
주로 사용하는 HTTP 메서드 : GET, POST, PUT, PATCH, DELETE
GET : @GetMapping 사용
@RestController
public class HelloController {
@GetMapping("/hello")
public void getHello() {
// ...
}
}
POST : @PostMapping 사용
@RestController
public class HelloController {
@PostMapping("/hello")
public void postHello() {
// ...
}
}
PUT : @PutMapping 사용
@RestController
public class HelloController {
@PutMapping("/hello")
public void putHello() {
// ...
}
}
PATCH : @PatchMapping 사용
@RestController
public class HelloController {
@PatchMapping("/hello")
public void patchHello() {
// ...
}
}
DELETE : @DeleteMapping 사용
@RestController
public class HelloController {
@DeleteMapping("/hello")
public void deleteHello() {
// ...
}
}
? 뒤에 오는 파라미터들을 처리할 때 사용 @RestController
public class UserController {
// /users?name=john&age=30 요청이 들어온 상황이라면
@GetMapping("/users")
public String getUser(
@RequestParam String name, // name 값은 john
@RequestParam int age // age 값은 30
) {
// ...
}
}
@RestController
public class UserController {
// /users?page=1&size=10 요청이 들어온 상황이라면
@GetMapping("/users")
public List<String> getUsers(
@RequestParam(defaultValue = "0") int page, // 1
@RequestParam(defaultValue = "10") int size, // 10
@RequestParam(required = false) String sort // null
) {
// ...
}
}
// @RequestParam이 너무 많은 경우
@GetMapping("/api/search")
public List<String> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) String email,
@RequestParam(required = false) Integer minAge,
@RequestParam(required = false) Integer maxAge,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size
) {
// 파라미터가 많아서 복잡함!
}
// @ModelAttribute 사용 (추천)
@GetMapping("/api/search")
public List<String> searchUsers(@ModelAttribute UserSearchDto dto) {
// 하나의 @ModelAttribute로 데이터를 받을 수 있다.
}
// 바인딩용 DTO 클래스
public class UserSearchDto {
private String name;
private String email;
private Integer minAge;
private Integer maxAge;
private Integer page = 0; // 기본값 설정 가능
private Integer size = 10; // 기본값 설정 가능
// ...
}
/users/123 형태의 요청에서 123 값 받을 수 있음 @RestController
public class UserController {
// GET /users/123
@GetMapping("/users/{userId}")
public String getUser(@PathVariable Long userId) { // userId는 123
// ...
}
}
@RestController
public class UserController {
// POST /users
// Body: {"name": "John", "email": "john@example.com", "age": 30}
@PostMapping("/api/users")
public String createUser(@RequestBody CreateUserRequest request) {
// ...
}
}
@Getter
public class CreateUserRequest {
// 위의 요청의 경우 아래와 같이 값이 매핑됩니다.
private String name; // John
private String email; // john@example.com
private int age; // 30
}