Home Application-development Mastering Spring MVC 4

Mastering Spring MVC 4

By Geoffroy Warin
books-svg-icon Book
Subscription
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
Subscription
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Setting Up a Spring Web Application in No Time
About this book

Spring MVC is the ideal tool to build modern web applications on the server side. With the arrival of Spring Boot, developers can really focus on the code and deliver great value, leveraging the rich Spring ecosystem with minimal configuration.

Spring makes it simple to create RESTful applications, interact with social services, communicate with modern databases, secure your system, and make your code modular and easy to test. It is also easy to deploy the result on different cloud providers.

Mastering Spring MVC will take you on a journey from developing your own web application to uploading it on the cloud.

You begin by generating your own Spring project using Spring Tool suite and Spring Boot.

As you develop an advanced-level interactive application that can handle file uploads as well as complex URLs, you will dive into the inner workings of Spring MVC and the principles of modern web architectures.

You will then test, secure, and optimize your Spring web application and design RESTful services that will be consumed on the frontend.

Finally, when everything is ready, you will release your application on a cloud provider and invite everyone to see.

Publication date:
September 2015
Publisher
Packt
Pages
320
ISBN
9781783982387

 

Chapter 1. Setting Up a Spring Web Application in No Time

In this chapter, we will get straight to the code and set up a web application, which we will be working on for the rest of this book.

We will leverage Spring Boot's autoconfiguration capabilities to build an application with zero boilerplate or configuration files.

I will lay out the big picture regarding how Spring Boot works and how to configure it. There are four ways to get started with Spring:

  • Using Spring Tool Suite to generate the starter code

  • Using IntelliJ IDEA 14.1, which now has good support for Spring Boot

  • Using Spring's website, http://start.Spring.io, to download a configurable zip file

  • Using the curl command line to http://start.Spring.io and achieving the same result

We will use Gradle and Java 8 throughout this book, but don't be scared. Even if you are still working with Maven and a previous version of Java, I bet you will find these technologies easy to work with.

Many official Spring tutorials have both a Gradle build and a Maven build, so you will find examples easily if you decide to stick with Maven. Spring 4 is fully compatible with Java 8, so it would be a shame not to take advantage of lambdas to simplify our code base.

I will also show you some Git commands. I think it's a good idea to keep track of your progress and commit when you are in a stable state. It will also make it easier to compare your work with the source code provided with this book.

As we will deploy our application with Heroku in Chapter 9, Deploying Your Web Application to the Cloud, I recommend that you start versioning your code with Git from the very beginning. I will give you some advice on how to get started with Git later in this chapter.

 

Getting started with Spring Tool Suite


One of the best ways to get started with Spring and discover the numerous tutorials and starter projects that the Spring community offers is to download Spring Tool Suite (STS). STS is a custom version of eclipse designed to work with various Spring projects, as well as Groovy and Gradle. Even if, like me, you have another IDE that you would rather work with, I strongly recommend that you give STS a shot because it gives you the opportunity to explore Spring's vast ecosystem in a matter of minutes with the "Getting Started" projects.

So, let's visit https://Spring.io/tools/sts/all and download the latest release of STS. Before we generate our first Spring Boot project we will need to install the Gradle support for STS. You can find a Manage IDE Extensions button on the dashboard. You will then need to download the Gradle Support software in the Language and framework tooling section.

I also recommend installing the Groovy Eclipse plugin along with the Groovy 2.4 compiler, as shown in the following screenshot. These will be needed later in this book when we set up acceptance tests with geb:

We now have two main options to get started.

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

You can also download the example code for this book at https://github.com/Mastering-Spring-MVC-4/mastering-spring-mvc4.

The first option is to navigate to File | New | Spring Starter Project, as shown in the following screenshot. This will give you the same options as http://start.Spring.io, embedded in your IDE:

You also have access to all the tutorials available on http://spring.io, selecting in File | New | Import Getting Started Content in the top bar. You will have the choice of working with either Gradle or Maven, as shown in the following screenshot:

Note

You can also check out the starter code to follow along with the tutorial, or get the complete code directly.

