데이터 매핑 - @ModelAttribute, @RequestParam, @RequestBody, @RequestPart

달래·2024년 2월 15일
0

Spring

목록 보기
3/7

REST API를 개발하면서, 초보자로서 항상 헷갈리는 것은 http 요청을 어떻게 받아와야 하는지입니다.
주로 데이터 요청은 JSON 데이터로 받을텐데, 페이징이 필요한 경우나 여러 필요에 의한 경우 queryString으로 데이터를 받을 수 있ㅇ습니다.

뿐만 아니라, 파일 전송이 필요한 경우는 form data로 보내기도 합니다.

이런 각각의 경우에서 클라이언트의 요청을 어떻게 API에서 받아오는지 파악해봅시다!

🫱클라이언트에서 데이터 보내기


HTTP Request Header: Content-Type
HTTP Request Body : 데이터

우선 클라이언트에서 서버로 데이터를 어떻게 넘기는지, 그 방식을 알아볼 필요가 있습니다.

일반적으로 HTTP Request의 Body에 클라이언트가 전송하려는 데이터가 담기는데, 해당 Body의 타입을 명시하는 Header가 Content-Type입니다.

이 Content-Type에 따라 서버는 데이터를 어떻게 받아올 지 정할 수 있습니다.

application/json

{key : value} 의 형태로 HTTP request body에 담아 전송합니다.

application/x-www-form-urlencoded

HTML form post의 default 값으로, 데이터를 url 인코딩 후 쿼리스트링인 key=value&key=value 형태로 HTTP request body에 담아 전송합니다.

HTML form get 전송은 body가 아닌 url에 queryString으로 key=value&key=value 형식으로 전송합니다.


multipart/form-data

파일 업로드시 사용되며 '파일을 비롯한 여러 데이터가 있음'이라는 뜻을 가집니다.
파일을 문자로 생성하여 HTTP request body에 담아 서버로 전송합니다.


🤝서버에서 데이터 받기


@ModelAttribute

  • multipart/form-data
  • formData(쿼리스트링)

Spring Controller에서 값을 받을 때 사용되는 default 값입니다.

즉, HTTP body로 오든 파라미터로 오든 다 받을 수 있고 body와 파라미터가 같이 오는 경우에도 값이 바인딩됩니다.

이런 형태가 가능한 이유는 @ModelAttribute가 필드 내부와 1:1로 값이 Setter나 Constructor를 통해 값이 매핑되기 때문입니다.


@RequestParam

  • multipart/form-data
  • formData(쿼리스트링)
public ResponseEntity<Void> getDiaries(@RequestParam(required="false") Long pageNo) {...}

한 가지 유형의 데이터를 받아올 수 있습니다.

파라미터가 String이나 MultipartFile이 아닌 경우 ConverterPropertyEditor에 의해 처리됩니다.

기본적으로 파라미터가 필수적으로 들어오게 설정되어 있기에 파라미터가 들어오지 않는 경우 BadRequest가 발생하므로 파라미터가 들어올 수도, 들어오지 않을 수도 있다면 required = false를 주어야 합니다.

요청 데이터의 개수가 많아지면 DTO를 생성해서 값을 매핑하는 것이 효율적입니다.


@RequestBody

  • application/json
public ResponseEntity<Void> createDiary(@RequestBody @Valid DiaryCreateRequest request) {...}

클라이언트의 HTTP 요청으로 넘어오는 HTTP Body의 내용을 HttpMessageConverter를 통해 Java Object로 역직렬화합니다.

클라이언트의 HTTP 요청 중 Body에서 바이너리 파일(multipart)을 포함하고 있지 않은 데이터를 받기 때문에, multipart/form-data가 포함되는 경우는 사용할 수 없습니다.

@RequestBody는 HTTP 요청으로 같이 넘어오는 Header의 Content-type을 보고 어떤 Converter를 사용할지 정하기에 클라이언트는 Content-type을 반드시 명시해야 합니다.


@RequestPart

  • application/json
  • multipart/form-data

@RequestBody + multipart/form-data인 경우에 사용합니다.

클라이언트의 HTTP 요청 중 Body에서 MultipartFile(Binary Stream)이 포함되는 경우에는 MutliPartResolver가 동작하여 (여기서도 전략 패턴이 사용) 역직렬화를 하게 됩니다.

Content-type이 'multipart/form-data'와 관련된 경우에 사용하는데,
MultipartFile이 포함되지 않는 경우는 @RequestBody와 같이 HttpMessageConverter가 동작하게 됩니다.

MultipartFile이 포함되지 않은 경우에는 @RequestBody와 같은 역할을 합니다.

@RequestBody, @RequestPart

RequestBody와 RequestPart는 HttpMessageConverter에 의해 동작하므로 Setter 없이 Object가 생성됩니다.

필드를 찾을때 ObjectMapper를 이용하고 이 ObjectMapper는 NoArgsConstructor + Getter 또는 Setter 등을 통해 private field에 접근 할 수 있게 구현되어 있습니다.

이때 접근할 수 있는 이유는 Jackson 라이브러리가 Reflection을 통해서 private field에 값을 할당할 수 있기 때문입니다.

profile
아좌잣~!

0개의 댓글