참고할만한 관련 링크

https://okky.kr/article/479068

 

OKKY | @RequestBody 질문인데 꼭좀 부탁드립니다...(제발...ㅠ)

intellij 로 시작한 Spring Boot 프로젝트에서 RequestBody 로 객체를 받지 못해 죽겠네요..ㅠㅜ 원인을 모르겠어서 소스 전체를 올려봅니다... RestController RequestMapping(value /builder/board ) public class BoardBuilderC

okky.kr

https://stackoverflow.com/questions/44230121/spring-boot-unsupported-media-type-with-requestbody

 

Spring boot Unsupported Media Type with @RequestBody

I checked in several different ways, also downloaded a new project to see what to check where is bug but I still do not know the answer. That is my RestController @RestController @RequestMapping(...

stackoverflow.com

 

한줄 요약

 

지금 작성하고 있는 컨트롤러의 매개변수 위주로 점검해보세요.

매개변수에 붙여준 어노테이션을 잘 확인해보세요.

 

 

상황

 

파일 업로드 기능이 있는 API를 만들기 위해서 아래와 같은 코드를 작성하고 테스트를 진행 했습니다.

@RestController
@RequestMapping("/card")
public class CardController {
	// ... 중략

	// 카드 생성하기
    @PostMapping(value = "")
    public ResponseEntity team (HttpServletRequest request
            , @RequestBody CardDTO cardDTO) throws UserNotFoundException, ResourceConflict {

		// 카드 생성
        Card savedCard = cardService.create(request, cardDTO);

        return new ResponseEntity(ResponseFilterManager.setFilters(savedCard, filters)
                , ResponseHeaderManager.headerWithOnePath(savedCard.getId()), HttpStatus.ACCEPTED);
    }
}

요청을 하면 Card 를 하나 생성하고 카드와 같이 파일을 하나 업로드 할 수 있는 기능입니다.

 

그리고 위 API 에 다음과 같이 form-data 형식 Content-Type 을 선택하고

파일을 세팅하고 요청을 전송 했습니다.

 

그런데 postman 이 다음과 같은 오류를 반환 했습니다.

 해석을 하자면 지원하지 않는 미디어 타입이라는 뜻 입니다.

즉, 해당 요청을 처리할 컨트롤러가 제 소스 내부에 없다는 말인데..

컨트롤러를 적절하게 만들었음에도(그렇게 생각했다.) 이런 에러를 보이는 이유를 찾을 수 없었습니다.

 

그러다가 문제의 원인을 발견했는데 컨트롤러의 매개변수가 문제 였습니다.

 

문제의 원인을 알리기 전에 앞어서 Content-Type에 대한 사전 지식이 있다면 문제 원인을 쉽게 파악할 수 있습니다.

Content-Type 에 대해 알고 싶다면 아래 링크를 참고 하시기 바랍니다.

https://way-be-developer.tistory.com/243

 

HTTP Request, Content-Type 이란?

Content-Type 이란? https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Content-Type Content-Type - HTTP | MDN Content-Type 개체 헤더는 리소스의 media type을 나타내기 위해 사용됩니다. developer...

way-be-developer.tistory.com

 


 

@RequestParam, @RequestBody, @ModelAttribute

 

일반적으로 매개변수를 받기 위해서 많이 사용하는 어노테이션의 종류에는 다음과 같은 3가지가 있습니다.

@RequestParam, @RequestBody, @ModelAttribute

 

전부 request 의 body를 매개변수로 받을 수 있다는 점에서 공통점이 있으나 

이 어노테이션 들을 정확하게 알지 못하고 사용하면 저와 같은 문제를 겪을 수 있습니다.

 

 


@RequestParam

 

단일 데이터를 받기 위해서 사용합니다.

즉, Request (클라이언트 요청)의 Content-Type이 "application/json" 이든, "application/x-www-form-urlencoded" 이든 "mulipart/form-data" 이든 상관 없이 동일하게 key에 매칭되는 하나의 필드 값을 받을 수 있습니다.

 

 

 

@RequestBody

 

클라이언트가 전송한 Json 형태의 데이터를 Java의 객체로 변환 시켜주는 역할을 합니다.

따라서 클라이언트가 요청한 헤더의 Content-Type이 application/json이 아니면 받을 수 없습니다.

또한 Body가 존재하지 않는(않아야 하는) Get 요청을 서버에서 @RequestBody로 받으려고 하면 에러가 발생할 수 있습니다.

 

- 추가정보

Get 메소드는 Body를 포함할 수 있지만, 공식적으로 권장하지 않기 때문에 Body가 없는 요청이 종종 들어올 수 있고(예를 들어 브라우저 url으로 요청을 하는 경우) 이때 @RequestBody를 사용하면 문제가 될 수 있습니다.

 

 

 

@ModelAttribute

 

@ModelAttribute는 클라이언트가 전송한, Content-Type이 multipart/form-data 인 데이터를 받기 위해 사용합니다.

이 때 @ModelAttribute 는 클라이언트가 전송한 데이터를 Java 객체와 바인딩하기 위해서 Setter 를 호출 합니다. (Setter 가 있어야 합니다)

또한 이 때 검증 작업(Validation)이 추가적으로 진행 됩니다.

 

예를 들어서 클라이언트가 아래와 같은 폼을 전송했다고 가정합니다.

<form action="http://localhost/test.jsp" method="post" enctype="multipart/form-data">
	<input type="text" name="name" value="김철수" />
	<input type="text" name="order" value="첫번째" />
</form>

그리고 서버에서 @ModelAttribute 를 이용해 아래와 같이 받습니다.

 

// DTO
public class PersonDTO {
	private String name;
	private int order;
	// getter와 setter 존재
}
// Controller
@PostMapping("test")
public void test (@ModelAttribute PersonDTO personDTO) {
		// ...
}

만약 서버가 위에서 처럼 @ModelAttribute 를 이용해서 

전송된 form 데이터를 PersonDTO 으로 받으려고 하면

int order 변수에 이 값(첫번째)을 바인딩 할 때 에러가 발생합니다. (BindException)

다른 어노테이션은 받을 수 없는 데이터를 무시하는 것과 대조됩니다.

 

한편, @ModelAttribute 는 setter 기반으로 바인딩을 한다고 했는데,

따라서 setter가 없으면 바인딩이 되지 않습니다.

 

(@RequestBody 어노테이션은 Setter함수가 없어도 값이 매핑이 됩니다.)

(아마 Reflection 기반이라서 그럴겁니다. 동작 원리는 아직 찾아보지 않았습니다.)

 

 

이렇게 오늘은 unsupported media type 415 error 문제가 발생하는 원인을 알아보았습니다.

적절한 타입의 어노테이션을 사용해서 이 문제를 해결하시길 바랍니다.

 

'프레임워크 > Spring' 카테고리의 다른 글

spring framework - @Value 가 동작하지 않는다면  (1) 2022.02.13