There is a lot of very interesting content available in the Getting Started Content and I encourage you to explore it on your own. It will demonstrate the integration of Spring with various technologies that you might be interested in.

For the moment, we will generate a web project as shown in the preceding image. It will be a Gradle application, producing a JAR file and using Java 8.

Here is the configuration we want to use:

Property

Value

Name

masterSpringMvc

Type

Gradle project

Packaging

Jar

Java version

1.8

Language

Java

Group

masterSpringMvc

Artifact

masterSpringMvc

Version

0.0.1-SNAPSHOT

Description

Be creative!

Package

masterSpringMvc

On the second screen you will be asked for the Spring Boot version you want to use and the the dependencies that should be added to the project.

At the time of writing this, the latest version of Spring boot was 1.2.5. Ensure that you always check out the latest release.

The latest snapshot version of Spring boot will also be available by the time you read this. If Spring boot 1.3 isn't released by then, you can probably give it a shot. One of its big features is the awesome devs tools. Refer to https://spring.io/blog/2015/06/17/devtools-in-spring-boot-1-3 for more details.

At the bottom the configuration window you will see a number of checkboxes representing the various boot starter libraries. These are dependencies that can be appended to your build file. They provide autoconfigurations for various Spring projects.

We are only interested in Spring MVC for the moment, so we will check only the Web checkbox.

Tip

A JAR for a web application? Some of you might find it odd to package your web application as a JAR file. While it is still possible to use WAR files for packaging, it is not always the recommended practice. By default, Spring boot will create a fat JAR, which will include all the application's dependencies and provide a convenient way to start a web server using Java -jar.

Our application will be packaged as a JAR file. If you want to create a war file, refer to http://spring.io/guides/gs/convert-jar-to-war/.

Have you clicked on Finish yet? If you have, you should get the following project structure:

We can see our main class MasterSpringMvcApplication and its test suite MasterSpringMvcApplicationTests. There are also two empty folders, static and templates, where we will put our static web assets (images, styles, and so on) and obviously our templates (jsp, freemarker, Thymeleaf). The last file is an empty application.properties file, which is the default Spring boot configuration file. It's a very handy file and we'll see how Spring boot uses it throughout this chapter.

The build.gradle file, the build file that we will detail in a moment.

If you feel ready to go, run the main method of the application. This will launch a web server for us.

To do this, go to the main method of the application and navigate to Run as | Spring Application in the toolbar either by right-clicking on the class or clicking on the green play button in the toolbar.

Doing so and navigating to http://localhost:8080 will produce an error. Don't worry, and read on.

I will show you how to generate the same project without STS, and we will come back to all these files.

 

Getting started with IntelliJ


IntelliJ IDEA is a very popular tool among Java developers. For the past few years I've been very pleased to pay Jetbrains a yearly fee for this awesome editor.

IntelliJ also has a way of creating Spring boot projects very quickly.

Go to the new project menu and select the Spring Initializr project type:

This will give us exactly the same options as STS, so refer to the previous chapter for the detailed configuration.

Tip

You will need to import the Gradle project into IntelliJ. I recommend generating the Gradle wrapper first (refer to the following Gradle build section).

If needed, you can reimport the project by opening its build.gradle file again.

 

Getting started with start.Spring.io


Go to http://start.Spring.io to get started with start.Spring.io. The system behind this remarkable Bootstrap-like website should be familiar to you! You will see the following screenshot when you go to the previously mentioned link:

Indeed, the same options available with STS can be found here. Clicking on Generate Project will download a ZIP file containing our starter project.

Getting started with the command line

For those of you who are addicted to the console, it is possible to curl http://start.Spring.io. Doing so will display instructions on how to structure your curl request.

For instance, to generate the same project as earlier, you can issue the following command:

