본문 바로가기
TIL(Today I Learned)

@RequestParam vs @RequestBody vs @RequestPart 공부한 내용 정리

by kkkdh 2023. 1. 31.
728x90

이번에 처음으로 Spring을 이용해 WAS 서버를 구현하다가 client로 부터의 request body의 parameter를 바인딩하는 방식에 여러 가지 어노테이션을 활용할 수 있음을 알게 되었습니다.

 

여러가지 글을 참고해서 자세한 원리까지는 모르더라도 일단 오늘 공부를 통해 알게된 내용을 최대한 정리해 보려 합니다.

 

Request message의 data를 매핑하기 위해 사용하는 어노테이션들

  • @RequestParam
  • @RequestBody
  • @RequestPart

@RequestParam

spring document에서는 위와 같이 설명하고 있다.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestParam.html

 

RequestParam (Spring Framework 6.0.4 API)

Whether the parameter is required. Defaults to true, leading to an exception being thrown if the parameter is missing in the request. Switch this to false if you prefer a null value if the parameter is not present in the request. Alternatively, provide a d

docs.spring.io

Document를 최대한 읽어본 결과, RequestParam은 query parameter, form data 및 multipart data의 일부를 바인딩하기 위해 사용할 수 있다고 합니다.

 

그러니깐 GET 방식의 HTTP request에 따라서 query parameter를 매핑하기 위해서도 사용할 수 있고, POST 방식 요청에 따른 form data도 바인딩하기 위해 사용할 수 있음을 의미합니다. multipart/form-data도 바인딩 가능

 

이는 Servlet API가 자동으로 request body를 parsing 한 뒤 "parameters"라고 불리는 single map에 query parameters와 form data를 mapping 시켜주기 때문이라고 합니다.

 

이렇게 RequestParam annotation을 사용한 request message의 데이터를 바인딩하기 위해서는 {name : value} 쌍으로 전달되는 parameter의 name과 일치하는 매개변수명을 사용해야 합니다.

헷갈려서 chatGPT한태 물어봤습니다..

어노테이션의 이름이 RequestParam 이라서 GET 요청에 따른 데이터만 바인딩이 되는건지 궁금해서 chatGPT에 물어보니 form data도 매핑할 수 있다고, 답장해줘서 이 부분도 이해할 수 있었습니다.

annotation에 부여할 수 있는 속성들

스펙을 보아하니 기본 값도 부여할 수 있고, 매개 변수의 이름을 다르게 사용하기 위해 바인딩할 request parameter의 이름을 속성에 지정할 수도 있을 것 같습니다.

 

required는 필수 여부를 부여하는 것 같습니다.

 

@RequestParam의 경우 하나의 parameter를 받아오기 위해 사용할 수 있기 때문에, 여러 개의 parameter를 받아와야 하는 상황이 된다면, @RequestBody 또는 @RequestPart와 더불어 DTO를 사용하는 것이 유지보수 측면에서 더 좋을 것 같다고 합니다.


@RequestBody

이 어노테이션은 request body를 통째로 바인딩 하기위해 사용할 수 있는 어노테이션입니다. (request에 binary 파일이 포함되어 있으면 안됩니다.)

 

Content-type 중 application/json or application/x-www-form-urlencoded를 바인딩 하는데 사용

 

document에 따르면 HttpMessageConverter를 거쳐서 request의 content type에 의존한 request body가 method argument로 매핑된다고 합니다.

 

@RequestBody 어노테이션을 사용하면, 자동 객체 생성 방식을 통한 request body mapping이 지원되는데, 저같은 경우에는 프로젝트에서 다음 그림과 같이 DTO(data transfer object)를 하나 만들어서 사용했습니다.

자동 객체 생성이 가능하기 위해서는 전달되는 json type의 request body의 key에 맞는 필드가 모두 구현되어 있어야 하며, getter를 구현한 경우 바인딩된 값들에 접근할 수 있습니다. (setter를 따로 구현하지 않아도 mapping 된다고 합니다.)

 

json 같은 데이터는 @RequestParam 어노테이션을 이용한 바인딩이 불가능하기 때문에, 한 번에 DTO를 이용한 request body 바인딩을 구현하고 싶은 경우에는 @RequestBody 어노테이션을 사용하는 편이 좋을 것 같습니다.


@RequestPart

스펙의 첫 줄만 읽어도 "multipart/form-data" 양식을 위한 어노테이션임을 알 수 있습니다.

 

