[Spring] Custom HttpMessageConvert 생성 & 등록을 위한 WebMvcConfigurer 활용
목차
개요
❗Custom Converter 등록을 위해서만 WebMvcConfigurer을 사용하지는 않습니다. `WebMvcConfigurer`에 대해 간단히 알아본 후, Custom `HttpMessageConverter`를 등록하는 방법에 대해 알아보겠습니다. 또한 일반 Type Converter와 다른 Custom `HttpMessageConverter` 생성 및 등록 방법에 대해 알아보겠습니다.
WebMvcConfigurer
정의
Spring Framework에서 웹 MVC 설정을 사용자 정의할 수 있도록 제공되는 인터페이스입니다.
✨ Spring Boot를 사용하면 대부분의 설정이 자동으로 제공되지만, 특별한 요구사항이 있을 때 `WebMvcConfigurer`를 구현해서 설정을 직접 조정할 수 있습니다.
Spring이 WebMvcConfigurer 구현체를 이용하여 설정하는 것이 아닌데, Spring Boot의 설정이 자동으로 제공되는 이유는 다음과 같습니다.
Spring Boot의 자동 설정 클래스
`org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration`
- 이 클래스는 Spring Boot에서 기본적인 MVC 설정을 자동으로 제공하는 핵심 클래스입니다.
- 여기서 ViewResolver, MessageConverter, Interceptor 등 대부분의 기본 설정을 자동으로 구성합니다.
설정 대상
- URL 매핑
- 정적 자원 처리
- CORS
- 인터셉터
- Formatter
- Message Converter 등
주요 메서드
메서드 | 역할 | 설명 |
configurePathMatch(PathMatchConfigurer configurer) | 경로 설정 | URL 경로 매칭 방식 설정 (예: 슬래시 처리 등) |
configureContentNegotiation(ContentNegotiationConfigurer configurer) | 콘텐츠 협상 | 클라이언트 요청의 Accept 헤더에 따라 반환 콘텐츠 유형 결정 |
configureAsyncSupport(AsyncSupportConfigurer configurer) | 비동기 설정 | @Async, Callable, DeferredResult 등을 사용할 때 비동기 처리 설정 |
configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) | 서블릿 핸들링 | DispatcherServlet이 처리하지 않는 요청을 서블릿에 위임 |
addFormatters(FormatterRegistry registry) | 포맷터 등록 | 문자열 ↔ 객체 변환용 포맷터, 컨버터 등록 |
addInterceptors(InterceptorRegistry registry) | 인터셉터 등록 | 요청 전/후 가로채기 로직 설정 (예: 인증, 로깅) |
addResourceHandlers(ResourceHandlerRegistry registry) | 정적 자원 처리 | /static/**, /public/** 등 정적 파일 위치 매핑 |
addCorsMappings(CorsRegistry registry) | CORS 설정 | 도메인 간 요청 허용 정책 설정 |
addViewControllers(ViewControllerRegistry registry) | 뷰 컨트롤러 설정 | 컨트롤러 없이 단순 URL → 뷰 매핑 |
configureViewResolvers(ViewResolverRegistry registry) | 뷰 리졸버 설정 | JSP, Thymeleaf 등의 뷰 리졸버 설정 |
addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) | 인자 리졸버 | 컨트롤러 메서드 인자 바인딩 커스터마이징 |
addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) | 반환값 핸들러 | 컨트롤러 반환값 처리 방식 커스터마이징 |
configureMessageConverters(List<HttpMessageConverter<?>> converters) | 메시지 컨버터 설정 | 요청/응답 데이터를 Java 객체와 JSON 등으로 변환 |
extendMessageConverters(List<HttpMessageConverter<?>> converters) | 메시지 컨버터 확장 | 기존 컨버터에 추가 설정 적용 |
configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) | 예외 처리 설정 | 예외 → 응답으로 변환하는 설정 커스터마이징 |
extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) | 예외 처리 확장 | 기존 예외 처리 로직에 추가 기능 부여 |
내부 구조
public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {
}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
default void addFormatters(FormatterRegistry registry) {
}
default void addInterceptors(InterceptorRegistry registry) {
}
default void addResourceHandlers(ResourceHandlerRegistry registry) {
}
default void addCorsMappings(CorsRegistry registry) {
}
default void addViewControllers(ViewControllerRegistry registry) {
}
default void configureViewResolvers(ViewResolverRegistry registry) {
}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
- 각 메서드는 `default`로 정의되어있습니다. 그 이유는 WebMvcConfigurer 인터페이스 구현 시, 모든 메서드를 구현할 필요없이 필요한 메서드만 구현하기 위함입니다.
Custom MessageConverter 생성 및 등록
❗WebMvcConfigurer 중에서, `HttpMessageConverter`와 관련된 `extendMessageConverters()`와 `configureMessageConverters`를 사용하여 등록합니다.
등록 방식
1. Custom MessageConverter 작성
public class MyCustomMessageConverter extends AbstractHttpMessageConverter<MyType> {
public MyCustomMessageConverter() {
super(new MediaType("application", "mytype"));
}
@Override
protected boolean supports(Class<?> clazz) {
return MyType.class.isAssignableFrom(clazz);
}
@Override
protected MyType readInternal(Class<? extends MyType> clazz, HttpInputMessage inputMessage)
throws IOException {
// 요청 데이터 파싱
InputStream inputStream = inputMessage.getBody();
// ...직접 파싱 로직...
return new MyType();
}
@Override
protected void writeInternal(MyType myType, HttpOutputMessage outputMessage)
throws IOException {
// 응답 데이터 출력
OutputStream outputStream = outputMessage.getBody();
// ...직접 출력 로직...
}
}
- 복잡한 작업을 간단하게 처리해주기 위해 `HttpMessageConverter`를 직접 구현하지 않고 ` AbstractHttpMessageConverter` 추상 클래스를 상속받아서 훨씬 편리하고 안전하게 custom converter를 만들 수 있습니다.
메서드 | 역할 |
supports(Class<?> clazz) | 이 컨버터가 처리할 수 있는 타입인지 확인 |
readInternal(...) | HTTP 요청 본문 → Java 객체로 변환 (역직렬화) |
writeInternal(...) | Java 객체 → HTTP 응답 본문으로 변환 (직렬화) |
2_1. extendMessageConverters(List<httpmessageconverter<?>> converters) 방식</httpmessageconverter<?>
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MyCustomMessageConverter());
}
}
- `@Configuration`: Spring에게 이 클래스를 Bean 설정 파일로 등록
- 내부에서 정의된 설정(예: MessageConverter, Interceptro 등)을 자동으로 적용하게 됩니다.
- `@Configuration`을 붙여야 Bean으로 등록되어 사용할 수 있습니다.
- 기존 Spring의 기본 컨버터 리스트에 커스텀 컨버터를 추가하였습니다.
- 자동 설정된 기본 컨버터는 그대로 유지됩니다.
2_2. configureMessageConverters(List<httpmessageconverter<?>> converters) 방식</httpmessageconverter<?>
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MyCustomMessageConverter());
}
}
- 커스텀 컨버터만 직접 명시합니다.
- Spring이 기본으로 제공하는 컨버터는 등록되지 않습니다.
- 전체 메시지 컨버터를 직접 컨트롤하고 싶을 때만 사용합니다.
✨ 주의 : 기본 JSON 컨버터(Jackson 등)도 포함되지 않기 때문에, 필요한 컨버터를 모두 수동으로 등록해야합니다.
custom 말고, 기본 HttpMessageConverter들은 자동 설정(Auto Configuration)을 통해 다음처럼 등록됩니다.
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
...
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
messageConverters.add(new MappingJackson2HttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ByteArrayHttpMessageConverter());
// 등등
}
...
}
Custom MessageConverter 필요 상황
상황 | 설명 |
기존 컨버터가 지원하지 않는 포맷 | 예: CSV, YAML, 커스텀 바이너리, 고유한 텍스트 포맷 등 |
특정 DTO만 별도로 처리하고 싶을 때 | 일부 클래스에만 커스텀 JSON 포맷 적용 등 |
보안이나 암호화된 요청/응답 처리 | 입력값 복호화 또는 응답 암호화 |
외부 시스템 연동 (특수 API 형식) | 예: 외부 시스템이 application/vnd.xxx+json 같은 형식을 요구 |
헤더나 구조가 정형화된 전용 응답 필요 | 응답에 반드시 특정 구조 ({status: ..., data: ...} ) 강제할 때 |
파일 또는 바이너리 처리 (비표준 방식) | 이미지, blob 등 커스텀 이진 데이터 처리 |
레거시 시스템 대응 | 오래된 시스템과 통신 시, JSON 구조가 이상한 경우 대응 필요 |