$ curl http://start.Spring.io/starter.tgz \
-d name=masterSpringMvc  \
-d dependencies=web \
-d language=java \
-d JavaVersion=1.8 \
-d type=gradle-project \
-d packageName=masterSpringMvc \
-d packaging=jar \
-d baseDir=app | tar -xzvf -
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
Dload  Upload   Total   Spent    Left  Speed
100  1255  100  1119  100   136   1014    123  0:00:01  0:00:01 --:--:--  1015
x app/
x app/src/
x app/src/main/
x app/src/main/Java/
x app/src/main/Java/com/
x app/src/main/Java/com/geowarin/
x app/src/main/resources/
x app/src/main/resources/static/
x app/src/main/resources/templates/
x app/src/test/
x app/src/test/Java/
x app/src/test/Java/com/
x app/src/test/Java/com/geowarin/
x app/build.Gradle
x app/src/main/Java/com/geowarin/AppApplication.Java
x app/src/main/resources/application.properties
x app/src/test/Java/com/geowarin/AppApplicationTests.Java

And viola! You are now ready to get started with Spring without leaving the console, a dream come true.

Tip

You might consider creating an alias with the previous command, it will help you prototype the Spring application very quickly.

 

Let's get started


Now that our web application is ready, let's take a look at how it is written. Before going further, we can save our work with Git.

If you don't know anything about Git, I recommend the two following tutorials:

Tip

Installing Git

On windows, install Git bash, which can be found at https://msysgit.github.io. On Mac, if you use homebrew you should already have Git. Otherwise, use the command brew install git. When in doubt, check out the documentation at https://git-scm.com/book/en/v2/Getting-Started-Installing-Git.

To version our work with Git, type the following commands in a console:

$ cd app
$ git init

With IntelliJ, ignore the generated files: .idea and *.iml. With eclipse you should commit the .classpath and .settings folder. In any case you should ignore the .gradle folder and the build folder.

Create a .gitignore file containing the following text:

# IntelliJ project files
.idea
*.iml

# gradle
.gradle
build

Now, we can add all the other files to Git:

$ git add .
$ git commit -m "Generated with curl start.Spring.io"
[master (root-commit) eded363] Generated with curl start.Spring.io
4 files changed, 75 insertions(+)
create mode 100644 build.Gradle
create mode 100644 src/main/Java/com/geowarin/AppApplication.Java
create mode 100644 src/main/resources/application.properties
create mode 100644 src/test/Java/com/geowarin/AppApplicationTests.Java

The Gradle build

If you are unfamiliar with Gradle, think of it as Maven's successor, a modern build tool. Like Maven, it uses conventions such as how to structure a Java application. Our sources will still be found in src/main/java, our webapp in src/main/webapp, and so on. Not unlike Maven, you can use Gradle plugins to deal with various build tasks. However, Gradle really shines because it allows you to write your own build tasks using the Groovy DSL. The default library makes it easy to manipulate files, declare dependencies between tasks, and execute jobs incrementally.

Tip

Installing Gradle

If you're on OS X, you can install Gradle with brew by using brew install gradle command. On any *NIX system (Mac included), you can install it with gvm (http://gvmtool.net/). Alternatively, you can grab the binary distribution at https://Gradle.org/downloads.

The first good practice when creating an application with Gradle is to generate a Gradle wrapper. The Gradle wrapper is a small script that you will share along with your code to ensure that the build will use the same version of Gradle that you used to build the application.

The command to generate the wrapper is Gradle wrapper:

$ gradle wrapper
:wrapper

BUILD SUCCESSFUL

Total time: 6.699 secs

If we look at the new files created, we can see two scripts and two directories:

$ git status -s
?? .gradle/
?? gradle/
?? gradlew
?? gradlew.bat

The .gradle directory contains the Gradle binaries; you wouldn't want to commit those to your version control.

We previously ignored this file along with the build directory so that you could safely git add everything else:

$ git add .
$ git commit -m "Added Gradle wrapper"

The Gradle directory contains information on how to get the binaries. The two other files are scripts: a batch script for windows (Gradlew.bat) and a shell script for other systems.

We can also run our application with Gradle instead of executing the application from the IDE:

$ ./gradlew bootrun

Issuing this command will run an embedded tomcat server with our application in it!

The log tells us that the server is running on port 8080. Let's check it out:

I can imagine your disappointment. Our application is not ready for the grand public just yet.

That being said, the work accomplished by the two files our project is made of is rather impressive. Let's review them.

The first one is the Gradle build file, build.Gradle:

