토리맘의 한글라이즈 프로젝트 logo 토리맘의 한글라이즈 프로젝트

스프링 부트 공식 레퍼런스를 한글로 번역한 문서입니다.

전체 목차는 여기에 있습니다.

목차


12.4. Spring MVC

스프링 부트에는 스프링 MVC를 포함하고 있는 스타터가 많이 있다. 몇 가지 스타터들은 스프링 MVC를 직접 가지고 있기 보단 의존성을 포함하고 있다. 이번 섹션에선 스프링 MVC와 스프링 부트에 관련해서 흔히 하는 질문들에 답해보겠다.

12.4.1. Write a JSON REST Service

스프링 부트 애플리케이션에 있는 모든 스프링 @RestController는 클래스패스에 Jackson2가 있다면 기본적으로 JSON 응답을 렌더링할 거다:

@RestController
public class MyController {

    @RequestMapping("/thing")
    public MyThing thing() {
        return new MyThing();
    }

}

MyThing을 Jackson2로 직렬화할 수만 있다면 (일반적인 POJO나 Groovy 객체라면 ok), localhost:8080/thing은 기본적으로 이 객체를 JSON으로 표현해서 응답한다. 브라우저에선 XML을 먼저 받는 accept 헤더를 보내는 경우가 있어서 간혹 XML 응답을 볼 수도 있다.

12.4.2. Write an XML REST Service

클래스패스에 Jackson XML 익스텐션이 있다면 (jackson-dataformat-xml) 이 익스텐션을 사용해 XML 응답을 렌더링할 수 있다. 앞에서 JSON 예시를 보여줬던 코드에서도 동작한다. Jackson XML 렌더러를 사용하려면 프로젝트에 아래 의존성을 추가해라:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

클래스패스에 Jackson의 XML 익스텐션은 없고 JAXB가 있다면, 다음 예제와 같이 MyThing@XmlRootElement를 추가해주면 XML로 렌더링할 수 있다:

@XmlRootElement
public class MyThing {

    private String name;

    // getters/setters ...

}

JAXB는 자바 8에서만 바로 사용 가능하다. 더 최신 버전을 사용하고 있다면 프로젝트에 아래 의존성을 추가해라:

<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
</dependency>

서버에서 JSON 대신 XML을 렌더링하도록 만들려면 Accept: text/xml 헤더를 전송해야 할 수도 있다 (아니면 브라우저를 사용하거나).

12.4.3. Customize the Jackson ObjectMapper

스프링 MVC는 (클라이언트와 서버 사이드 모두) HttpMessageConverters를 사용해서 HTTP exchange의 컨텐츠 변환을 협상한다. 클래스패스에 Jackson이 있을 때는 자동 설정된 Jackson2ObjectMapperBuilder 인스턴스가 미리 디폴트 컨버터들을 제공해줄 거다.

ObjectMapper(Jackson XML 컨버터에선 XmlMapper) 인스턴스(기본으로 만들어진다)에는 다음과 같은 프로퍼티가 커스텀되어 있다:

스프링 부트에선 이 동작을 좀 더 쉽게 커스텀할 수 있다.

ObjectMapperXmlMapper 인스턴스는 environment를 사용해 설정할 수 있다. Jackson은 처리 과정을 다양한 측면으로 커스텀할 수 있게끔 폭넓은 on/off 기능들을 제공한다. 이 기능들은 6개의 enum(Jackson에 들어있다)으로 표현하며, 이 enum 값은 environment의 프로퍼티에 매핑된다:

Enum Property Values
com.fasterxml.jackson.databind.
DeserializationFeature
spring.jackson.deserialization.<feature_name> true, false
com.fasterxml.jackson.core.
JsonGenerator.Feature
spring.jackson.generator.<feature_name> true, false
com.fasterxml.jackson.databind.
MapperFeature
spring.jackson.mapper.<feature_name> true, false
com.fasterxml.jackson.core.
JsonParser.Feature
spring.jackson.parser.<feature_name> true, false
com.fasterxml.jackson.databind.
SerializationFeature
spring.jackson.serialization.<feature_name> true, false
com.fasterxml.jackson.annotation.
JsonInclude.Include
spring.jackson.default-property-inclusion always,
non_null,
non_absent,
non_default,
non_empty

