Skip to content

1. Introduction

The PDF of this document is available |HERE|.

The examples in this document are available |HERE|.

Here, we aim to introduce, through examples, the key concepts of Spring MVC, a Java web framework that provides a framework for developing web applications according to the MVC (Model–View–Controller) pattern. Spring MVC is a branch of the Spring ecosystem [http://projects.spring.io/spring-framework/]. We also present the Thymeleaf view engine [http://www.thymeleaf.org/].

This course is intended for readers with a solid command of the Java language. No prior knowledge of web programming is required.

Although detailed, this document is likely incomplete. Spring is a vast framework with many branches. To learn more about Spring MVC, you can consult the following resources:

This document has been written so that it can be read without a computer at hand. Therefore, many screenshots are included.

1.1. Sources

This document has two main sources:

  • [Introduction to ASP.NET MVC by Example]. Spring MVC and ASP.NET MVC are two similar frameworks, the latter having been built well after the former. In order to compare the two frameworks, I followed the same progression as in the document on ASP.NET MVC;
  • the document on ASP.NET MVC does not currently (Dec 2014) contain a case study with its solution. I have used the one from the document [AngularJS / Spring 4 Tutorial] here, which I have modified as follows:
    • The case study in [AngularJS / Spring 4 Tutorial] is that of a client/server application where the server is a web service / JSON built with Spring MVC and the client is an AngularJS client;
    • in this document, we use the same web service/JSON, but the client is a two-tier web application [jQuery client] / [web service/JSON];

In addition to these sources, I searched the Internet for answers to my questions. The website [http://stackoverflow.com/] was particularly helpful to me.

1.2. Tools Used

The following examples were tested in the following environment:

  • Windows 8.1 Pro 64-bit machine;
  • JDK 1.8;
  • Spring Tool Suite 3.6.3 IDE (see Section 9.3);
  • Chrome browser (other browsers were not used);
  • Chrome extension [Advanced Rest Client] (see section 9.6);

Note regarding JDK 1.8: One of the methods in the case study uses a method from the [java.lang] package in Java 8.

All examples are Maven projects that can be opened in Eclipse, IntelliJ IDEA, or NetBeans. In the following, the screenshots are from the Spring Tool Suite IDE, a variant of Eclipse.

1.3. The examples

The examples are available |HERE| as a downloadable ZIP file.

  

To load all projects into STS, proceed as follows:

  • In [1-3], import the Maven projects;
  • in [4], specify the examples folder;
  • In [5], select all projects in the folder;
  • in [6], confirm;
  • in [7], the imported projects;

1.4. The Role of Spring MVC in a Web Application

Let’s situate Spring MVC within the development of a web application. Most often, it will be built on a multi-tier architecture such as the following:

  • the [Web] layer is the layer in contact with the web application user. The user interacts with the web application through web pages viewed in a browser. Spring MVC is located in this layer and only in this layer;
  • the [business] layer implements the application’s business logic, such as calculating a salary or an invoice. This layer uses data from the user via the [Web] layer and from the DBMS via the [DAO] layer;
  • the [DAO] (Data Access Objects) layer, the [ORM] (Object Relational Mapper) layer, and the JDBC driver manage access to data in the DBMS. The [ORM] layer acts as a bridge between the objects handled by the [DAO] layer and the rows and columns of tables in a relational database. Here we will use the Hibernate ORM. A specification called JPA (Java Persistence API) allows us to abstract away from the specific ORM used, provided it implements these specifications. This is the case with Hibernate and other Java ORMs. We will therefore henceforth refer to the ORM layer as the JPA layer;
  • the integration of the layers is handled by the Spring framework;

Most of the examples provided below will use only a single layer, the [Web] layer:

However, this document will conclude with the construction of a multi-tier web application:

The browser will connect to a [Web1] application implemented using Spring MVC / Thymeleaf, which will retrieve its data from a [Web2] web service also implemented with Spring MVC. This second web application will access a database.

1.5. The Spring MVC Development Model

Spring MVC implements the MVC (Model–View–Controller) architectural pattern as follows:

The processing of a client request proceeds as follows:

  1. request - the requested URLs are of the form http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... The [Front Controller] uses a configuration file or Java annotations to "route" the request to the correct controller and the correct action within that controller. To do this, it uses the [Action] field of the URL. The rest of the URL [/param1/param2/...] consists of optional parameters that will be passed to the action. The C in MVC here refers to the chain [Front Controller, Controller, Action]. If no controller can handle the requested action, the web server will respond that the requested URL was not found.
  2. processing
  • The selected action can use the parameters that the [Front Controller] has passed to it. These can come from several sources:
    • the path [/param1/param2/...] of the URL,
    • the [p1=v1&p2=v2] parameters of the URL,
    • from parameters posted by the browser with its request;
  • when processing the user's request, the action may need the [business] layer [2b]. Once the client's request has been processed, it may trigger various responses. A classic example is:
    • an error page if the request could not be processed correctly
    • a confirmation page otherwise
  • The action instructs a specific view to render [3]. This view will display data known as the view model. This is the "M" in MVC. The action will create this view model [2c] and instruct a view to render [3];
  1. Response - the selected view V uses the model M constructed by the action to initialize the dynamic parts of the HTML response it must send to the client, then sends this response.

Now, let’s clarify the relationship between MVC web architecture and layered architecture. Depending on how we define the model, these two concepts may or may not be related. Let’s consider a single-layer Spring MVC web application:

If we implement the [Web] layer with Spring MVC, we will indeed have an MVC web architecture but not a multi-layer architecture. Here, the [Web] layer will handle everything: presentation, business logic, and data access. It is the actions that will perform this work.

Now, let’s consider a multi-layer web architecture:

The [Web] layer can be implemented without a framework and without following the MVC model. We then have a multi-layer architecture, but the Web layer does not implement the MVC model.

For example, in the .NET world, the [Web] layer above can be implemented with ASP.NET MVC, resulting in a layered architecture with an MVC-style [Web] layer. Once this is done, we can replace this ASP.NET MVC layer with a classic ASP.NET layer (WebForms) while keeping the rest (business logic, DAO, ORM) unchanged. We then have a layered architecture with a [Web] layer that is no longer MVC-based.

In MVC, we said that the M model was that of the V view, i.e., the set of data displayed by the V view. Another definition of the M model in MVC is given:

Many authors consider that what lies to the right of the [Web] layer forms the M model of MVC. To avoid ambiguity, we can refer to:

  • the domain model when referring to everything to the right of the [Web] layer
  • the view model when referring to the data displayed by a view V

Hereinafter, the term "M model" will refer exclusively to the model of a V view.

1.6. A First Spring MVC Project

From now on, we will be working with the Spring Tool Suite (STS) IDE, a version of Eclipse customized for Spring. The website [http://spring.io/guides] offers getting-started tutorials to explore the Spring ecosystem. We will follow one of them to learn the Maven configuration required for a Spring MVC project.

Note: Most beginners will not fully grasp the project’s details. That’s not important. These details are explained later in this document. We’ll simply follow the steps.

1.6.1. The demo project

  • In [1], we import one of the Spring guides;
  • in [2], we select the [Serving Web Content] example;
  • in [3], we select the Maven project;
  • in [4], we select the final version of the guide;
  • in [5], we confirm;
  • in [6], the imported project;

Let’s examine the project, starting with its Maven configuration.

1.6.2. Maven Configuration

The [pom.xml] file is as follows:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-serving-web-content</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>
  • lines 6–8: the Maven project properties. A [<packaging>] tag specifying the type of file produced by the Maven build is missing. In its absence, the [jar] type is used. The application is therefore a console-based executable application, not a web application, where the packaging would be [war];
  • lines 10–14: The Maven project has a parent project [spring-boot-starter-parent]. This defines most of the project’s dependencies. They may be sufficient, in which case no additional dependencies are added, or they may not be, in which case the missing dependencies are added;
  • Lines 17–20: The [spring-boot-starter-thymeleaf] artifact includes the libraries necessary for a Spring MVC project used in conjunction with a view engine called [Thymeleaf]. This artifact includes a very large number of libraries, including those for an embedded Tomcat server. The application will run on this server;

The libraries included in this configuration are numerous:

Above, we see the Tomcat server archives.

Spring Boot is a branch of the Spring ecosystem [http://projects.spring.io/spring-boot/]. This project aims to minimize the configuration required for Spring projects. To achieve this, Spring Boot performs auto-configuration based on the dependencies present in the project’s classpath. Spring Boot provides many ready-to-use dependencies. For example, the [spring-boot-starter-thymeleaf] dependency found in the previous Maven project includes all the dependencies required for a Spring MVC application using the [Thymeleaf] view engine. With these two features:

  • ready-to-use dependencies;
  • auto-configuration based on these dependencies and "reasonable" default values, you can very quickly have a working Spring MVC application. This is the case with the project studied here;

1.6.3. The Architecture of a Spring MVC Application

Spring MVC implements the MVC (Model–View–Controller) architectural pattern:

The processing of a client request proceeds as follows:

  1. request - the requested URLs are of the form http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... The [Dispatcher Servlet] is the Spring class that handles incoming URLs. It "routes" the URL to the action that should handle it. These actions are methods of specific classes called [Controllers]. The C in MVC here is the chain [Dispatcher Servlet, Controller, Action]. If no action has been configured to handle the incoming URL, the [Dispatcher Servlet] will respond that the requested URL was not found (404 NOT FOUND error);
  2. processing
  • the selected action can use the parameters that the [Dispatcher Servlet] has passed to it. These can come from several sources:
    • the path [/param1/param2/...] of the URL,
    • the URL parameters [p1=v1&p2=v2],
    • from parameters posted by the browser with its request;
  • when processing the user's request, the action may need the [business] layer [2b]. Once the client's request has been processed, it may trigger various responses. A classic example is:
    • an error page if the request could not be processed correctly
    • a confirmation page otherwise
  • the action instructs a specific view to be displayed [3]. This view will display data known as the view model. This is the M in MVC. The action will create this M model [2c] and instruct a V view to be displayed [3];
  1. response - the selected view V uses the model M constructed by the action to initialize the dynamic parts of the HTML response it must send to the client, then sends this response.

We will examine these different elements in the project under study.

1.6.4. The controller C

  

The imported application has the following controller:


package hello;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class GreetingController {

    @RequestMapping("/greeting")
    public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
        model.addAttribute("name", name);
        return "greeting";
    }

}
  • line 8: the [@Controller] annotation makes the [GreetingController] class a Spring controller, meaning that its methods are registered to handle URLs. A Spring controller is a singleton. Only a single instance is created;
  • line 11: the [@RequestMapping] annotation specifies the URL handled by the method, in this case the URL [/greeting]. We will see later that this URL can be parameterized and that it is possible to retrieve these parameters;
  • line 12: the method accepts two parameters:
    • [String name]: this parameter is initialized by a parameter named [name] in the processed request, for example [/greeting?name=alfonse]. This parameter is optional [required=false] and when it is not present, the [name] parameter will take the value 'World' [defaultValue="World"],
    • [Model model] is a view model. It is passed in empty, and it is the action’s (the greeting method’s) role to populate it. This model will be passed to the view that the action will render. It is therefore a view model;
  • line 13: the value of [name] is placed in the view model. The [Model] class behaves like a dictionary;
  • line 14: the method returns the name of the view that should display the constructed model. The exact name of the view depends on the [Thymeleaf] configuration. In the absence of such a configuration, the view displayed here will be [/templates/greeting.html], where the [templates] folder must be at the root of the project’s classpath;

Let’s examine our Eclipse project:

The [src/main/java] and [src/main/resources] folders are both folders whose contents will be added to the project’s Classpath. For [src/main/java], the compiled versions of the Java source code will be placed there. The contents of the [src/main/resources] folder are added to the Classpath without modification. We can therefore see that the [templates] folder will be in the project’s Classpath [1].

You can verify this [2-3] in the Eclipse [Navigator] window [Window / Show view / Other / General / Navigator]. The [target] folder is created by compiling (or "building") the project. The [classes] folder represents the root of the Classpath. You can see that the [templates] folder is present there.

1.6.5. The View V

In MVC, we have just seen the controller C and the model M. The view V is represented here by the following [greeting.html] file:


<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
  • line 2: the Thymeleaf tag namespace;
  • line 8: a <p> tag (paragraph) with a Thymeleaf attribute. The [th:text] attribute sets the content of the paragraph. Inside the string, we have the expression [${name}]. This means we want the value of the [name] attribute from the view template. Now, recall that this attribute was added to the model by the action:

model.addAttribute("name", name);

The first parameter sets the attribute’s name, and the second sets its value.

1.6.6. Execution

  

The [Application.java] class is the project’s executable class. Its code is as follows:


package hello;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
@EnableAutoConfiguration
public class Application {

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

}
  • Line 11: The class is executable with a [main] method specific to console applications. The [SpringApplication] class on line 12 will start the Tomcat server present in the dependencies and deploy the web service on it;
  • line 4: we can see that the [SpringApplication] class belongs to the [Spring Boot] project;
  • line 12: the first parameter is the class that configures the project, the second contains any additional parameters;
  • line 8: the [@EnableAutoConfiguration] annotation instructs Spring Boot to configure the project;
  • line 7: the [@ComponentScan] annotation causes the directory containing the [Application] class to be scanned for Spring components. One will be found: the [GreetingController] class, which has the [@Controller] annotation, making it a Spring component;

Let’s run the project:

 

We get the following console logs:


.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-27 16:48:12.567  INFO 3908 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 3908 (started by ST in D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete)
2014-11-27 16:48:12.723  INFO 3908 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1a38c59b: startup date [Thu Nov 27 16:48:12 CET 2014]; root of context hierarchy
2014-11-27 16:48:13.813  INFO 3908 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoCon figurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-11-27 16:48:15.247  INFO 3908 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-11-27 16:48:15.574  INFO 3908 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-11-27 16:48:15.575  INFO 3908 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.56
2014-11-27 16:48:15.955  INFO 3908 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-11-27 16:48:15.955  INFO 3908 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3236 ms
2014-11-27 16:48:16.918  INFO 3908 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-11-27 16:48:16.922  INFO 3908 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-11-27 16:48:17.354  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-27 16:48:17.679  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/greeting],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String hello.GreetingController.greeting(java.lang.String,org.springframework.ui.Model)
2014-11-27 16:48:17.681  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-11-27 16:48:17.682  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-11-27 16:48:17.696  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-27 16:48:17.697  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-27 16:48:18.159  INFO 3908 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-11-27 16:48:18.491  INFO 3908 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-11-27 16:48:18.493  INFO 3908 --- [           main] hello.Application                        : Started Application in 6.833 seconds (JVM running for 8.658)
  • line 13: the Tomcat server starts on port 8080 (line 12);
  • line 17: the [DispatcherServlet] servlet is present;
  • line 20: the method [hello.GreetingController.greeting] has been discovered, along with the URL it handles [/greeting];

To test the web application, we request the URL [http://localhost:8080/greeting]:

 

It may be interesting to view the HTTP headers sent by the server. To do this, we will use the Chrome plugin called [Advanced Rest Client] (see section 9.6):

  • in [1], the requested URL;
  • in [2], the GET method is used;
  • in [3], the server indicated that it was sending a response in HTML format;
  • in [4], the HTML response;
  • in [5], we request the same URL but this time using a POST request;
  • in [7], the information is sent to the server in [urlencoded] format;
  • in [6], the name parameter with its value;
  • in [8], the browser tells the server that it is sending [urlencoded] information;
  • in [9], the HTML response from the server;

To stop the application:

1.6.7. Creating an executable archive

It is possible to create an executable archive outside of Eclipse. The necessary configuration is in the [pom.xml] file:


    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
</build>
  • Lines 7–10 define the plugin that will create the executable archive;
  • Line 2 defines the project's executable class;

Here’s how to proceed:

  • in [1]: we run a Maven goal;
  • in [2]: there are two goals: [clean] to delete the [target] folder from the Maven project, [package] to regenerate it;
  • in [3]: the generated [target] folder will be created in this folder;
  • in [4]: the target is generated;

Note: for the generation to succeed, the JVM used by STS must be a JDK [Window / Preferences / Java / Installed JREs]:

 

In the logs that appear in the console, it is important to see the [spring-boot-maven-plugin] plugin. This is the plugin that generates the executable archive.

[INFO] --- spring-boot-maven-plugin:1.1.9.RELEASE:repackage (default) @ gs-serving-web-content ---

Using a console, navigate to the generated folder:


gs-serving-web-content-complete\target>dir
 ...

 Directory: D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete
\target

11/27/2014  5:07 PM    <DIR>          .
11/27/2014  5:07 PM    <DIR>          ..
11/27/2014  5:07 PM    <DIR>          classes
11/27/2014  5:07 PM    <DIR>          generated-sources
11/27/2014  5:07 PM        13,419,551 gs-serving-web-content-0.1.0.jar
11/27/2014  5:07 PM             3,522 gs-serving-web-content-0.1.0.jar.original
11/27/2014  5:07 PM    <DIR>          maven-archiver
11/27/2014  5:07 PM    <DIR>          maven-status
  • line 12: the generated archive;

This archive is executed as follows:


gs-serving-web-content-complete\target>java -jar gs-serving-web-content-0.1.0.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-27 17:14:50.439  INFO 8172 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 8172 (D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete\target\gs-serving-web-content-0.1.0.jar started by ST in D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete\target)
2014-11-27 17:14:50.491  INFO 8172 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@12f4ec3a: startup date [Thu Nov 27 17:14:50 CET 2014]; root of context hierarchy

Note: You must first stop any web service that may have been started in Eclipse (see page 17).

Now that the web application is running, you can access it using a browser:

 

1.6.8. Deploying the application on a Tomcat server

While Spring Boot is very convenient in development mode, a production application will be deployed on a real Tomcat server. Here’s how to proceed:

Modify the [pom.xml] file as follows:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-serving-web-content</artifactId>
    <version>0.1.0</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <!-- Thymeleaf environment -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- WAR generation -->
<!--         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency> -->
    </dependencies>

    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>

Changes need to be made in two places:

  • line 9: you must specify that you are going to generate a WAR (Web Archive) file;
  • lines 24–28: you must add a dependency on the [spring-boot-starter-tomcat] artifact. This artifact includes all Tomcat classes in the project’s dependencies;
  • line 27: this artifact is [provided], meaning that the corresponding archives will not be included in the generated WAR. Instead, these archives will be located on the Tomcat server where the application will run;

In fact, if we look at the project’s current dependencies, we see that the [spring-boot-starter-tomcat] dependency is already present:

  

There is therefore no need to add it to the [pom.xml] file. We have commented it out for reference.

We also need to configure the web application. In the absence of a [web.xml] file, this is done using a class that extends [SpringBootServletInitializer]:

  

The [ApplicationInitializer] class is as follows:


package hello;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

public class ApplicationInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

}
  • line 6: the [ApplicationInitializer] class extends the [SpringBootServletInitializer] class;
  • line 9: the [configure] method is overridden (line 8);
  • line 10: the class that configures the project is provided;

To run the project, proceed as follows:

  • in [1], run the project on one of the servers registered in the Eclipse IDE;
  • in [2], select [Tomcat v8.0] above;

Once this is done, you can enter the URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] in a browser:

 

Note: Depending on the versions of [Tomcat] and [TC Server Developer], this execution may fail. This was the case with [Apache Tomcat 8.0.3 and 8.0.15], for example. In the example above, the version of Tomcat used was [8.0.9].

We now know how to generate a WAR archive. Moving forward, we will continue working with Spring Boot and its executable JAR archive.

1.7. A second Spring MVC project

1.7.1. The demo project

  • In [1], we import one of the Spring guides;
  • in [2], we select the [Rest Service] example;
  • in [3], we select the Maven project;
  • in [4], we select the final version of the guide;
  • in [5], we confirm;
  • in [6], the imported project;

Web services accessible via standard URLs that return JSON data are often called REST (REpresentational State Transfer) services. In this document, I will simply refer to the service we are going to build as a web/JSON service. A service is said to be RESTful if it follows certain rules. I have not attempted to adhere to these rules.

Let’s now examine the imported project, starting with its Maven configuration.

1.7.2. Maven Configuration

The [pom.xml] file is as follows:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-rest-service</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>
</project>
  • lines 6–8: the Maven project properties. A [<packaging>] tag specifying the type of file produced by the Maven build is missing. In its absence, the [jar] type is used. The application is therefore a console-based executable application, not a web application, in which case the packaging would be [war];
  • lines 10–14: The Maven project has a parent project [spring-boot-starter-parent]. This defines most of the project’s dependencies. They may be sufficient, in which case no additional dependencies are added, or they may not be, in which case the missing dependencies are added;
  • lines 17–20: The [spring-boot-starter-web] artifact includes the libraries necessary for a Spring MVC web service project where no views are generated. This artifact includes a very large number of libraries, including those for an embedded Tomcat server. The application will run on this server;

The libraries included in this configuration are numerous:

Above, we see the three Tomcat server archives.

1.7.3. The architecture of a Spring [web / JSON] service

Let’s review how Spring MVC implements the MVC model:

The processing of a client request proceeds as follows:

  1. request - the requested URLs are of the form http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... The [Dispatcher Servlet] is the Spring class that handles incoming URLs. It "routes" the URL to the action that must process it. These actions are methods of specific classes called [Controllers]. The C in MVC here is the chain [Dispatcher Servlet, Controller, Action]. If no action has been configured to handle the incoming URL, the [Dispatcher Servlet] will respond that the requested URL was not found (404 NOT FOUND error);
  2. processing
  • the selected action can use the parameters that the [Dispatcher Servlet] has passed to it. These can come from several sources:
    • the path [/param1/param2/...] of the URL,
    • the URL parameters [p1=v1&p2=v2],
    • from parameters posted by the browser with its request;
  • when processing the user's request, the action may need the [business] layer [2b]. Once the client's request has been processed, it may trigger various responses. A classic example is:
    • an error page if the request could not be processed correctly
    • a confirmation page otherwise
  • the action instructs a specific view to render [3]. This view will display data known as the view model. This is the M in MVC. The action will create this M model [2c] and instruct a V view to render [3];
  1. Response - the selected view V uses the model M created by the action to initialize the dynamic parts of the HTML response it must send to the client, then sends this response.

For a web service / JSON, the previous architecture is slightly modified:

  • in [4a], the model, which is a Java class, is converted into a JSON string by a JSON library;
  • in [4b], this JSON string is sent to the browser;

1.7.4. The C controller

  

The imported application has the following controller:


package hello;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}
  • Line 9: The [@RestController] annotation makes the [GreetingController] class a Spring controller, meaning its methods are registered to handle URLs. We have seen the similar [@Controller] annotation. The return type of that controller’s methods was [String], which was the name of the view to display. Here, it is different. The methods of a [@RestController] return objects that are serialized to be sent to the browser. The type of serialization performed depends on the Spring MVC configuration. Here, they will be serialized to JSON. It is the presence of a JSON library in the project dependencies that causes Spring Boot to automatically configure the project in this way;
  • line 14: the [@RequestMapping] annotation specifies the URL handled by the method, in this case the URL [/greeting];
  • line 15: we have already explained the [@RequestParam] annotation. The result returned by the method is an object of type [Greeting].
  • line 12: a long integer of atomic type. This means it supports concurrent access. Multiple threads may want to increment the [counter] variable at the same time. This will be handled properly. A thread can only read the counter’s value once the thread currently modifying it has finished its modification.

