
어제 살펴본 처리 흐름을 따라 코드를 작성해보겠다.
파란색 부분은 스프링에서 자동으로 처리해주는 곳이고, 보라색 부분은 개발자가 직접 구현해야 하는 부분이다.
View 부분은 어느 정도 개발자가 구현해줘야 하는 부분이다.
1) 클라이언트로부터 요청이 들어온다.
2) 들어온 요청은 DispatcherServlet로 들어온다.
모든 요청은 DispatcherServlet로 들어온다.
3) DispatcherServlet이 HandlerMapping에게 “이 URL을 처리할 컨트롤러(핸들러)가 누구냐?”를 물어본다.
4) HandlerMapping이 찾은 컨트롤러 정보를 HandlerAdapter에게 전달한다.
5) HandlerAdapter가 실제 Controller 메서드를 호출한다.
6) Controller가 Service를 호출한다 → Service가 Repository 호출 → Repository가 DB 조회
7) Controller는 Model에 데이터를 담고, View 이름(view name)을 반환한다.
8) DispatcherServlet이 ViewResolver에게 view name을 전달한다.
9) ViewResolver가 실제 View(템플릿) 객체를 찾아준다.
10) View가 Model을 이용해 HTML을 렌더링하고 Response로 반환한다.
@Controller
public class UserController {
@GetMapping("/users")
public String listUsers(@RequestParam String keyword, Model model) {
// Service 호출
List<UserDTO> users = userService.searchUsers(keyword);
// Model에 담기
model.addAttribute("users", users);
model.addAttribute("keyword", keyword);
// View 이름 반환
return "users/list";
}
}
| 단계 | 컴포넌트 | 제공자 | 역할 |
|---|---|---|---|
| ①② | DispatcherServlet | Spring | 모든 요청의 진입점 |
| ② | HandlerMapping | Spring | URL → Controller 매핑 찾기 |
| ③④ | HandlerAdapter | Spring | Controller 메서드 실행 |
| ⑤ | Controller | 개발자 | 요청 처리, Service 호출 |
| ⑤ | Service | 개발자 | 비즈니스 로직 수행 |
| ⑤ | Repository | 개발자 | DB 접근 |
| ⑥⑦ | ViewResolver | Spring | View 이름 → View 파일 매핑 |
| ⑧ | View | 개발자 | HTML 렌더링 |
View 이름(String)을 반환 → ViewResolver가 처리
@Controller
public class UserController {
@GetMapping("/users")
public String listUsers(Model model) {
return "users/list";
}
}
객체를 반환 → JSON으로 자동 변환
(@Controller + @ResponseBody)
@RestController
public class UserRestController {
@GetMapping("/api/users")
public List<UserDTO> getUsers() {
return users;
}
}
// URL: /users?keyword=kim&page=1&size=10
@GetMapping("/users")
public String search(
@RequestParam String keyword,
@RequestParam(required = false) Integer page,
@RequestParam(defaultValue = "10") int size
) {
return "users/list";
}
여러 값:
// URL: /users?ids=1&ids=2&ids=3
@GetMapping("/users")
public String getMultiple(@RequestParam List<Long> ids) {
return "users/list";
}
// URL: /users/123
@GetMapping("/users/{id}")
public String detail(@PathVariable Long id) {
return "users/detail";
}
@PostMapping("/users")
public String create(@ModelAttribute UserDTO userDTO) {
userService.create(userDTO);
return "redirect:/users";
}
유효성:
@PostMapping("/users")
public String create(
@Valid @ModelAttribute UserDTO userDTO,
BindingResult result
) {
if (result.hasErrors()) return "users/form";
userService.create(userDTO);
return "redirect:/users";
}
오늘 내용이 너무 방대하여 이해하기가 조금 힘들었다.
MVC 흐름을 먼저 확실히 잡고, 어노테이션은 “어디에 붙이고 무엇을 반환하느냐(View vs JSON)” 기준으로 외우면 덜 헷갈린다.