buildscript {
    ext {
        springBootVersion = '1.2.5.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 
        classpath("io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot' 
apply plugin: 'io.spring.dependency-management' 

jar {
    baseName = 'masterSpringMvc'
    version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile("org.springframework.boot:spring-boot-starter-test") 
}


eclipse {
    classpath {
         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
         containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.3'
}

What do we see here?

  • A dependency on the Spring Boot plugin distributed on Maven central.

  • Our project is a Java project. IDE project files can be generated by Gradle for IntelliJ or Eclipse.

  • The application will generate a JAR file.

  • Our project dependencies are hosted on maven central.

  • Our classpath includes spring-boot-starter-web in production and spring-boot-starter-test for testing.

  • Some additional configuration for eclipse.

  • The version of the Gradle wrapper is 2.3.

The Spring Boot Plugin will generate a fat jar that contains all the dependencies of the project. To build it, type:

./gradlew build

You will find the JAR in the directory build/libs. This directory will contain two files, the fat jar called masterSpringMvc-0.0.1-SNAPSHOT.jar and the classic JAR file that does not include any dependencies, masterSpringMvc-0.0.1-SNAPSHOT.jar.original.

Tip

Runnable jar

One of the main advantages of Spring Boot is embedding everything the application needs in one easily redistributable JAR file, including the web server. If you run java jar masterSpringMvc-0.0.1-SNAPSHOT.jar, tomcat will start on port 8080, just like it did when you developed it. This is extremely handy for deploying in production or in the cloud.

Our main dependency here is spring-boot-starter-web. Spring Boot provides a good number of starters that will automatically configure some aspects of the application for us by providing typical dependencies and Spring configuration.

For instance, spring-starter-web will include dependencies of tomcat-embedded and Spring MVC. It will also run the most commonly used Spring MVC configuration and provide a dispatcher listening on the "/" root path, error handling such as the 404 page we saw earlier, and a classical view resolver configuration.

We'll see more on this later. First, let's take a look at the next section.

Let me see the code!

Here is all the code that is needed to run the application. Everything is in a classic main function, which is a huge advantage because you can run your application in your IDE like you would for any other program. You can debug it and also benefit from some class reloading out of the box without a plugin.

This reloading will be available in the debug mode when saving your file in eclipse, or clicking on Make Project in IntelliJ. This will be possible only if the JVM is able to switch the new compile version of the class file with the new one; modifying the static variable or touching configuration files will force you to reload the application.

Our main class looks as follows:

package masterSpringMvc;

import org.Springframework.boot.SpringApplication;
import org.Springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AppApplication {

    public static void main(String[] args) {
        SpringApplication.run(AppApplication.class, args);
    }
}

Note the @SpringBootApplication annotation. If you look at the code of this annotation you will see that it actually combines three other annotations: @Configuration, @EnableAutoConfiguration, and @ComponentScan:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {

  /**
  * Exclude specific auto-configuration classes such that they will never be applied.
  */
  Class<?>[] exclude() default {};
}

The @Configuration class should be familiar to you if you've already configured a Spring application with Java code earlier. It indicates that our class will handle classical aspects of a Spring configuration: declaring beans, for instance.

The @ComponentScan class is also a classic. It will tell Spring where to look to find our Spring components (services, controllers, and so on). By default, this annotation will scan every current package and everything under it.

The novelty here is @EnableAutoConfiguration, which will instruct Spring Boot to do its magic. If you remove it, you will no longer benefit from Spring Boot's autoconfiguration.

The first step when writing an MVC application with Spring Boot is usually to add a controller to our code. Add the controller in the controller subpackage so that it is picked up by the @ComponentScan annotation:

package masterSpringMvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {

    @RequestMapping("/")
    @ResponseBody
    public String hello() {
        return "Hello, world!";
    }
}

This time, if you open your browser and visit http://localhost:8080 you will see this lovely Hello, world! output:

 

Spring Boot behind the curtains


If you already set up a Spring MVC application earlier, you may be used to writing at least a small portion of XML or a handful of Java annotation configuration classes.

Initialization steps are typically as follows:

  1. Initializing the DispatcherServlet of Spring MVC.

  2. Setting up an encoding filter to ensure that client requests are encoded correctly.

  3. Setting up a view resolver to tell Spring where to find our views and in which dialect they are written (jsp, Thymeleaf templates, and so on).

  4. Configuring static resources locations (css, js).

  5. Configuring supported locales and resource bundles.

  6. Configuring a multipart resolver for file uploads to work.

  7. Including tomcat or jetty to run our application on a web server.

  8. Setting up the error pages (For example 404).

However, Spring Boot handles all that work for us. Because this configuration is typically up to your application, you can come up with an unlimited amount of combinations.

Spring boot, in a way, is an opinionated Spring project configurator. It is based on conventions and will enforce them on your project by default.

The dispatcher and multipart configuration

Let's see what happens behind the curtains.

We will use the default Spring Boot configuration file that was created for us and put it in the debug mode. Add the following line to src/main/resources/application.properties:

debug=true

Now, if we launch our application again we'll see Spring Boot's autoconfiguration report. It is divided into two parts: positive matches, which list all autoconfigurations that are used by our application; and negative matches, which are Spring Boot autoconfigurations whose requirements weren't met when the application started:

=========================
AUTO-CONFIGURATION REPORT
=========================


Positive matches:
-----------------

  DispatcherServletAutoConfiguration
      - @ConditionalOnClass classes found: org.Springframework.web.servlet.DispatcherServlet (OnClassCondition)
      - found web application StandardServletEnvironment (OnWebApplicationCondition)

  EmbeddedServletContainerAutoConfiguration
      - found web application StandardServletEnvironment (OnWebApplicationCondition)

  ErrorMvcAutoConfiguration
      - @ConditionalOnClass classes found: javax.servlet.Servlet,org.springframework.web.servlet.DispatcherServlet (OnClassCondition)
      - found web application StandardServletEnvironment (OnWebApplicationCondition)

  HttpEncodingAutoConfiguration
      - @ConditionalOnClass classes found: org.springframework.web.filter.CharacterEncodingFilter (OnClassCondition)
      - matched (OnPropertyCondition)


<Input trimmed>

Let's take a closer look at DispatcherServletAutoConfiguration:

/**
* {@link EnableAutoConfiguration Auto-configuration} for the Spring
* {@link DispatcherServlet}. Should work for a standalone application where an embedded
* servlet container is already present and also for a deployable application using
* {@link SpringBootServletInitializer}.
*
* @author Phillip Webb
* @author Dave Syer
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

    /*
    * The bean name for a DispatcherServlet that will be mapped to the root URL "/"
    */
    public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";

    /*
    * The bean name for a ServletRegistrationBean for the DispatcherServlet "/"
    */
    public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";

    @Configuration
    @Conditional(DefaultDispatcherServletCondition.class)
    @ConditionalOnClass(ServletRegistration.class)
    protected static class DispatcherServletConfiguration {

        @Autowired
        private ServerProperties server;

        @Autowired(required = false)
        private MultipartConfigElement multipartConfig;

        @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
        public ServletRegistrationBean dispatcherServletRegistration() {
            ServletRegistrationBean registration = new ServletRegistrationBean(
                    dispatcherServlet(), this.server.getServletMapping());
            registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
            if (this.multipartConfig != null) {
                registration.setMultipartConfig(this.multipartConfig);
            }
            return registration;
        }

        @Bean
        @ConditionalOnBean(MultipartResolver.class)
        @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
        public MultipartResolver multipartResolver(MultipartResolver resolver) {
            // Detect if the user has created a MultipartResolver but named it incorrectly
            return resolver;
        }

    }

    @Order(Ordered.LOWEST_PRECEDENCE - 10)
    private static class DefaultDispatcherServletCondition extends SpringBootCondition {

        @Override
        public ConditionOutcome getMatchOutcome(ConditionContext context,
                AnnotatedTypeMetadata metadata) {
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            ConditionOutcome outcome = checkServlets(beanFactory);
            if (!outcome.isMatch()) {
                return outcome;
            }
            return checkServletRegistrations(beanFactory);
        }

    }
}

This is a typical Spring Boot configuration class:

  • It is annotated with @Configuration like any other Spring configuration class.

  • It typically declares its priority level with the @Order annotation. You can see that DispatcherServletAutoConfiguration needs to be configured first.

  • It can also contain hints such as @AutoConfigureAfter or @AutoConfigureBefore to further refine the order in which configurations are processed.

  • It is enabled under certain conditions. With @ConditionalOnClass(DispatcherServlet.class), this particular configuration ensures that our classpath contains DispatcherServlet, which is a good indication that Spring MVC is in the classpath and the user certainly wants to bootstrap it.

This file also contains classic bean declarations for the Spring MVC dispatcher servlet and a multipart resolver. The whole Spring MVC configuration is broken into multiple files.

It is also worth noting that these beans obey certain rules to check whether are active. The ServletRegistrationBean function will be enabled under the @Conditional(DefaultDispatcherServletCondition.class) condition, which is a bit complex but checks whether you already have a dispatcher servlet registered in your own configuration.

The MultipartResolver function will become active only if the condition @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) is met, for example, if we didn't declare it ourselves.

This means Spring boot only gives you a hand in configuring your application according to common use cases. However, at any point, you can override these defaults and declare your own configuration.

So, the DispatcherServletAutoConfiguration class explains why we have a dispatcher servlet and a multipart resolver.

The view resolver, static resources, and locale configuration

Another very relevant piece of configuration is WebMvcAutoConfiguration. It declares the view resolver, the locale resolver, and the location of our static resources. The view resolver is as follows:

@Configuration
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {

  @Value("${spring.view.prefix:}")
  private String prefix = "";

  @Value("${spring.view.suffix:}")
  private String suffix = "";

  @Bean
  @ConditionalOnMissingBean(InternalResourceViewResolver.class)
  public InternalResourceViewResolver defaultViewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix(this.prefix);
    resolver.setSuffix(this.suffix);
    return resolver;
  }
}

The view resolver configuration is really typical. What's really interesting here is the use of configuration properties to allow users to customize it.

What it says is "I will look for two variables in the user's application.properties called spring.view.prefix and spring.view.suffix". This is a very handy way to set up the view resolver with only two lines in our configuration.

Keep this in mind for the next chapter. For now, we will just stroll through Spring Boot's code.

Regarding static resources, this configuration includes the following lines:

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
    "classpath:/META-INF/resources/", "classpath:/resources/",
    "classpath:/static/", "classpath:/public/" };