1.7.5. The M model

The M model produced by the previous method is the following [Greeting] object:

  

package hello;

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}

Converting this object to JSON will create the string {"id":n,"content":"text"}. Ultimately, the JSON string produced by the controller method will be in the following format:

{"id":2,"content":"Hello, World!"}

or

{"id":2,"content":"Hello, John!"}

1.7.6. Execution

  

The [Application.java] class is the project’s executable class. Its code is as follows:


package hello;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
@EnableAutoConfiguration
public class Application {

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

}

We have already encountered and explained this code in the previous example.

1.7.7. Running the project

Let’s run the project:

 

We get the following console logs:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-28 15:22:55.005  INFO 3152 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 3152 (started by ST in D:\data\istia-1415\spring mvc\dvp-final\gs-rest-service)
2014-11-28 15:22:55.046  INFO 3152 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@62e136d3: startup date [Fri Nov 28 15:22:55 CET 2014]; root of context hierarchy
2014-11-28 15:22:55.762  INFO 3152 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-11-28 15:22:56.567  INFO 3152 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-11-28 15:22:56.738  INFO 3152 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-11-28 15:22:56.740  INFO 3152 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.56
2014-11-28 15:22:56.869  INFO 3152 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-11-28 15:22:56.870  INFO 3152 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1827 ms
2014-11-28 15:22:57.478  INFO 3152 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-11-28 15:22:57.481  INFO 3152 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-11-28 15:22:57.685  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-28 15:22:57.879  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/greeting],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public hello.Greeting hello.GreetingController.greeting(java.lang.String)
2014-11-28 15:22:57.884  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping: Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-11-28 15:22:57.885  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-11-28 15:22:57.906  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-28 15:22:57.907  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-28 15:22:58.231  INFO 3152 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-11-28 15:22:58.318  INFO 3152 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-11-28 15:22:58.319  INFO 3152 --- [           main] hello.Application                        : Started Application in 3.788 seconds (JVM running for 4.424)
  • line 13: the Tomcat server starts on port 8080 (line 12);
  • line 17: the [DispatcherServlet] servlet is present;
  • line 20: the method [GreetingController.greeting] has been discovered;

