60. Spring MVC

60.1 Write a JSON REST service

Any Spring @RestController in a Spring Boot application should render JSON response by default as long as Jackson2 is on the classpath. For example:

@RestController
public class MyController {

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

}

As long as MyThing can be serialized by Jackson2 (e.g. a normal POJO or Groovy object) then http://localhost:8080/thing will serve a JSON representation of it by default. Sometimes in a browser you might see XML responses (but by default only if MyThing was a JAXB object) because browsers tend to send accept headers that prefer XML.

60.2 Write an XML REST service

Since JAXB is in the JDK the same example as we used for JSON would work, as long as the MyThing was annotated as @XmlRootElement:

@XmlRootElement
public class MyThing {
    private String name;
    // .. getters and setters
}

To get the server to render XML instead of JSON you might have to send an Accept: text/xml header (or use a browser).

60.3 Customize the Jackson ObjectMapper

Spring MVC (client and server side) uses HttpMessageConverters to negotiate content conversion in an HTTP exchange. If Jackson is on the classpath you already get a default converter with a vanilla ObjectMapper. Spring Boot has some features to make it easier to customize this behavior.

The smallest change that might work is to just add beans of type com.fasterxml.jackson.databind.Module to your context. They will be registered with the default ObjectMapper and then injected into the default message converter. To replace the default ObjectMapper completely, define a @Bean of that type and mark it as @Primary.

In addition, if your context contains any beans of type ObjectMapper then all of the Module beans will be registered with all of the mappers. So there is a global mechanism for contributing custom modules when you add new features to your application.

Finally, if you provide any @Beans of type MappingJackson2HttpMessageConverter then they will replace the default value in the MVC configuration. Also, a convenience bean is provided of type HttpMessageConverters (always available if you use the default MVC configuration) which has some useful methods to access the default and user-enhanced message converters.

See also the Section 60.4, “Customize the @ResponseBody rendering” section and the WebMvcAutoConfiguration source code for more details.

60.4 Customize the @ResponseBody rendering

Spring uses HttpMessageConverters to render @ResponseBody (or responses from @RestController). You can contribute additional converters by simply adding beans of that type in a Spring Boot context. If a bean you add is of a type that would have been included by default anyway (like MappingJackson2HttpMessageConverter for JSON conversions) then it will replace the default value. A convenience bean is provided of type HttpMessageConverters (always available if you use the default MVC configuration) which has some useful methods to access the default and user-enhanced message converters (useful, for example if you want to manually inject them into a custom RestTemplate).

As in normal MVC usage, any WebMvcConfigurerAdapter beans that you provide can also contribute converters by overriding the configureMessageConverters method, but unlike with normal MVC, you can supply only additional converters that you need (because Spring Boot uses the same mechanism to contribute its defaults). Finally, if you opt-out of the Spring Boot default MVC configuration by providing your own @EnableWebMvc configuration, then you can take control completely and do everything manually using getMessageConverters from WebMvcConfigurationSupport.

See the WebMvcAutoConfiguration source code for more details.

60.5 Handling Multipart File Uploads

Spring Boot embraces the Servlet 3 javax.servlet.http.Part API to support uploading files. By default Spring Boot configures Spring MVC with a maximum file of 1Mb per file and a maximum of 10Mb of file data in a single request. You may override these values, as well as the location to which intermediate data is stored (e.g., to the /tmp directory) and the threshold past which data is flushed to disk by using the properties exposed in the MultipartProperties class. If you want to specify that files be unlimited, for example, set the multipart.maxFileSize property to -1.

The multipart support is helpful when you want to receive multipart encoded file data as a @RequestParam-annotated parameter of type MultipartFile in a Spring MVC controller handler method.

See the MultipartAutoConfiguration s ource for more details.

60.6 Switch off the Spring MVC DispatcherServlet