private static final String[] RESOURCE_LOCATIONS;
static {
  RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length
      + SERVLET_RESOURCE_LOCATIONS.length];
  System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,
      SERVLET_RESOURCE_LOCATIONS.length);
  System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,
      SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
  if (!this.resourceProperties.isAddMappings()) {
    logger.debug("Default resource handling disabled");
    return;
  }

  Integer cachePeriod = this.resourceProperties.getCachePeriod();
  if (!registry.hasMappingForPattern("/webjars/**")) {
    registry.addResourceHandler("/webjars/**")
        .addResourceLocations("classpath:/META-INF/resources/webjars/")
        .setCachePeriod(cachePeriod);
  }
  if (!registry.hasMappingForPattern("/**")) {
    registry.addResourceHandler("/**")
        .addResourceLocations(RESOURCE_LOCATIONS)
        .setCachePeriod(cachePeriod);
  }
}

The declaration of resource locations is a bit convoluted but we can still understand two things:

  • Any resource accessed with the "webjar" prefix will be resolved inside the classpath inside the classpath. This will allow us to use prepackaged JavaScript dependencies from Maven central.

  • Our static resources can reside in any of the locations after our classpath /META-INF/resources/, /resources/, /static/, or /public/.

Tip

WebJars are JAR packages of client JavaScript libraries available on Maven central. They include a Maven project file, which allows for transitive dependencies and works in all JVM-based applications. WebJars are an alternative to JavaScript package managers such as bower or npm. They are great for applications that require just a few JavaScript libraries. Find the list of available WebJars on www.webjars.org.