To test the web application, we request the URL [http://localhost:8080/greeting]:

 

We receive the expected JSON string.

Note: This example did not work with Eclipse's built-in browser.

It may be helpful to view the HTTP headers sent by the server. To do this, we will use the Chrome plugin called [Advanced Rest Client] (see Appendices, section 9.6):

  • in [1], the requested URL;
  • in [2], the GET method is used;
  • in [3], the JSON response;
  • in [4], the server indicated that it was sending a response in JSON format;
  • in [5], we request the same URL but this time using a POST request;
  • in [7], the information is sent to the server in [urlencoded] format;
  • in [6], the name parameter with its value;
  • in [8], the browser tells the server that it is sending [urlencoded] data;
  • in [9], the server's JSON response;

1.7.8. Creating an executable archive

As we did for the previous project, we create an executable archive:

  • in [1]: we run a Maven target;
  • in [2]: there are two goals: [clean] to delete the [target] folder from the Maven project, [package] to regenerate it;
  • in [3]: the generated [target] folder will be located in this folder;
  • in [4]: we generate the target;

In the logs that appear in the console, it is important to see the [spring-boot-maven-plugin] plugin. This is the plugin that generates the executable archive.

[INFO] --- spring-boot-maven-plugin:1.1.0.RELEASE:repackage (default) @ gs-rest-service ---

Using a console, navigate to the generated folder:


D:\Temp\wksSTS\gs-rest-service\target>dir
 ...
06/11/2014  3:30 PM    <DIR>          classes
06/11/2014  3:30 PM    <DIR>          generated-sources
06/11/2014  3:30 PM        11,073,572 gs-rest-service-0.1.0.jar
06/11/2014  3:30 PM             3,690 gs-rest-service-0.1.0.jar.original
06/11/2014  3:30 PM    <DIR>          maven-archiver
06/11/2014  3:30 PM    <DIR>          maven-status
...
  • line 5: the generated archive;

This archive is executed as follows:


D:\Temp\wksSTS\gs-rest-service-complete\target>java -jar gs-rest-service-0.1.0.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.0.RELEASE)

