스프링에서 HTTP 요청으로 넘어오는 데이터를 어떻게 받아야 하는지에 대해
명확한 개념정의 없이 사용하다보니, 때때로 문제를 일으키기도 한다.
물론 제대로 적용하고 있을 때조차, 왜 이 어노테이션을 사용해야 하는지 모르고 사용하는 경우도 많다.
회사에서는 Binary 데이터가 포함되는 파일 전송의 경우에는 모두 @ModelAttribute 로 처리하고 있었는데,
API는 Frontend와 통신함에 있어 모두 Json 형식으로 통신하고 있기 때문에,
굳이 Model 객체를 반환하지 않음에도 불구하고, ModelAttribute를 쓰는것이 맞는가에 대한 의문이 들었다.
물론 ModelAttribute가 단순히 Model 객체를 사용하는 목적이 아니기도 한 것 같아,
이 기회에 더 자세히 알아보고자 한다.
@RequestParam
@RequestParam 은 하나의 파라미터를 요청으로부터 받을 때 사용한다
@RequestParam("name") 으로 파라미터 이름을 지정할 수 있다.
지정하지 않으면 변수명이 사용된다.
Multipart 도 받을 수 있다.
@GetMapping("/test")
public String myMapping(@RequestParam String data) {
log.info("data = {}", data);
return data;
}
@ModelAttribute
HTTP 요청 데이터의 type이 form-data 일 경우에 사용할 수 있다.
(application/x-www-form-urlencoded 또는 multipart/form-data)
Get Parameter든, HTTP Body이든 Binary File이든 모두 Binding이 되는데, 그 이유는
@ModelAttribute는 필드 내부에 생성자와 Setter를 통해 매핑이 되기 때문이다.
하지만, 그 때문에 DTO 클래스에 setter나 생성자가 없다면 값이 없어 null 처리 된다.
@PostMapping("/test-model")
public String myMapping(@ModelAttribute MyModel myModel) {
log.info("model = {}, {}", myModel.getId(), myModel.getName());
return myModel.getName();
}
@RequestBody
@RequestBody 는 HTTP 요청으로 넘어오는 body의 내용을
HttpMessageConverter를 통해 자바 Object로 역직렬화 한다.
주로 Json 형식을 자바 객체로 변환하기 위해 사용하고, 요청받은 데이터를 변환시키기 때문에,
생성자나 setter가 없어도 값이 매핑된다.
특징으로는 binary 파일 형식(MultiPart 형식)은 받지 못한다.
Header에 담긴 Content-type 을 통해 어떤 Converter를 사용해 자바 객체로 변환할지 정하기 때문에,
타입 명시가 반드시 필요하다.
(Json 형식으로 받기 위해서는 "application/json" 타입으로 지정)
@PostMapping("/test")
public String myMapping(@RequestBody MyRecord myRecord) {
log.info("record = {}, {}", myRecord.id(), myRecord.name());
return myRecord.name();
}
@RequestPart
Content-type이 'multipart/form-data'인 경우에 받을 수 있다. 이 경우 MultiPartResolver가 동작한다.
즉 @RequestBody를 사용할 때, Binary 데이터가 포함된다면 사용할 수 있다.
@PostMapping("/test")
public String myMapping(@RequestPart MyRecord myRecord, @RequestPart MultipartFile file) {
log.info("record = {}, {}", myRecord.id(), myRecord.name());
log.info("file size = {}", file.getSize());
return myRecord.name();
}
ModelAttribute와 달리 RequestBody는 어떻게 생성자와 setter 없이도 클래스 내부의 private 변수에 접근할 수 있을까?
알아본 결과, RequestBody는 내부적으로 Jackson 라이브러리의 ObjectMapper를 사용하고 있는데,
Java Reflection 기술을 활용하여 private field에 접근하기 때문이다.
참고 자료 : https://middleearth.tistory.com/35
'개발 > Spring' 카테고리의 다른 글
[Spring] Elasticsearch를 Spring에 적용해보자(2) (0) | 2023.08.20 |
---|---|
[Spring] Kotlin + Spring 프로젝트 만들고 테스트 해보기 (0) | 2023.08.05 |
[Spring] @Configuration, @Bean 으로 의존성 주입(DI) 하기 (0) | 2023.07.16 |
[Spring] Security의 인가(Authorization) 실패 시 처리 (0) | 2023.07.02 |
[Spring] Security와 Jwt 사용을 통한 인증, 인가 도입기 (0) | 2023.06.25 |