Spring Boot wants to serve all content from the root of your application / down. If you would rather map your own servlet to that URL you can do it, but of course you may lose some of the other Boot MVC features. To add your own servlet and map it to the root resource just declare a @Bean of type Servlet and give it the special bean name dispatcherServlet (You can also create a bean of a different type with that name if you want to switch it off and not replace it).

60.7 Switch off the Default MVC configuration

The easiest way to take complete control over MVC configuration is to provide your own @Configuration with the @EnableWebMvc annotation. This will leave all MVC configuration in your hands.

60.8 Customize ViewResolvers

A ViewResolver is a core component of Spring MVC, translating view names in @Controller to actual View implementations. Note that ViewResolvers are mainly used in UI applications, rather than REST-style services (a View is not used to render a @ResponseBody). There are many implementations of ViewResolver to choose from, and Spring on its own is not opinionated about which ones you should use. Spring Boot, on the other hand, installs one or two for you depending on what it finds on the classpath and in the application context. The DispatcherServlet uses all the resolvers it finds in the application context, trying each one in turn until it gets a result, so if you are adding your own you have to be aware of the order and in which position your resolver is added.

WebMvcAutoConfiguration adds the following ViewResolvers to your context:

  • An InternalResourceViewResolver with bean id “defaultViewResolver”. This one locates physical resources that can be rendered using the DefaultServlet (e.g. static resources and JSP pages if you are using those). It applies a prefix and a suffix to the view name and then looks for a physical resource with that path in the servlet context (defaults are both empty, but accessible for external configuration via spring.view.prefix and spring.view.suffix). It can be overridden by providing a bean of the same type.
  • A BeanNameViewResolver with id “beanNameViewResolver”. This is a useful member of the view resolver chain and will pick up any beans with the same name as the View being resolved. It can be overridden by providing a bean of the same type, but it’s unlikely you will need to do that.
  • A ContentNegotiatingViewResolver with id “viewResolver” is only added if there are actually beans of type View present. This is a “master” resolver, delegating to all the others and attempting to find a match to the “Accept” HTTP header sent by the client. There is a useful blog about ContentNegotiatingViewResolver that you might like to study to learn more, and also look at the source code for detail. You can switch off the auto-configured ContentNegotiatingViewResolver by defining a bean named “viewResolver”.
  • If you use Thymeleaf you will also have a ThymeleafViewResolver with id “thymeleafViewResolver”. It looks for resources by surrounding the view name with a prefix and suffix (externalized to spring.thymeleaf.prefix and spring.thymeleaf.suffix, defaults “classpath:/templates/” and “.html” respectively). It can be overridden by providing a bean of the same name.
  • If you use FreeMarker you will also have a FreeMarkerViewResolver with id “freeMarkerViewResolver”. It looks for resources in a loader path (externalized to spring.freemarker.templateLoaderPath, default “classpath:/templates/”) by surrounding the view name with a prefix and suffix (externalized to spring.freemarker.prefix and spring.freemarker.suffix, with empty and “.ftl” defaults respectively). It can be overridden by providing a bean of the same name.
  • If you use Groovy templates (actually if groovy-templates is on your classpath) you will also have a Groovy TemplateViewResolver with id “groovyTemplateViewResolver”. It looks for resources in a loader path by surrounding the view name with a prefix and suffix (externalized to spring.groovy.template.prefix and spring.groovy.template.suffix, defaults “classpath:/templates/” and “.tpl” respectively). It can be overriden by providing a bean of the same name.
  • If you use Velocity you will also have a VelocityViewResolver with id “velocityViewResolver”. It looks for resources in a loader path (externalized to spring.velocity.resourceLoaderPath, default “classpath:/templates/”) by surrounding the view name with a prefix and suffix (externalized to spring.velocity.prefix and spring.velocity.suffix, with empty and “.vm” defaults respectively). It can be overridden by providing a bean of the same name.

Check out WebMvcAutoConfiguration, ThymeleafAutoConfiguration, FreeMarkerAutoConfiguration, GroovyTemplateAutoConfiguration and VelocityAutoConfiguration