2014-06-11 15:32:47.088  INFO 4972 --- [           main] hello.Application
                  : Starting Application on Gportpers3 with PID 4972 (D:\Temp\wk
sSTS\gs-rest-service-complete\target\gs-rest-service-0.1.0.jar started by ST in
D:\Temp\wksSTS\gs-rest-service-complete\target)
...

Note: You must first stop any web service that may have been launched in Eclipse (see section 1.6.6).

Now that the web application is running, you can access it using a browser:

 

1.7.9. Deploying the application on a Tomcat server

As we did for the previous project, we modify the [pom.xml] file as follows:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-rest-service</artifactId>
    <version>0.1.0</version>
    <packaging>war</packaging>

    ...
</project>
  • Line 9: You must specify that you are going to generate a WAR (Web Archive) file;

You also need to configure the web application. If there is no [web.xml] file, this is done using a class that extends [SpringBootServletInitializer]:

  

The [ApplicationInitializer] class is as follows:


package hello;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

public class ApplicationInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

}
  • line 6: the [ApplicationInitializer] class extends the [SpringBootServletInitializer] class;
  • line 9: the [configure] method is overridden (line 8);
  • line 10: the class that configures the project is provided;

To run the project, proceed as follows:

  • In [1-2], run the project on one of the servers registered in the Eclipse IDE;

Once this is done, you can request the URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] in a browser:

 

1.8. Conclusion

We have introduced two types of Spring MVC projects:

  • a project where the web application sends an HTML stream to the browser. This stream is generated by the [Thymeleaf] view engine;
  • a project where the web application sends a JSON stream to the browser;

In the first case, two Maven dependencies are required for the project:


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
</dependencies>

In the second case, the Maven dependencies are as follows:


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
</dependencies>

These configurations introduce a large number of cascading dependencies, many of which are unnecessary. For deploying the application, we will use a manual Maven configuration that includes only the dependencies necessary for the project.

We will now return to the basics of web programming by introducing two fundamental concepts:

  • the HTTP (HyperText Transfer Protocol) exchange between a browser and a web application;
  • the HTML (HyperText Markup Language) that the browser interprets to display a page it has received;