지원되는 메서드 인수 타입에는 Spring의 MultipartResolver 추상화와 결합된 MultipartFile과 Servlet 3.0 multipart 요청과 결합된 javax.servlet.http.Part가 포함된다고 합니다. (이건 뭔지 자세히 모르겄습니다.)

 

@RequestParam 어노테이션은 “multipart/form-data” 요청의 일부를 같은 메소드 인수 타입을 지원하는 메소드 인수와 연결하는 데 사용할 수 있습니다.
주요 차이점은 메소드 인수가 String 또는 원시 MutipartFile/Part가 아닌 경우 @RequestParam은 등록된 Converter 또는 PropertyEditor를 통한 형식 변환에 의존하는 반면, @RequestPart는 요청 부분의 ‘Content-Type’ 헤더를 고려하는 HttpMessageConverters에 의존한다는 점입니다.

여기서 알 수 있는 점은 @RequestParam과 @RequestPart가 복잡한 데이터 타입(file(이미지), string(JSON, XML 등..))을 제외한 다른 유형의 데이터 타입 변환에 의존하는 요소가 다르다는 점인 것 같습니다.

 

추가적인 차이점은 @RequestPart가 @RequestParam이 매핑 가능한 일반적인 name - value 유형의 data 뿐만 아니라, 복잡한 데이터(JSON, raw data, XML 등..)의 바인딩을 담당할 수 있다는 것이 중요한 것 같다고 생각했습니다.

 

그러니까 @RequestPart를 사용하면, (JSON, MultipartFile, text) 이런 식으로 request body가 넘어오는 경우 각각의 part를 분할해서 mapping 하기 위해서는 MultiPartResolver를 이용한 역직렬화를 해야 하므로 "multipart/form-data" 전용인 것 같다..

설정 가능한 옵션들

여기서 name 속성을 작성하지 않으면, default로 method의 매개 변수 명으로 사용되는 것 같습니다. 


공부한 내용들을 조금 정리해 보자면,

  • 세 개의 어노테이션 모두 request message의 data를 메서드의 매개 변수로 바인딩하기 위해 Controller에서 사용한다.
  • @RequestParam은 하나의 query parameter 또는 form data의 값을 바인딩하기 위해 사용하며
  • @RequestBody는 request message의 request body 전체를 바인딩할 때 사용한다. (DTO를 이용한 자동 객체 생성 기능 또한 사용 가능하다)
  • @RequestPart는 "multipart/form-data" 전용으로 사용하며, 다른 part의 데이터를 쪼개서 가져오는데 특화되어 있다.

참고한 글들

https://somuchthings.tistory.com/160?category=983431 

 

[Spring boot] @RequestParam vs @RequestPart

조사하게 된 원인 프로젝트를 하면서 Multipart 데이터로 JSON과 이미지 파일 데이터를 함께 받기 위해 스프링 기능을 찾던 도중 @RequestPart에 대해 새로 알게 되었다. @RequestParam이라는 어노테이션도

somuchthings.tistory.com

https://ocblog.tistory.com/49

 

Spring / @RequestBody vs @RequestParam 이해하기

컨트롤러에서 데이터를 인자에 할당하는 대표적인 방법으로는 @RequestBody 와 @RequestParam 이 있다. @Controller public class UserController { @PostMapping("/receive") public String age(@RequestParam String name) { System.out.prin

ocblog.tistory.com

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestPart.html

 

RequestPart (Spring Framework 6.0.4 API)

Annotation that can be used to associate the part of a "multipart/form-data" request with a method argument. Supported method argument types include MultipartFile in conjunction with Spring's MultipartResolver abstraction, jakarta.servlet.http.Part in conj

docs.spring.io

https://middleearth.tistory.com/35

 

RequestBody vs RequestPart vs RequestParam vs ModelAttribute

이 4개는 매일 사용하면서도 매일 헷갈린다. 내용 정리를 확실하게 해놔야 할 필요성을 느껴 정리한다. @RequestBody HTTP 요청으로 넘어오는 body의 내용을 HttpMessageConverter를 통해 Java Object로 역직렬

middleearth.tistory.com

 

공부하며 이해한 내용을 바탕으로한 글이기 때문에, 틀린 내용이 포함되어 있을 수 있으며, 공부를 진행하면서 업데이트할 예정입니다!

728x90

댓글