2025-10-16 Spring MVC패턴

Ckd gus·2026년 2월 2일

전체 흐름

어제 살펴본 처리 흐름을 따라 코드를 작성해보겠다.

파란색 부분은 스프링에서 자동으로 처리해주는 곳이고, 보라색 부분은 개발자가 직접 구현해야 하는 부분이다.
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 예시 (코드 블럭 중첩 없이 표현)

@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";
    }
}

핵심 요약

단계컴포넌트제공자역할
①②DispatcherServletSpring모든 요청의 진입점
HandlerMappingSpringURL → Controller 매핑 찾기
③④HandlerAdapterSpringController 메서드 실행
Controller개발자요청 처리, Service 호출
Service개발자비즈니스 로직 수행
Repository개발자DB 접근
⑥⑦ViewResolverSpringView 이름 → View 파일 매핑
View개발자HTML 렌더링

중요한 어노테이션

@Controller

View 이름(String)을 반환 → ViewResolver가 처리

@Controller
public class UserController {
    @GetMapping("/users")
    public String listUsers(Model model) {
        return "users/list";
    }
}

@RestController

객체를 반환 → JSON으로 자동 변환
(@Controller + @ResponseBody)

@RestController
public class UserRestController {
    @GetMapping("/api/users")
    public List<UserDTO> getUsers() {
        return users;
    }
}

@RequestMapping / HTTP 메서드 매핑

  • @GetMapping : 조회
  • @PostMapping : 생성
  • @PutMapping : 전체 수정
  • @PatchMapping : 부분 수정
  • @DeleteMapping : 삭제

@RequestParam (쿼리 파라미터)

// 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";
}

@PathVariable (경로 변수)

// URL: /users/123
@GetMapping("/users/{id}")
public String detail(@PathVariable Long id) {
    return "users/detail";
}

@ModelAttribute (폼 데이터)

@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)” 기준으로 외우면 덜 헷갈린다.

profile
백엔드 공부중입니다.

0개의 댓글