스프링 MVC는 request를 직접 만지지 않아도 된다
서블릿 MVC에서는 요청 데이터를 읽는 방식이 명확했다.
- request.getParameter("title")
- request.setAttribute("todos", list)
즉 request를 직접 만지는 코드가 컨트롤러에 반복된다.
스프링 MVC는 이 부분을 크게 추상화했다.
- 요청 파라미터를 자동으로 모아서 객체(DTO)에 넣어준다
- View로 넘길 데이터도 Model로 넣으면 알아서 request에 옮겨준다
그래서 컨트롤러 코드가 짧아지고 의도가 더 분명해진다.
1) 파라미터 바인딩: DTO를 파라미터로 받으면 자동으로 채워준다
스프링 MVC는 컨트롤러 메서드 파라미터를 보고
요청 파라미터를 자동으로 수집해서 넣어준다.
예를 들어 요청이 이렇게 들어온다고 하자.
- title=study
- finished=true
컨트롤러에서 DTO를 파라미터로 받으면
public String register(TodoDTO dto)
스프링은 내부적으로 대략 이런 작업을 한다.
- TodoDTO 객체를 생성한다
- 요청 파라미터 이름을 보고 필드에 매칭한다
- setter를 호출해서 값을 채운다
- 필요하면 타입 변환도 시도한다(String → int/boolean 등)
즉 “DTO 하나로 요청 데이터 수집이 끝나는 구조”이다.
// ================================
// [파라미터 바인딩] 요청 파라미터를 DTO로 자동 수집
// - 요청 파라미터 이름과 DTO 필드명이 매칭되면 자동으로 setXXX를 호출해 채운다
// ================================
@Data
public class TodoDTO {
private String title;
private boolean finished;
}
2) 바인딩이 되려면 조건이 있다
파라미터 바인딩이 자연스럽게 되려면 조건이 있다.
- 파라미터 이름과 DTO 필드명이 맞아야 한다
- DTO에 기본 생성자가 있어야 한다(스프링이 객체를 만들어야 함)
- setter가 있어야 한다(setXXX로 채우기 때문)
그래서 DTO는 보통 JavaBeans 형태로 만든다.
- private 필드
- getter/setter
- 기본 생성자
Lombok을 쓰면 @Data나 @Getter/@Setter로 쉽게 만든다.
// ================================
// [컨트롤러] DTO 파라미터로 받기 + Model로 View에 전달
// ================================
@Controller
@RequestMapping("/todo")
@RequiredArgsConstructor
public class TodoController {
private final TodoService todoService;
@PostMapping("/register")
public String register(TodoDTO dto) { // ✅ 자동 바인딩
todoService.register(dto);
return "redirect:/todo/list";
}
@GetMapping("/list")
public String list(Model model) { // ✅ Model로 전달
model.addAttribute("todos", todoService.list());
return "todo/list";
}
}
3) @RequestParam: 파라미터 누락/기본값 처리가 필요할 때
스프링 MVC의 바인딩은 편하지만,
파라미터가 누락되면 문제가 생길 수 있다.
예를 들어 page는 없으면 1로 처리하고 싶을 수 있다.
이럴 때 @RequestParam을 쓴다.
- defaultValue: 없을 때 기본값
- required: 필수 여부
즉 @RequestParam은 “파라미터 수집의 정책”을 명시하는 도구이다.
// ================================
// [RequestParam] 파라미터가 없을 때 기본값 지정/필수 여부 제어
// ================================
@GetMapping("/search")
public String search(
@RequestParam(defaultValue = "1") int page,
@RequestParam(required = false) String keyword
) {
// page는 없으면 1
// keyword는 없으면 null
return "todo/search";
}
4) Model: View로 넘길 데이터를 담는 상자
서블릿 MVC에서는 View로 데이터를 넘길 때 request에 담았다.
- request.setAttribute("todos", list)
스프링 MVC에서는 Model을 쓴다.
- model.addAttribute("todos", list)
중요한 포인트는 이것이다.
EL이 Model 객체 자체를 읽는 게 아니다
Model에 담긴 attribute가 request 영역으로 옮겨지고, JSP는 그 값을 읽는다
즉 스프링 MVC는 내부적으로
- Model에 담긴 값을 request attribute로 옮겨준다
그래서 JSP에서는
- ${todos}
로 바로 읽힌다.
5) 왜 컨트롤러에서 request/response를 덜 만지는가
스프링 MVC는 DispatcherServlet이 요청/응답의 많은 처리를 표준화하고,
컨트롤러는 “비즈니스 의도”만 표현하게 만드는 게 목표이다.
그래서 컨트롤러는 보통 이런 코드가 된다.
- DTO로 입력 받기
- Service 호출
- Model에 넣기
- view 이름 또는 redirect 반환하기
이 구조가 유지보수성과 생산성을 크게 높인다.
정리
- 스프링 MVC는 요청 파라미터를 DTO로 자동 바인딩해준다
- 바인딩은 이름 매칭 + 기본 생성자 + setter가 필요하다
- @RequestParam으로 기본값/필수 여부를 명시할 수 있다
- Model에 담으면 스프링이 request attribute로 옮겨서 JSP EL이 읽을 수 있게 한다
- 그래서 컨트롤러가 request/response를 직접 만지는 코드가 줄어든다
'Web > Web Basics' 카테고리의 다른 글
| [스프링과 스프링 MVC] 4. LocalDate 바인딩이 왜 자주 깨지는가 (0) | 2026.03.31 |
|---|---|
| [스프링과 스프링 MVC] 2. 스프링 MVC는 “프론트 컨트롤러”로 움직인다 (0) | 2026.03.30 |
| [스프링과 스프링 MVC] 1. DI와 빈(Bean) (0) | 2026.03.30 |
| [상태 유지와 공통 처리] 5. MyBatis 설정 흐름 (0) | 2026.03.30 |
| [상태 유지와 공통 처리] 4. MyBatis는 무엇을 해결하는가 (0) | 2026.03.30 |