There is also a part of this file that is dedicated to locale management:

@Bean
@ConditionalOnMissingBean(LocaleResolver.class)
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
  return new FixedLocaleResolver(
      StringUtils.parseLocaleString(this.mvcProperties.getLocale()));
}

This default locale resolver handles only one locale and allows us to define it via the spring.mvc.locale configuration property.

 

Error and encoding configuration


Remember when we first launched our application without adding a controller? We got a funny Whitelabel Error Page output.

Error handling is a lot trickier than it looks, especially when you don't have a web.xml configuration file and want your application to be portable across web servers. The good news is that Spring Boot takes care of that for us! Let's look at ErrorMvcAutoConfiguration:

ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@ConditionalOnWebApplication
// Ensure this loads before the main WebMvcAutoConfiguration so that the error View is
// available
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@Configuration
public class ErrorMvcAutoConfiguration implements EmbeddedServletContainerCustomizer,
        Ordered {

    @Value("${error.path:/error}")
    private String errorPath = "/error";

    @Autowired
    private ServerProperties properties;

    @Override
    public int getOrder() {
        return 0;
    }

    @Bean
    @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
    public DefaultErrorAttributes errorAttributes() {
        return new DefaultErrorAttributes();
    }

    @Bean
    @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
    public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
        return new BasicErrorController(errorAttributes);
    }

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        container.addErrorPages(new ErrorPage(this.properties.getServletPrefix()
                + this.errorPath));
    }

    @Configuration
    @ConditionalOnProperty(prefix = "error.whitelabel", name = "enabled", matchIfMissing = true)
    @Conditional(ErrorTemplateMissingCondition.class)
    protected static class WhitelabelErrorViewConfiguration {

        private final SpelView defaultErrorView = new SpelView(
                "<html><body><h1>Whitelabel Error Page</h1>"
                        + "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>"
                        + "<div id='created'>${timestamp}</div>"
                        + "<div>There was an unexpected error (type=${error}, status=${status}).</div>"
                        + "<div>${message}</div></body></html>");

        @Bean(name = "error")
        @ConditionalOnMissingBean(name = "error")
        public View defaultErrorView() {
            return this.defaultErrorView;
        }

        // If the user adds @EnableWebMvc then the bean name view resolver from
        // WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment.
        @Bean
        @ConditionalOnMissingBean(BeanNameViewResolver.class)
        public BeanNameViewResolver beanNameViewResolver() {
            BeanNameViewResolver resolver = new BeanNameViewResolver();
            resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
            return resolver;
        }

    }
}

