- 쿼리 파라미터로 날아오는 데이터를 받을 수 있게 해줌
- 파라미터 이름으로 바인딩 되는 형식
- EX) @RequestParam("username") String memberName에서 username으로 넘어오는 쿼리 파라미터를 String memberName에 바인딩 됨
- 만약 괄호 안의 값이 없다면 변수명으로 바인딩 됨
- EX) @RequestParam String memberName이라면 memberName으로 넘어오는 쿼리 파라미터를 바인딩.
- Primitive타입, Map과 같은 컬렉션 등에 사용 가능
- @RequestParam과 동일하게 쿼리 파라미터로 날아오는 데이터를 받을 수 있음
- 차이점은 필요한 객체를 생성하고 그 객체에 값을 넣어주는 것까지 가능함
- 실행 순서 => 객체 생성 => 넘어온 쿼리 파라미터 이름으로 객체에 프로퍼티를 찾음 => 해당 객체의 프로퍼티의 setter를 호출해 파라미터 값을 바인딩함
- ex) 파라미터 이름이 username이면 setUsername()메서드를 찾아 호출해 값을 바인딩
- @RequestParam으로 쿼리 파라미터를 줄줄이 받는 것 보다, 적절한 객체를 생성해서 @ModelAttribute로 받으면 훨씬 깔끔한 코드를 작성할 수 있다.
- 위의 두 가지 어노테이션과 가장 큰 차이점은 어떤 대상을 타겟으로 하냐에 있다.
- 위의 어노테이션들은 쿼리 파라미터를 대상으로 하고, @RequestBody의 경우 HTTP 메세지 바디에서 오는 JSON 형태의 데이터를 Java 객체에 매핑할 때 사용함.
- 넘어오는 JSON형태의 데이터에 맞게 객체를 만들고 어노테이션을 붙여주면 객체에 값들이 맵핑되어 사용할 수 있음
- Spring에서 Controller의 반환 타입이 String일때 기본적으로 View를 내려주는데, @ResponseBody 어노테이션을 사용하면 HTTP 메세지의 바디에 return 값을 넣어준다.
- 객체가 반환타입일 때 @ResponseBody가 있으면 객체를 Http 메세지 바디에 넣어 알맞게 JSON형식으로 변환됨.
- HttpEntity: HTTP header, body 정보를 편리하게 조회할 수 있으며, 응답에서도 메세지 바디 정보를 직접 반환하고 헤더 정보 포함 가능함(view 조회x)
- RequestEntity: HttpEntity를 상속받고 HttpMethod ,url 정보가 추가됨
- ResponseEntity: HttpEntity를 상속받고 HTTP 상태 코드 설정 가능
- @RequestBody를 사용하여 메세지 바디 내용(JSON)을 객체에 바로 맵핑하듯이, 위의 1,2들도 <>안에 객체 타입을 명시해주면 바로 객체에 바인딩됨.
- @ResponseBody를 사용하여 객체를 바로 Http 메세지 바디에 넣어주어 JSON으로 변환해주듯이 1,3도 가능함.
@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) {
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new HttpEntity<>("ok");
}
@ResponseBody
@PostMapping("/request-body-json-v5")
public HelloData requestBodyJsonV5(@RequestBody HelloData data) {
log.info("username={}, age={}", data.getUsername(), data.getAge());
return data;
}
@ResponseBody
@PostMapping("/request-body-json-v4")
public String requestBodyJsonV4(HttpEntity<HelloData> httpEntity) {
HelloData data = httpEntity.getBody();
log.info("username={}, age={}", data.getUsername(), data.getAge());
return "ok";
}
@ResponseBody
@PostMapping("/request-body-json-v4")
public String requestBodyJsonV4(HttpEntity<HelloData> httpEntity) {
HelloData data = httpEntity.getBody();
log.info("username={}, age={}", data.getUsername(), data.getAge());
return "ok";
}
@GetMapping("/response-body-string-v2")
public ResponseEntity<String> responseBodyV2() {
return new ResponseEntity<>("ok", HttpStatus.OK);
}
@GetMapping("/response-body-json-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return new ResponseEntity<>(helloData, HttpStatus.OK);
}
- 모든 것은 Spring이 Http Message Converter를 사용하여 가능하다.
- HTTP 메시지 컨버터는 HTTP 요청, HTTP 응답 둘 다 사용된다.
canRead() , canWrite() : 메시지 컨버터가 해당 클래스, 미디어타입을 지원하는지 체크
read() , write() : 메시지 컨버터를 통해서 메시지를 읽고 쓰는 기능- ByteArrayHttpMessageConverter : byte[] 데이터를 처리한다.
클래스 타입: byte[] , 미디어타입: / ,
요청 예) @RequestBody byte[] data
응답 예) @ResponseBody return byte[] 쓰기 미디어타입 application/octet-stream
StringHttpMessageConverter : String 문자로 데이터를 처리한다.- 클래스 타입: String , 미디어타입: /
요청 예) @RequestBody String data
응답 예) @ResponseBody return "ok" 쓰기 미디어타입 text/plain- MappingJackson2HttpMessageConverter : application/json
클래스 타입: 객체 또는 HashMap , 미디어타입 application/json 관련
요청 예) @RequestBody HelloData data
응답 예) @ResponseBody return helloData 쓰기 미디어타입 application/json 관련
실제 요청이 왔을때
- HTTP 요청 데이터 읽기
HTTP 요청이 오고, 컨트롤러에서 @RequestBody , HttpEntity 파라미터를 사용한다.
메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead() 를 호출한다.
대상 클래스 타입을 지원하는가?
예) @RequestBody 의 대상 클래스 ( byte[] , String , HelloData )
HTTP 요청의 Content-Type 미디어 타입을 지원하는가?
예) text/plain , application/json , /
canRead() 조건을 만족하면 read() 를 호출해서 객체 생성하고, 반환한다.- HTTP 응답 데이터 생성
컨트롤러에서 @ResponseBody , HttpEntity 로 값이 반환된다.
메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite() 를 호출한다.
대상 클래스 타입을 지원하는가.
예) return의 대상 클래스 ( byte[] , String , HelloData )
HTTP 요청의 Accept 미디어 타입을 지원하는가.(더 정확히는 @RequestMapping 의 produces )
예) text/plain , application/json , /
canWrite() 조건을 만족하면 write() 를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성한다.


@GetMapping("/v2/members")
public Page<MemberTeamDto> searchMemberV2(@ModelAttribute MemberSearchCond cond, Pageable pageable){
return memberRepository.searchPageComplex(cond,pageable);
}
해당 코드를 보면 MemberSearchCond cond는 쿼리 파라미터 형식으로 넘어오는 데이터들
(?memberName="memberA"&teamName="teamA")에 대해 @ModelAttribute를 사용하여 객체를 생성하고 바인딩해준 후 사용하는데, Pageable은 인터페이스 형식으로 Spring Data JPA에서 PageRequest(Pageable를 구현한)객체를 만들어서 size나 page등 쿼리 파라미터로 넘어오는 것들을 넣어준다. 그렇다면 @ModelAttribute를 생략해준 것인가? 싶어 붙여보았으나 에러가 났고, 그 이유는 Spring이 자동으로 설정해주니 어노테이션이 불필요하다는 것이였다,,, 나는 @ModelAttribute를 생략해준 줄 알았는데 그게 아니였다..