예를 들어 pretty print를 활성화하려면 spring.jackson.serialization.indent_output=true를 설정해라. 완화된 바인딩 규칙을 적용하기 때문에 indent_output처럼, enum 상수값 INDENT_OUTPUT과 대소문자가 완벽하게 일치하지 않아도 된다.

이 environment 기반 설정은 자동 설정된 Jackson2ObjectMapperBuilder 빈에 적용되며, 자동 설정된 ObjectMapper 빈 등, 이 빌더를 사용해 생성하는 모든 매퍼에 적용된다.

컨텍스트의 Jackson2ObjectMapperBuilderJackson2ObjectMapperBuilderCustomizer 빈을 하나 이상 사용해서 커스텀할 수 있다. 이 customizer 빈은 순서를 지정할 수 있으며 (부트의 자체 customizer는 order가 0으로 설정돼 있다), 순서를 잘 활용하면 부트의 커스텀 로직 전후에 별도 커스텀 로직을 실행할 수 있다.

com.fasterxml.jackson.databind.Module 타입 빈은 자동 설정된 Jackson2ObjectMapperBuilder에 자동으로 등록돼서, 이 빌더로 생성하는 모든 ObjectMapper 인스턴스에 적용된다. 이 메커니즘을 통해 애플리케이션에 새 기능을 추가할 때 전역으로 사용할 커스텀 모듈을 제공할 수 있다.

디폴트 ObjectMapper를 완전히 교체하고 싶을 때는 ObjectMapper 타입 @Bean을 정의하고 @Primary로 마킹하거나, 빌더를 통해 접근하는 게 좋다면 Jackson2ObjectMapperBuilder @Bean을 정의해라. 두 경우 모두 ObjectMapper의 자동 설정은 전부 비활성화된다.

MappingJackson2HttpMessageConverter 타입 @Bean들을 제공하면 MVC 설정에 있는 기본값이 대체된다. 간편한 HttpMessageConverters 타입 빈도 제공하고 있다 (디폴트 MVC 설정에서는 항상 사용할 수 있다). 여기에는 디폴트 메세지 컨버터와 사용자가 개선한 메세지 컨버터에 접근할 수 있는 유용한 메소드들이 들어있다.

자세한 내용은 “@ResponseBody 렌더링 커스텀하기” 섹션과 WebMvcAutoConfiguration 소스 코드를 참고해라.

12.4.4. Customize the @ResponseBody Rendering

스프링은 HttpMessageConverters를 사용해서 @ResponseBody(또는 @RestController의 응답)를 렌더링한다. 스프링 부트 컨텍스트에 빈을 적절한 타입으로 넣어주면 컨버터를 더 추가할 수 있다. 추가하는 빈이 이미 디폴트로 포함시킨 타입일 때는 (JSON 변환에선 MappingJackson2HttpMessageConverter 등) 기본값이 대체된다. 간편한 HttpMessageConverters 타입 빈을 제공하고 있으며, 디폴트 MVC 설정에선 이 타입 빈을 항상 이용할 수 있다. 여기에는 디폴트 메세지 컨버터와 사용자가 개선한 메세지 컨버터에 접근할 수 있는 유용한 메소드들이 들어있다 (예를 들어 커스텀 RestTemplate에 수동으로 주입하고 싶을 때 유용할 수 있다).

평소 MVC를 사용할 때 처럼 WebMvcConfigurer 빈들을 제공하면, 이 빈으로도 configureMessageConverters 메소드를 재정의해서 컨버터에 기여할 수 있다. 하지만 평소 MVC 때와는 달리 필요한 컨버터를 추가로만 제공할 수 있다 (스프링 부트에서도 같은 메커니즘으로 기본값을 제공하기 때문). 마지막으로 자체 @EnableWebMvc 설정을 제공해서 스프링 부트의 디폴트 MVC 설정에서 빠져나오면, WebMvcConfigurationSupport에 있는 getMessageConverters를 활용해 모든 작업을 수동으로 제어할 수 있다.