What does this piece of configuration do?

  • It defines a bean, DefaultErrorAttributes, which exposes helpful error information via special attributes such as the status, error code, and associated stack trace.

  • It defines a BasicErrorController bean, which is an MVC controller in charge of displaying the error page we've seen.

  • It allows us to deactivate Spring Boot whitelabel error page by setting error.whitelable.enabled to false in our configuration file, application.properties.

  • We can also leverage our templating engine to provide our own error page. It will be named error.html, for example. This is what the condition ErrorTemplateMissingCondition checks.

We'll see how to properly handle errors later in this book.

As far as encoding is concerned, the very simple HttpEncodingAutoConfiguration function will handle it by providing Spring's CharacterEncodingFilter class. It is possible to override the default encoding ("UTF-8") with spring.http.encoding.charset and disable this configuration with spring.http.encoding.enabled.

 

Embedded Servlet container (Tomcat) configuration


By default, Spring Boot runs and packages our application using the Tomcat embedded API.

Let's look at EmbeddedServletContainerAutoConfiguration:

@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(EmbeddedServletContainerCustomizerBeanPostProcessorRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {

  /**
  * Nested configuration for if Tomcat is being used.
  */
  @Configuration
  @ConditionalOnClass({ Servlet.class, Tomcat.class })
  @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
  public static class EmbeddedTomcat {

    @Bean
    public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
      return new TomcatEmbeddedServletContainerFactory();
    }

  }

  /**
  * Nested configuration if Jetty is being used.
  */
  @Configuration
  @ConditionalOnClass({ Servlet.class, Server.class, Loader.class })
  @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
  public static class EmbeddedJetty {

    @Bean
    public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
      return new JettyEmbeddedServletContainerFactory();
    }

  }

  /**
  * Nested configuration if Undertow is being used.
  */
  @Configuration
  @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
  @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
  public static class EmbeddedUndertow {

    @Bean
    public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
      return new UndertowEmbeddedServletContainerFactory();
    }

  }
}

