클라이언트에서 서버로 통신하는 메시지를 요청(request) 메시지라고 하며, 서버에서 클라이언트로 통신하는 메시지를 응답(response) 메시지라고 한다.
웹에서 화면전환(새로고침) 없이 이루어지는 동작들은 대부분 비동기 통신으로 이루어진다.
비동기통신을 하기위해서는 클라이언트에서 서버로 요청 메세지를 보낼 때, 본문에 데이터를 담아서 보내야 하고, 서버에서 클라이언트로 응답을 보낼때에도 본문에 데이터를 담아서 보내야 한다.
이 본문이 바로 body 이다.
즉, 요청본문 requestBody, 응답본문 responseBody 을 담아서 보내야 한다.
이때 본문에 담기는 데이터 형식은 여러가지 형태가 있겠지만 가장 대표적으로 사용되는 것이 JSON 이다.
즉, 비동기식 클라-서버 통신을 위해 JSON 형식의 데이터를 주고받는 것이다.
스프링 MVC에서도 클라이언트에서 전송한 xml데이터나 json 등등 데이터를 컨트롤러에서 DOM객체나 자바객체로 변환해서 송수신할 수 있다.
@RequestBody 어노테이션과 @ResponseBody 어노테이션이 각각 HTTP요청 바디를 자바객체로 변환하고 자바객체를 다시 HTTP 응답 바디로 변환해준다.
요청 본문(request body)에 담긴 값을 자바객체로 변환.
@RequestBody를 통해서 자바객체로 conversion을 하는데, 이때 HttpMessageConverter를 사용한다.
@ResponseBody 가 붙은 파라미터에는 HTTP 요청의 분문 body 부분이 그대로 전달된다.
RequestMappingHandlerAdpter 에는 HttpMessageConverter 타입의 메세지 변환기가 여러개 등록되어 있다.
@RequestBody
HTTP 요청으로 넘어오는 body의 내용을 HttpMessageConverter를 통해 Java Object로 역직렬화한다.
이 어노테이션이 붙은 파라미터에는 http요청의 본문(body)이 그대로 전달된다.
일반적인 GET/POST의 요청 파라미터라면 @RequestBody를 사용할 일이 없을 것이다.
반면에 xml이나 json기반의 메시지를 사용하는 요청의 경우에 이 방법이 매우 유용하다.
HTTP 요청의 바디내용을 통째로 자바객체로 변환해서 매핑된 메소드 파라미터로 전달해준다.
multipart 요청이 아닌, 즉 어떤 바이너리 파일을 포함하고 있지 않은 데이터를 받는 역할을 한다.
HttpMessageConverter란?
간단하게 HTTP 요청과 응답에 대해서 "전략 패턴"을 사용해서 converting 해주는 역할.
전략 패턴은 하나의 메서드가 여러 가지의 대응 방법을 미리 준비해두고 필요한 상황마다 대응 방법을 달리 하는 방법을 말한다.
@RequestMapping(value = "/ajaxTest.do")
public String ajaxTest(@RequestBody UserVO getUserVO) throws Exception {
System.out.println(getUserVO.getId( ));
return "test/login.tiles";
}
RequestBody는 HTTP 요청으로 같이 넘어오는 Header의 Content-type을 보고 어떤 Converter를 사용할지 정하기에 Content-type을 반드시 명시해야 한다.
Content-type의 종류 (중 일부)
application/json: {key : value}의 형태로 전송
application/x-www-form-urlencoded: key=value&key=value 형태로 전송(HTML form의 default 값)
multipart/form-data: 파일 업로드시 사용되며 '파일을 비롯한 여러 데이터가 있음'이라는 뜻을 가짐. (@RequestBody로 받을 수 없음 !!)
사용 방법: REST API를 통해 단순 데이터를 주고 받는 일반적인 경우에 사용할 수 있다.
Controller에서 받을때 어노테이션 생략시 @ModelAttribute가 default이므로 @RequestBody를 사용하고자 하는 경우에는 반드시 기술해야 한다.
@ResponseBody
자바객체를 HTTP요청의 바디내용으로 매핑하여 클라이언트로 전송한다.
@ResponseBody 가 붙은 파라미터가 있으면 HTTP요청의 미디어타입과 파라미터의 타입을 먼저 확인한다.
* dispatcher-servlet.xml 의 <annotation-drvien> 태그 내에 선언하는 <message-converter> 에서 확인.
메세지 변환기 중에서 해당 미디어타입과 파라미터 타입을 처리할 수 있다면, HTTP요청의 본문 부분을 통째로 변환해서 지정된 메소드 파라미터로 전달해준다.
@ResponseBody
@RequestMapping(value = "/ajaxTest.do")
public UserVO ajaxTest() throws Exception {
UserVO userVO = new UserVO(); userVO.setId("테스트");
return userVO;
}
즉, @Responsebody 어노테이션을 사용하면 http요청 body를 자바 객체로 전달받을 수 있다.
* @RestController
@Controller와는 다르게 @RestController는 리턴값에 자동으로 @ResponseBody가 붙게되어 별도 어노테이션을 명시해주지 않아도 HTTP 응답데이터(body)에 자바 객체가 매핑되어 전달 된다.
@Controller인 경우에 바디를 자바객체로 받기 위해서는 @ResponseBody 어노테이션을 반드시 명시해주어야한다.
@RequestBody / @ResponseBody 정리.
클라이언트에서 서버로 필요한 데이터를 요청하기 위해 JSON 데이터를 요청 본문에 담아서 서버로 보내면, 서버에서는 @RequestBody 어노테이션을 사용하여 HTTP 요청 본문에 담긴 값들을 자바객체로 변환시켜, 객체에 저장한다.
서버에서 클라이언트로 응답 데이터를 전송하기 위해 @ResponseBody 어노테이션을 사용하여 자바 객체를 HTTP 응답 본문의 객체로 변환하여 클라이언트로 전송한다.
@RequestPart
Content-type이 'multipart/form-data'와 관련된 경우에 사용한다.
MultipartFile이 포함되는 경우에 MutliPartResolver가 동작하여 (여기서도 전략 패턴이 사용된다) 역직렬화를 하게 됨.
MultipartFile이 포함되지 않는 경우는 @RequestBody와 같이 HttpMessageConverter가 동작하게 된다.
사용 방법: @RequestBody가 필요하지만 Binary Stream이 포함되는 경우(MultipartFile과 같은)에 사용할 수 있다.
@RequestParam
하나의 파라미터만을 받을때 사용된다. 기본적으로 파라미터가 필수적으로 들어오게 설정되어 있기에 파라미터가 들어오지 않는 경우 BadRequest가 발생하므로 파라미터가 들어올 수도, 들어오지 않을 수도 있다면 required = false를 주어야 한다.
@RequestParam 또한 @RequestPart와 같이 MultipartFile을 받을 때 사용할 수 있다.
@RequestPart와의 다른 점은 @RequestParam의 경우 파라미터가 String이나 MultipartFile이 아닌 경우 Converter나 PropertyEditor에 의해 처리 되지만 @RequestPart는 HttpMessageConverter를 이용하여 Content-type을 참고하여 처리한다는 점이다.
이때 하나의 요청 파라미터에만 대응한다고 해서 1개의 MultipartFile만 받을 수 있는게 아닌 List<MultipartFile>의 형태로도 받을 수 있으며
모든 파라미터를 Map<String, String>처럼 한 번에 받을 수 있으나 많은 데이터를 하나의 파라미터로 받는 것은 유지 보수성의 측면에서 좋지 못 하므로 많은 데이터를 주고받는 경우에는 @RequestBody와 DTO를 이용하는 편이 좋다.
사용 방법: 간단한 name-value 형태의 데이터를 주고받을 때 사용할 수 있으며 파라미터가 복잡해지는 경우 @RequestBody나 @RequestPart를 이용하여 DTO를 사용하는 것이 좋다.
@ModelAttribute
상술했듯이 Spring Controller에서 값을 받을때 default가 @ModelAttribute이며 다음과 같은 상황에 사용할 수 있다.
- Content-type이 multipart/form-data의 형태를 받을때
- HTTP 파라미터를 받는 경우
즉 HTTP body로 오든 파라미터로 오든 다 받을 수 있고 body와 파라미터가 같이 오는 경우에도 값이 바인딩된다.
이런 형태가 가능한 이유는 @ModelAttribute는 필드 내부와 1:1로 값이 Setter나 Constructor를 통해 매핑되기 때문이다.
@RequestPart와 다른 점은 HttpMessageConverter에 의해 값이 바인딩되는 것이 아닌 적절한 Setter 혹은 Constructor를 통해 값이 주입된다는 점이다.
즉 해당 DTO의 필드에 접근할 수 있는 적절한 수단이 존재하지 않으면 값이 바인딩 될 수 없다.
HttpMessageConverter가 동작하는 @RequestPart나 @RequestBody의 경우 필드를 찾을때 ObjectMapper를 이용하고 이 ObjectMapper는 NoArgsConstructor와 Getter나 Setter 등을 통해 private field에 접근 할 수 있게 구현되어 있다.
이때 접근할 수 있는 이유는 Jackson 라이브러리는 Reflection을 통해서 private field에 값을 할당할 수 있기 때문이다.
ObjectMapper를 Override하면 어떤 접근자도 필요없게 만들 수도 있다!
정리
@RequestBody
application/json을 주고받을때 주로 사용함. multipart/form-data이 포함되는 경우는 사용 불가.
@RequestPart
@RequestBody + multipart/form-data인 경우에 사용.
RequestBody와 RequestPart는 HttpMessageConverter에 의해 동작하므로 Setter 없이 Object 생성됨.
@RequestParam
1개의 HTTP 파라미터를 받을 때 사용.
multipart/form-data을 받아야 되는 경우에 사용 가능.
기본 설정으로 필요 여부가 필수로 되어있음.
@ModelAttribute
@RequestPart와 유사하지만 동작 원리는 완전히 다르다.
값에 직접적으로 접근할 수 있는 수단이 필요.
출처 : RequestBody vs RequestPart vs RequestParam vs ModelAttribute (tistory.com)
[Spring] @RequestBody / @ResponseBody 어노테이션 이란? (tistory.com)
'Studying > Java' 카테고리의 다른 글
StringBuilder와 StringBuffer (0) | 2023.08.10 |
---|---|
[@Annotation] @RequestParam (0) | 2023.08.10 |
RequestDispatcher (0) | 2023.08.10 |
[IT용어] REST API (0) | 2023.08.08 |
[IT용어] JWT(Json Web Token) (0) | 2023.08.08 |