24. Developing web applications

Spring Boot is well suited for web application development. You can easily create a self-contained HTTP server using embedded Tomcat or Jetty. Most web applications will use the spring-boot-starter-web module to get up and running quickly.

If you haven’t yet developed a Spring Boot web application you can follow the "Hello World!" example in the Getting started section.

24.1 The ‘Spring Web MVC framework’

The Spring Web MVC framework (often referred to as simply ‘Spring MVC’) is a rich ‘model view controller’ web framework. Spring MVC lets you create special @Controller or @RestController beans to handle incoming HTTP requests. Methods in your controller are mapped to HTTP using @RequestMapping annotations.

Here is a typical example @RestController to serve JSON data:

@RestController
@RequestMapping(value="/users")
public class MyRestController {

    @RequestMapping(value="/{user}", method=RequestMethod.GET)
    public User getUser(@PathVariable Long user) {
        // ...
    }

    @RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
    List<Customer> getUserCustomers(@PathVariable Long user) {
        // ...
    }

    @RequestMapping(value="/{user}", method=RequestMethod.DELETE)
    public User deleteUser(@PathVariable Long user) {
        // ...
    }

}

Spring MVC is part of the core Spring Framework and detailed information is available in the reference documentation. There are also several guides available at spring.io/guides that cover Spring MVC.

24.1.1 Spring MVC auto-configuration

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
  • Support for serving static resources, including support for WebJars (see below).
  • Automatic registration of Converter, GenericConverter, Formatter beans.
  • Support for HttpMessageConverters (see below).
  • Automatic registration of MessageCodeResolver (see below)
  • Static index.html support.
  • Custom Favicon support.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc. If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Bean of type WebMvcConfigurerAdapter, but without @EnableWebMvc.

24.1.2 HttpMessageConverters

Spring MVC uses the HttpMessageConverter interface to convert HTTP requests and responses. Sensible defaults are included out of the box, for example Objects can be automatically converted to JSON (using the Jackson library) or XML (using JAXB).

If you need to add or customize converters you can use Spring Boot’s HttpMessageConverters class:

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

    @Bean
    public HttpMessageConverters customConverters() {
        HttpMessageConverter<?> additional = ...
        HttpMessageConverter<?> another = ...
        return new HttpMessageConverters(additional, another);
    }

}

24.1.3 MessageCodesResolver

Spring MVC has a strategy for generating error codes for rendering error messages from binding errors: MessageCodesResolver. Spring Boot will create one for you if you set the spring.mvc.message-codes-resolver.format property PREFIX_ERROR_CODE or POSTFIX_ERROR_CODE (see the enumeration in DefaultMessageCodesResolver.Format).

24.1.4 Static Content

By default Spring Boot will serve static content from a folder called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. It uses the ResourceHttpRequestHandler from Spring MVC so you can modify that behavior by adding your own WebMvcConfigurerAdapter and overriding the addResourceHandlers method.

In a stand-alone web application the default servlet from the container is also enabled, and acts as a fallback, serving content from the root of the ServletContext if Spring decides not to handle it. Most of the time this will not happen (unless you modify the default MVC configuration) because Spring will always be able to handle requests through the DispatcherServlet.