자세한 내용은 WebMvcAutoConfiguration 소스 코드를 확인해봐라.

12.4.5. Handling Multipart File Uploads

스프링 부트는 서블릿 3 javax.servlet.http.Part API를 포용해서 파일 업로드를 지원한다. 기본적으로 스프링 부트는 스프링 MVC에서 단일 요청으로 사용할 수 있는 파일 사이즈는 파일 당 최대 1MB, 전체 파일 데이터는 최대 10MB로 설정한다. 중간 데이터를 저장할 위치와 (ex. /tmp 디렉토리), 데이터를 디스크로 플러시할 임계치 등, 이런 설정들은 MultipartProperties 클래스에 정의돼 있는 프로퍼티를 통해 커스텀할 수 있다. 예를 들어 파일 사이즈에 제한을 두지 않으려면 spring.servlet.multipart.max-file-size 프로퍼티를 -1로 설정해라.

스프링의 멀티파트 지원을 이용하면 멀티파트로 인코딩한 파일을 간편하게 받을 수 있다. 스프링 MVC 컨트롤러 핸들러 메소드에 MultipartFile 타입 파라미터를 선언하고 @RequestParam 어노테이션을 달아주면 된다.

자세한 내용은 MultipartAutoConfiguration 소스 코드를 참고해라.

Apache Commons File Upload같은 별도 의존성을 도입하는 것보단, 컨테이너가 내장하고 있는 멀티파트 업로드 지원을 활용하는 걸 권장한다.

12.4.6. Switch Off the Spring MVC DispatcherServlet

기본적으로 모든 컨텐츠는 애플리케이션의 루트(/)에서 서빙한다. 다른 경로에 매핑하고 싶다면 아래와 같이 설정해주면 된다:

properties yaml
spring.mvc.servlet.path=/mypath
spring:
  mvc:
    servlet:
      path: "/mypath"

다른 서블릿도 사용한다면, 각각을 Servlet이나 ServletRegistrationBean 타입 @Bean으로 선언하면 되며, 그러면 스프링 부트가 알아서 컨테이너에 등록해줄 거다. 이렇게 서블릿이 등록되면 DispatcherServlet을 호출하지 않고 DispatcherServlet의 하위 컨텍스트에 매핑할 수 있다.

DispatcherServlet을 직접 설정하는 건 흔치 않지만, 그래도 정말 필요하다면 DispatcherServletPath 타입 @Bean도 함께 정의해서 커스텀 DispatcherServlet의 경로를 제공해야 한다.

12.4.7. Switch off the Default MVC Configuration

MVC 설정을 전부 직접 제어하려면 @EnableWebMvc 어노테이션으로 자체 @Configuration을 제공하는 게 가장 쉽다. 이렇게 하면 MVC 설정을 모두 도맡아야 한다.

12.4.8. Customize ViewResolvers

ViewResolver는 스프링의 핵심 컴포넌트로, @Controller의 뷰 이름을 실제 View 구현체로 바꿔준다. ViewResolver는 주로 REST 스타일 서비스가 아닌 UI 애플리케이션에서 사용한다는 점을 참고해라 (@ResponseBody를 렌더링할 때는 View를 사용하지 않는다). 선택할 수 있는 ViewResolver 구현체는 다양하며, 스프링 자체에선 어떤 것을 꼭 사용해야 한다같은 의견은 제시하지 않는다. 반면 스프링 부트는 클래스패스와 애플리케이션 컨텍스트에서 찾은 것들에 따라 한 두개를 미리 마련해줄 거다. DispatcherServlet은 애플리케이션 컨텍스트에서 찾은 리졸버를 모두 사용해서 결과가 나올 때까지 순서대로 리졸브해본다. 자체 구현체를 추가할 때는 리졸버가 어디에 어떤 순서로 추가되는지 알고 있어야 한다.

WebMvcAutoConfiguration에선 컨텍스트에 아래와 같은 ViewResolver들을 추가한다:

더 자세한 내용은 아래 코드를 참고해라:


전체 목차는 여기에 있습니다.

<< >>

TOP