[SpringBoot] DTO + MultipartFile 동시 요청 오류

qufdl·2023년 7월 2일
1

Trouble Shooting

목록 보기
1/1

문제 상황

게시물에 이미지를 첨부하는 기능을 구현하면서 @RequestBody로 DTO를, @RequestParam 으로MultipartFile을 함께 입력받고자 했다. Content-Type이 다른 두 가지 데이터를 한 번에 입력 받은 적이 없어서 기존처럼 구현했더니 에러가 발생했다.

기존 코드 : @RequestBody + @RequestParam

@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> writePost(
      @RequestBody WritePostRequest request,
      @RequestParam("image") MultipartFile image) throws IOException {
    postService.writePost(request, image);
    return ResponseEntity.noContent().build();
}

Swagger로 테스트하니 다음과 같은 415(지원되지 않는 미디어 유형)오류가 생겼다.

"Content-Type 'multipart/form-data;boundary=----WebKitFormBoundarykAE7PKpAiKkbsfIt;charset=UTF-8' is not supported.",

알아보니 multipart/form-data와 JSON(or XML)을 함께 입력 받기 위해선 @RequestPart 어노테이션을 사용해야 한다.

해결

1차 수정 코드 : @RequestPart + @RequestPart

@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> writePost(
        @RequestPart(value = "request") WritePostRequest request,
        @RequestPart(value = "image") MultipartFile image) throws IOException {
    postService.writePost(request, image);
    return ResponseEntity.noContent().build();
}

Swagger로 데이터를 전달하니 다음과 같은 오류가 발생한다.

"detail": "Content-Type 'application/octet-stream' is not supported.",
  • Swagger로 springdoc-openapi를 사용했는데, 이는 api당 두가지 이상의 Content-type의 데이터 요청 기능을 제공하지 않기 때문에 발생한 오류다.
  • Postman을 사용했을 때는 정상적으로 동작한다. Postman으로 테스트 할 경우 각 입력의 Content-type을 명시해주어야 한다.

Postman으로 테스트를 진행해도 되지만, react 개발을 하는 팀원과 Swagger을 통해 소통하는 중이므로 Swagger로 테스트가 가능하길 바랐다.
그래서 여기를 참고하여 수정했다.

2차 수정 코드

@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> writePost(
         @RequestPart(value = "request") @Parameter(schema =@Schema(type = "string", format = "binary")) WritePostRequest request,
         @RequestPart(value = "image") MultipartFile image) throws IOException {
      postService.writePost(request, image);
      return ResponseEntity.noContent().build();
}


request엔 JSON 파일을, image엔 이미지 파일을 첨부하면 정상적으로 실행된다.

@RequestParam vs @RequestPart

1. @RequestParam

  • 쿼리 파라미터, form 데이터, multipart/form-data 등의 요청 파라미터를 처리할 수 있다.
  • 메소드 인수가 String이나 multipart/form-data가 아닐 경우 등록된 Converter 또는 PropertyEditor를 통한 형식 변환에 의존한다.
  • Key/Value form 필드와 함께 사용된다.

2. @RequestPart

  • multipart/form-data에 특화되어 여러 복잡한 값을 처리할 때 사용할 수 있다.
  • 메소드 파라미터 타입이 String 또는 MultipartFile/Part가 아닐 경우 요청 부분의 Content-Type 헤더를 고려하는 HttpMessageConverters에 의존한다.
  • JSON, XML등을 포함하는 복잡한 Content를 포함하는 곳에 적합하다.

Reference

0개의 댓글