JustDoEat
[SpringMVC,문제해결] 멀티파트 요청에서 File 타입, DTO 바인딩 문제 ModelAttribute와 RequestPart 차이에서 오는 문제 본문
[SpringMVC,문제해결] 멀티파트 요청에서 File 타입, DTO 바인딩 문제 ModelAttribute와 RequestPart 차이에서 오는 문제
kingmusung 2024. 11. 30. 22:25
개요
이미지 파일과 Json형식의 데이터를 같이 보내야 하는 상황에서.
MultipartFile 타입의 인자를 클라이언트로 받음과 동시에 컨트롤러에서 DTO에 한 번에 맵핑시키고 싶었다.
하지만 일반적인 DTO 맵핑과 다르게 맵핑이 되지 않아 골머리를 썩고 있었다.
문제 해결을 위해 각 특성을 살펴보고 해결해 보겠다.
RequestBody, RequestParam, RequestPart
RequestBody
Content-Type이 application/json 인 데이터를 받을 때 우리가 통상적으로 많이 쓰는 어노테이션이다.
HTTP 요청의 본문의 데이터를 DTO의 필드 값과 맵핑을 시켜줄 때 사용한다.
@Getter
public class ReviewCreateReqDto{
private final Long productId;
private final int rating;
private final String content;
ReviewCreateReqDto(Long productId, int rating, String content){
this.productId = productId;
this.rating = rating;
this.content = content;
}
}
해당 요청 본문에 있는 값들은 컨트롤러로 들어올 때 @RequestBody라는 어노테이션에 의해 자동으로 맵핑이 된다.
@GetMapping("/reviews")
public String getProduct(@RequestBody ReviewCreateReqDto reviewCreateReqDto)
하지만, 나의 상황은
Content_type = multipart/form-data 이기 때문에 배제하도록 하겠다.
RequestParam
@GetMapping("/products")
public String getProduct(@RequestParam String name, @RequestParam int price)
RequestParam은
GET /products?name=laptop&price=1200
위처럼 쿼리 파라미터를 맵핑하는 데 사용한다.
혹은 Content_type = multipart/form-data에서 application/json 타입의
간단한 데이터를 맵핑할 때 사용되고, DTO로의 변환은 허용하지 않는다.
body부분에 application/json 이 있다고 Header에 Content_type이 application/json 인건 절대 아니다.
Header에 Content_type은 Content_type = multipart/form-data이다.
성공적으로 잘 된다.
DTO로의 변환을 시도한다면?
'java.lang.String' to required type
'com.gulbi.Backend.domain.rental.product.dto.product.request.ProductRegisterRequestDto';
Cannot convert value of type 'java.lang.String' to required type 'com.gulbi.Backend.domain.rental.product.dto.product.request.ProductRegisterRequestDto' for property 'productInfo'
dto로
일단 DTO로의 맵핑이 안되므로 RequestParam도 탈락이다.
+
@PathVariable
@GetMapping("/products/{id}")
public String getProduct(@PathVariable Long id
RequestPart
멀티파트 요청에서 파일과 Json 데이터를 같이 보낼 때 사용한다,
Json만 보낼 때도 사용가능하다 하지만 이럴 거면 멀티파트 요청을 할 필요는 없겠다.
추가로 RequestParam과 다르게 DTO로의 변환을 허용한다.
"나 : 그러면 RequestPart를 사용하면 문제 해결이네??
??? : 아니."
나는 json타입을 못 받아서 고생을 한 게 아니다, 멀티파트에서 파일 부분을 받아올 때 MultipartFile 타입이 아닌
깔삼하게 DTO로 변환을 받고 싶었다.
문제는 이렇게 요청을 보내면 내가 의도한 방식대로 동작하지 않고, ProductImageCollection에는 null값이 담기게 된다,
즉 맵핑이 제대로 되지 않았던 거다.
"ModelAttribute를 사용하면 해결이 된다."
이렇게 되면 복잡한 DTO 생성로직에도 굴복하지 않고 바로 맵핑이 가능하다.
Modelattribute의 정의를 찾아보면, ContentType = multipart-formdata에서 사용을 하고, 폼데이터로 들어온 데이터를 dto에 바인딩을 시켜준다는데 RequestPart 차이점을 잘 모르겠다.
하지만 한 가지 알아낸 건 있다.
RequestPart와 ModelAttribute의 객체생성 차이.
해당 실험에서 볼 수 있는 지표는, ModelAttribute는 생성자를 이용, RequestPart는 생성자를 이용하지 않음.이다.
요청값에서 단순히 String, Long, int, double 등 기본적인 자료형의 값을 추출해 DTO와 매핑은 RequestPart가 가능하지만.
나의 경우처럼 DTO 타입에 기본적인 자료형이 아닌, 다른 타입(클래스, 엔티티, 일급 컬렉션 등)을 받는다면 스프링이 인식을 할 수 없다.
객체 생성 시 필요한 로직을 생성자에 정의를 했지만 RequestPart는 생성자를 이용해서 DTO를 만들지 않기 때문에 맵핑이 되지 않지만.
ModelAttribute는 생성자를 이용하기 때문에 맵핑이 된 것이다.
'Yajoba > Backend' 카테고리의 다른 글
MultipartFile 에서 파일 확장자를 검사 해보자. + 멀티파트에서 @Validated가 안되는 현상 (4) | 2024.11.28 |
---|---|
상품검색 서비스가 언제 확장될지 모른다! 전략패턴(Strategy Pattern)으로 해결해보자 (0) | 2024.11.27 |
팩토리 클래스에 객체 생성에 필요한 서비스를 의존을 받았다. 정답일까 아닐까 (1) | 2024.11.21 |
Data JPA, DTO, Projection 방식중 적합 한 방식은 ? (0) | 2024.10.28 |
[문제해결]카테고리입니다, 셀프조인도 같이 드시면 맛있습니다 (4) | 2024.10.13 |