RestController의 처리 과정

① 클라이언트가 HTTP 요청 전송
- 브라우저, 모바일 앱, Postman 등이 서버에 HTTP 요청을 보냄
예: GET /users/1, POST /login
② DispatcherServlet이 요청 수신
- DispatcherServlet은 Spring MVC의 프론트 컨트롤러
- 모든 HTTP 요청을 이 Servlet이 가장 먼저 받음
- 이후 적절한 컨트롤러로 요청을 위임함 (HandlerMapping을 통해)
③ HandlerMapping이 실행되어 Handler(컨트롤러) 결정
- 요청 URL과 메서드를 보고 어떤 컨트롤러 메서드(@GetMapping 등)를 실행할지 결정
ex: /users/1 → UserController.getUserById()
④ HandlerAdapter가 실제 컨트롤러 호출을 준비
- 단순히 Handler(=메서드)를 결정하는 것만으로는 실행이 불가능
- Spring은 다양한 타입의 핸들러(예: @RestController, @Controller, @RequestMapping)를 실행할 수 있도록
HandlerAdapter를 통해 호출 방식 및 파라미터 바인딩을 처리
⑤ HandlerAdapter가 실제 컨트롤러(@RestController) 메서드 실행
- 개발자가 구현한 @RestController 메서드가 호출됨
- 이 과정에서 @RequestBody, @PathVariable 등이 적용되어 필요한 값이 주입됨
- 파라미터 바인딩을 하면서, @RequestBody가 있다면 HttpMessageConverter가 동작해서 요청 본문을 자바 객체로 변환
- Service, Repository를 통해 비즈니스 로직 + DB 처리 수행 후,
⑥ 컨트롤러에서 ResponseEntity 또는 객체 반환
- ResponseEntity 또는 일반 객체를 반환함
예: return new ResponseEntity<>(user, HttpStatus.OK);
또는 그냥 return user;
⑦ HttpMessageConverter가 자바 객체를 JSON 등으로 변환
- 이 시점이 바로 HTTP 메시지 컨버터가 동작하는 순간!
- 컨트롤러가 반환한 객체를 HTTP 응답으로 보내기 위해, HttpMessageConverter가 작동하여
자바 객체 → JSON (또는 XML 등) 문자열로 변환
⑧ DispatcherServlet이 HTTP 응답을 클라이언트에게 반환
- 최종적으로 JSON 데이터와 함께 200 OK, 404 Not Found 등의 상태 코드를 포함해
클라이언트에게 응답이 전송됨
HTTPMessageConverter
"Spring MVC에서 HTTP 요청/응답의 바디(body)를 자바 객체 ↔ JSON, XML, 문자열 등으로 변환해주는 인터페이스"
- 요청(@RequestBody) → 자바 객체
- 자바 객체 → 응답(@ResponseBody, @RestController)
요청
- 요청에서는 @RequestBody와 @RequestPart를 사용할 때만 HttpMessageConverter가 작동함
- HTTP 메시지 바디를 변환하는 컴포넌트기 때문에, 요청의 Body를 다룰 때만 동작
- 쿼리 파라미터나, URL같은 바디가 없는 데이터를 처리할 땐 동작 X
- 즉, 요청 데이터가 HTTP 메시지 바디에 담겨있다면, 이를 자바 객체로 매핑하기 위해 @RequestBody가 꼭 필요함
- 이 때, Spring은 요청의 Content-Type 헤더를 보고 등록된 메시지 컨버터들 중, 해당 타입을 처리할 수 있는 컨버터를 자동 선택하여 자바 객체로 매핑
- text/plain인 경우, StringHttpMessageConverter 사용 (평문을 자바의 String 객체로 변환)
- application/xml인 경우, MappingJackson2XmlHttpMessageConverter 사용
- application/json인 경우, MappingJackson2HttpMessageConverter 사용
- form-data의 경우에도 HTTP 메시지 바디에 포함되지만, Spring은 이를 쿼리스트링처럼 key-value 구조의 요청 파라미터처럼 인식하기 때문에,
별도의 HttpMessageConverter 없이, 내부 바인딩 처리기(WebDataBinder 등)를 통해 자바 객체로 자동 매핑한다.
(@RequestParam, @ModelAttribute 사용)
- 하지만, HTTP 메시지 바디에 있기 떄문에 @RequestBody로 기술적으로는 받을 수 있긴하다.. (Converter도 있지만, 거의 안씀)
요청 처리 Annotation
"@RequestBody는 HTTP 요청 바디(body)의 데이터를 자바 객체로 변환해 달라는 Spring에게의 명확한 신호다."
- 즉, 요청 데이터가 쿼리 파라미터가 아니라 HTTP 바디에 담겨 있는 경우, Spring은 @RequestBody가 존재할 때만 해당 데이터를 처리하며,
이때 HttpMessageConverter를 사용해 요청 본문을 자바 객체로 변환한다.
- 단, multipart/form-data나 application/x-www-form-urlencoded는 예외적으로 처리되며, 이러한 HTTP 메시지 바디 요청은 key-value 구조의 요청 파라미터로 인식되어, Spring 내부 바인딩 처리기를 통해 다음과 같은 방식으로 매핑된다:
- @RequestParam → 단일 파라미터를 하나씩 바인딩, form 데이터나 쿼리 스트링 처리 ex) String username
- @ModelAttribute → 여러 파라미터를 묶은 객체, 쿼리스트링(비바디)이나 form 데이터(key-value)를 자바 복합 필드 객체로 자동 바인딩 ex) User user
- 위에서 언급했듯, form-data는 HTTP 메시지 바디에 포함되긴 하지만, 예외적으로 요청 파라미터 key-value로 인식하여 HTTPMessageConverter없이
Spring 내부 바인딩 처리기를 통해 객체로 매핑
- @RequestPart → multipart/form-data 안에 JSON 같은 구조화된 데이터가 포함된 경우 JSON과 파일 데이터를 나눠서 받음
- 이 경우 JSON이 포함되어 있기 떄문에 HttpMessageConverter 작동
- 파일 데이터의 경우에는 MultipartResolver가 요청을 파싱하여 자바의 MultipartFile 객체로 자동 바인딩
@RequestPart("request") RequestDTO requestDTO,
@RequestPart(value = "attachments", required = false) List<MultipartFile> multipartFileList) {
Annotation 정리
- multipart/form-data나 application/x-www-form-urlencoded 같은 form 데이터는:
- @RequestParam → 파라미터 당 단일 값으로 받고싶을 때 (텍스트, 파일 등) / 한 요청에 여러 파라미터가 들어오면 여러 개 쓰면 됨
- @RequestParam String username, @RequestParam String password
- @ModelAttribute → 여러 파라미터를 자바 객체로 묶어받고 싶을 때
- @ModelAttribute User user (useranme과 password가 포함된 User 객체)
- @RequestPart → multipart 안의 JSON + 파일을 각각 처리할 때
- JSON, XML, text/plain 등 구조화된 HTTP body 데이터는:
- @RequestBody로 받아서 Content-Type 헤더에 따라 HttpMessageConverter를 통해 자바 객체로 변환
응답
- 응답에서는 @ResponseBody나 @RestController가 붙어있어야만 HttpMessageConverter가 작동
- @ResponseBody가 붙어있다면, Spring Boot는 기본적으로 응답에서 JSON 컨버터 Jackson을 사용 (MappingJackson2HttpMessageConverter)
- 반환 타입 + 클라이언트의 Accept 헤더를 참고하여, 컨버터를 결정 (XML, 문자 등)
- 별도로 명시해주지 않으면 기본적으로 객체를 JSON으로 변환
ModelAttribute vs RequestBody
@ModelAttribute
- 쿼리 스트링 (?name=abc&age=30) 이나
폼 데이터 (application/x-www-form-urlencoded) 로 넘어오는 값을
객체에 자동으로 바인딩할 때 사용
- ex) /users?name=Tom&age=20 → User(name=Tom, age=20)
@RequestBody
- 요청의 body 에 JSON 같은 데이터가 담겨 있을 때 사용
- 예를 들어, 클라이언트가 { "name": "Tom", "age": 20 } 이런 JSON을 body에 담아 보내는 경우 그걸 객체로 매핑!