The preceding code is pretty straight forward. This code includes three different configurations, which will be activated depending on what's available on your classpath.

You can use Tomcat, tc-server, Jetty, or Undertow with Spring Boot. Your server can be easily replaced by excluding the spring-boot-starter-tomcat JAR dependency and replacing it with its Jetty or Undertow equivalent. Please refer to the documentation if you wish to do so.

All the configuration of our Servlet container (Tomcat) will happen in TomcatEmbeddedServletContainerFactory. While you should definitely read it because it provides a very advanced configuration of tomcat embedded (for which finding documentation can be hard), we will not look at this class directly.

Instead, I will walk you through the different options available to configure your Servlet Container.

The HTTP port

You can change the default HTTP port by defining a server.port property in your application.properties file or by defining an environment variable called SERVER_PORT.

You can disable HTTP by setting this variable to -1 or launch it on a random port by setting it to 0. This is very handy for testing.

The SSL configuration

Configuring SSL is such a chore, but spring boot has a simple solution. You need only a handful of properties to secure your server:

server.port = 8443
server.ssl.key-store = classpath:keystore.jks
server.ssl.key-store-password = secret
server.ssl.key-password = another-secret

You will have to generate a keystore file for the above example to work, thought.

We'll have a deeper look at our security options in Chapter 6, Securing Your Application. Of course, you can customize the TomcatEmbeddedServletContainerFactory function further by adding your own EmbeddedServletContainerFactory. This can come in handy if you wish to add multiple connectors, for instance. Refer to the documentation at http://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html#howto-configure-ssl for more information.

Other configurations

You can add classic Java web elements such as Servlet, Filter, and ServletContextListener by simply declaring them as the @Bean elements in your configuration.

Out of the box, spring boot also added three other things for us:

  • JSON serialization with Jackson in JacksonAutoConfiguration

  • Default HttpMessageConverters in `HttpMessageConvertersAutoConfiguration

  • JMX capabilities in JmxAutoConfiguration

We will see a bit more about the jackson configuration in Chapter 5, Crafting a RESTful Application. About JMX configuration, you can try it out by connecting to your application with jconsole locally:

You can add more interesting MBeans by adding org.springframework.boot:spring-boot-starter-actuator to your classpath. You can even define your own MBeans and expose them on HTTP using Jolokia. On the other hand, you can also disable those endpoints by adding spring.jmx.enabled=false to your configuration.

 

Summary


We now have a very humble spring web application with a RESTful JSON "Hello world" despite having configured nothing ourselves. We have seen what spring boot does for us, how it does it, and hopefully we've got a good idea of how to override the default autoconfiguration.

Detailing how spring boot works is the topic of a book all by itself. If you want to dig deeper, I recommend that you read the excellent book Learning Spring Boot by Greg Turnquist in the same collection.

We are now ready for the next chapter where our application will reach a new stage by actually serving web pages, and you will learn more about spring MVC's philosophy.

About the Author
  • Geoffroy Warin

    Geoffroy Warin has been programming since he was 10. A firm believer in the Software Craftsmanship movement and open source initiatives, he is a developer by choice and conviction. He has been working on the conception of enterprise-level web applications in Java and JavaScript throughout the course of his career.

    At ease with both the backend and frontend, Geoffroy has a strong focus on Clean Code and testability. He believes that developers should strive for readable code that delivers constant value to their customers.

    Pair programming and mentorship are his primary tools to promote a test-driven development approach and create great software designs.

    He also teaches courses on Java web stacks and is a Groovy and Spring enthusiast.

    Lately, he has been part of the reviewing team for Learning Spring Boot and Spring Boot Cookbook, both by Packt Publishing, which cover the latest major additions to the Spring ecosystem.

    Check out his blog at http://geowarin.github.io and his Twitter account at https://twitter.com/geowarin for fresh Spring and JavaScript programming tips.

    Browse publications by this author
Latest Reviews (4 reviews total)
Mastering Spring MVC 4
Unlock this book and the full library FREE for 7 days
Start now