In addition to the ‘standard’ static resource locations above, a special case is made for Webjars content. Any resources with a path in /webjars/** will be served from jar files if they are packaged in the Webjars format.

[Tip]Tip

Do not use the src/main/webapp folder if your application will be packaged as a jar. Although this folder is a common standard, it will only work with war packaging and it will be silently ignored by most build tools if you generate a jar.

24.1.5 Template engines

As well as REST web services, you can also use Spring MVC to serve dynamic HTML content. Spring MVC supports a variety of templating technologies including Velocity, FreeMarker and JSPs. Many other templating engines also ship their own Spring MVC integrations.

Spring Boot includes auto-configuration support for the following templating engines:

When you’re using one of these templating engines with the default configuration, your templates will be picked up automatically from src/main/resources/templates.

[Tip]Tip

JSPs should be avoided if possible, there are several known limitations when using them with embedded servlet containers.

24.1.6 Error Handling

Spring Boot provides an /error mapping by default that handles all errors in a sensible way, and it is registered as a ‘global’ error page in the servlet container. For machine clients it will produce a JSON response with details of the error, the HTTP status and the exception message. For browser clients there is a ‘whitelabel’ error view that renders the same data in HTML format (to customize it just add a View that resolves to ‘error’). To replace the default behaviour completely you can implement ErrorController and register a bean definition of that type, or simply add a bean of type ErrorAttributes to use the existing mechanism but replace the contents.

If you want more specific error pages for some conditions, the embedded servlet containers support a uniform Java DSL for customizing the error handling. For example:

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
    return new MyCustomizer();
}

// ...

private static class MyCustomizer implements EmbeddedServletContainerCustomizer {

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        container.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
    }

}

You can also use regular Spring MVC features like @ExceptionHandler methods and @ControllerAdvice. The ErrorController will then pick up any unhandled exceptions.

N.B. if you register an ErrorPage with a path that will end up being handled by a Filter (e.g. as is common with some non-Spring web frameworks, like Jersey and Wicket), then the Filter has to be explicitly registered as an ERROR dispatcher, e.g.

@Bean
public FilterRegistrationBean myFilter() {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new MyFilter());
    ...
    registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
    return registration;
}

(the default FilterRegistrationBean does not include the ERROR dispatcher type).

Error Handling on WebSphere Application Server

When deployed to a servlet container, a Spring Boot uses its error page filter to forward a request with an error status to the appropriate error page. The request can only be forwarded to the correct error page if the response has not already been committed. By default, WebSphere Application Server 8.0 and later commits the response upon successful completion of a servlet’s service method. You should disable this behaviour by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false

24.2 Embedded servlet container support

Spring Boot includes support for embedded Tomcat and Jetty servers. Most developers will simply use the appropriate ‘Starter POM’ to obtain a fully configured instance. By default both Tomcat and Jetty will listen for HTTP requests on port 8080.

24.2.1 Servlets and Filters

When using an embedded servlet container you can register Servlets and Filters directly as Spring beans. This can be particularly convenient if you want to refer to a value from your application.properties during configuration.

By default, if the context contains only a single Servlet it will be mapped to /. In the case of multiple Servlet beans the bean name will be used as a path prefix. Filters will map to /*.

If convention-based mapping is not flexible enough you can use the ServletRegistrationBean and FilterRegistrationBean classes for complete control. You can also register items directly if your bean implements the ServletContextInitializer interface.

24.2.2 The EmbeddedWebApplicationContext

Under the hood Spring Boot uses a new type of ApplicationContext for embedded servlet container support. The EmbeddedWebApplicationContext is a special type of WebApplicationContext that bootstraps itself by searching for a single EmbeddedServletContainerFactory bean. Usually a TomcatEmbeddedServletContainerFactory or JettyEmbeddedServletContainerFactory will have been auto-configured.

[Note]Note

You usually won’t need to be aware of these implementation classes. Most applications will be auto-configured and the appropriate ApplicationContext and EmbeddedServletContainerFactory will be created on your behalf.

24.2.3 Customizing embedded servlet containers

Common servlet container settings can be configured using Spring Environment properties. Usually you would define the properties in your application.properties file.

Common server settings include:

  • server.port — The listen port for incoming HTTP requests.
  • server.address — The interface address to bind to.
  • server.sessionTimeout — A session timeout.

See the ServerProperties class for a complete list.

Programmatic customization

If you need to configure your embdedded servlet container programmatically you can register a Spring bean that implements the EmbeddedServletContainerCustomizer interface. EmbeddedServletContainerCustomizer provides access to the ConfigurableEmbeddedServletContainer which includes numerous customization setter methods.

import org.springframework.boot.context.embedded.*;
import org.springframework.stereotype.Component;

@Component
public class CustomizationBean implements EmbeddedServletContainerCustomizer {

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        container.setPort(9000);
    }

}

Customizing ConfigurableEmbeddedServletContainer directly

If the above customization techniques are too limited, you can register the TomcatEmbeddedServletContainerFactory or JettyEmbeddedServletContainerFactory bean yourself.

@Bean
public EmbeddedServletContainerFactory servletContainer() {
    TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
    factory.setPort(9000);
    factory.setSessionTimeout(10, TimeUnit.MINUTES);
    factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html");
    return factory;
}

Setters are provided for many configuration options. Several protected method ‘hooks’ are also provided should you need to do something more exotic. See the source code documentation for details.

24.2.4 JSP limitations

When running a Spring Boot application that uses an embedded servlet container (and is packaged as an executable archive), there are some limitations in the JSP support.

  • With Tomcat it should work if you use war packaging, i.e. an executable war will work, and will also be deployable to a standard container (not limited to, but including Tomcat). An executable jar will not work because of a hard coded file pattern in Tomcat.
  • Jetty does not currently work as an embedded container with JSPs.

There is a JSP sample so you can see how to set things up.