Swagger UI 적용을 위해 다음 의존성을 추가했다.
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
그런데 /swagger-ui/index.html 접속 시 401 Unauthorized 에러가 발생했고, 콘솔에는 NoSuchMethodError와 ControllerAdviceBean 관련 오류 발생했다.
springdoc-openapi 2.5.0 버전이 내가 사용 중이던 Spring Boot 3.4.4 버전과 호환되지 않는 것이었다.
springdoc 내부에서 사용하는 API가 Spring 3.2.x 기준이었다...
Spring Boot 버전을 3.2.5로 다운그레이드했더니 Swagger UI에 접속을 성공했다.
상품 등록 API에서 이미지와 상품 데이터를 동시에 @RequestPart로 받도록 설계했다.
@Operation(summary = "상품 등록", description = "상품 정보를 등록합니다. 이미지 파일은 Multipart 형식으로 첨부합니다.")
@PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<?> createItem(
@Parameter(description = "상품 데이터(JSON)") @RequestPart("data") ItemRequestDto requestDto,
@Parameter(description = "상품 이미지 파일들") @RequestPart(value = "images") List<MultipartFile> images,
@AuthenticationPrincipal UserDetailsImpl userDetails) throws IOException {
...
}
Swagger에서 요청 시 JSON을 application/json이 아닌 application/octet-stream 으로 보내버려서 아래 에러 발생했다.
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException:
Content-Type 'application/octet-stream' is not supported]
Swagger의 @RequestPart 지원이 제한적이라 JSON을 직렬화하지 못하고 이진 데이터로 보내버린다. 쉽게 말하면 JSON 데이터를 보내려고 해도, 내부적으로 그걸 일반 JSON이 아니라 ‘파일처럼’ 이진 데이터 (octet-stream) 으로 보내버리기 때문이다.
application/octet-stream 처리를 Jackson이 하지 않도록 커스텀 컨버터 등록했다.
@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
// Swagger가 보내는 'application/octet-stream' 요청을 무시하게 설정
public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
protected boolean canWrite(MediaType mediaType) {
return false;
}
}
이 컨버터는 application/octet-stream 타입을 아예 무시하게 하므로, Jackson이 application/json 처리 쪽으로 넘어가게 된다.
"이진 데이터는 무시하라"는 설정을 해주는 커스텀 HttpMessageConverter`를 만들어서,
Spring이 "이건 처리 안 해도 되는 거구나" 하고 넘기게 한 것이다.
Swagger에서도 JSON과 이미지를 동시 전송 성공하게 되었다.
@RequestPart를 쓸 때는 JSON 직렬화 처리 방식을 정확히 이해하고 있어야 함MediaTypeNotSupported가 나왔다면 컨버터 체인을 의심해볼 것HttpMessageConverter를 구현하거나 확장해 적용하는 방법을 익힘