Spring MVC Cookbook - Sample Chapter
Spring MVC Cookbook - Sample Chapter
ee
By designing your Maven modules, you will achieve an Enterprise-standard stateless REST application. This
guide uniquely features a massive overview of practical development techniques collated from the Spring
ecosystem. You will implement Hypermedia and HATEOAS to guide your customer's stateless conversation
with the product and see how a messaging service based on WebSocket can be configured. Finally, you will
learn how to set up and organize different levels of automated tests.
pl
e
$ 54.99 US
34.99 UK
P U B L I S H I N G
Sa
Alex Bretet
Spring MVC is a lightweight framework for web applications. Being part of the Spring Framework, it naturally
extends it to offer a consistent solution for web related issues.
P U B L I S H I N G
Alex Bretet
Preface
Welcome to the singular universe of Spring MVC Cookbook. We hope you are ready for this
journey that will take you through modern Spring web development practices. We have been
building the cloudstreetmarket.com , a stock exchange platform with social capabilities.
We are about to take you through each step of its development process.
Preface
In this chapter, you also will learn how to transfer the model from controllers to JSP views
using the JSTL and how to design a JavaScript MVC pattern with AngularJS.
Chapter 3, Working with Java Persistence and Entities, gives you a glimpse of . It is necessary
at this stage to learn how persistent data can be handled in a Spring ecosystem and thus in a
Spring MVC application. We will see how to configure, a JPA persistence provider (Hibernate)
from dataSource and entityManagerFactory in Spring. You will learn how to build a beneficial JPA
object-relational mapping from EJB3 Entities and then how to query repositories using Spring
Data JPA.
Chapter 4, Building a REST API for a Stateless Architecture, provides insights into Spring MVC
as a REST Web Services engine. We will see the amazing support the Framework provides,
with several annotations acting as doorknobs on method-handlers to abstract web-related
logic and thus only focus on the business. This principle appears with annotations for request
binding (binding of parameters, URL paths, headers, and so on) and Response Marshalling
and also for integrated support of Spring Data pagination.
This chapter also presents how to set up exception handling as part of Spring MVC to translate
predefined exception-Types into generic error responses. You will understand how to configure
the content negotiation, an important bit for REST APIs, and finally, how to expose and
document REST Endpoints using Swagger and the Swagger UI.
Chapter 5, Authenticating with Spring MVC, presents how to configure an authentication on
controllers and services from standard protocols such as HTTP BASIC and OAuth2. You will
learn several concepts and practices related to Spring Security, such as the Filters chain, the
<http> namespace, the Authentication Manager, or the management of roles and users. Our
OAuth2 flow is a client implementation. We authenticate users in our application when they
are first authenticated with a third-party provider: Yahoo! These Yahoo! authentications and
connections are later used to pull fresh financial data from Yahoo! Finance. It will be very
interesting to see how the OAuth2 flow can be entirely abstracted, in the backend, with the
Spring Social library.
Chapter 6, Implementing HATEOAS, demonstrates how to take a RESTful Spring MVC API a
step further. A Hypermedia-driven application provides links along with every single requested
resource. These links reflect URLs of related resources. They provide to the user client
(whatever type of client it may be) real-time navigation optionsprecious documentation that
is also the actual implementation.
We will see how to build such links from JPA Entities associations or from the controller layer.
Chapter 7, Developing CRUD Operations and Validations, goes into the more advanced concepts
of Spring MVC. Presenting the tools and techniques that support interactive HTTP methods
(PUT, POST, and DELETE), we will lean on the HTTP1/1 specification (RFC 7231 Semantics and
Content) to learn how to return the appropriate response status code or headers.
Our use of the Spring Validator together with the ValidationUtils utility class provides a
compliant implementation of the validation-related JSR-303 and JSR-349 specifications.
Preface
The last recipe is the place where an internationalization (I18N) of messages and content
happens. We also present a client-side implementation, with AngularJS, that relies on
published internationalization web services.
Chapter 8, Communicating Through WebSockets and STOMP, focuses on the uprising
WebSocket technology and on building Message-Oriented-Middleware for our application. This
chapter provides a rare showcase that implements so much about WebSockets in Spring. From
the use of the default embedded WebSocket message broker to a full-featured external broker
(with STOMP and AMQP protocols), we will see how to broadcast messages to multiple clients
and also how to defer the execution of time-consuming tasks with great scalability benefits.
You will learn how to dynamically create private queues and how to get authenticated clients
to post and receive messages from these private queues.
To achieve a WebSocket authentication and an authentication of messages, we will make
the API stateful. By stateful, understand that the API will use HTTP sessions to keep users
authenticated between their requests. With the support of Spring Session and the highly
clusterable Redis server, sessions will be shared across multiple web apps.
Chapter 9, Testing and Troubleshooting, introduces a set of tools and common practices to
maintain, debug, and improve an application's state. As a way of finishing this journey, we will
visit how to upgrade the database schema from one version of the application to another as
part of the Maven builds with the Flyway Maven Plugin. We will also go through how to write
and automate unit tests (with Maven Surefire and Mockito) and integration tests (using a set
of libraries such as Cargo, Rest-assured, and Maven Failsafe).
The last recipe provides insightful guidelines in order to apply Log4j2 globally as a logging
framework, as it is more than important to rely on a relevant logging solution to troubleshoot
efficiently, whichever environment we may be on.
Introduction
Before we dive into this routine for initializing the developments, we are going to answer, as an
introduction, a couple of questions that should help you understand the routine better.
Remember that the result of this chapter will also constitute the minimal starting point for all
the further chapters.
Let's do it with fun!
Throughout this book, we will be acting on behalf of the ZipCloud
company. ZipCloud aims to build different products in the social
and financial industry. We are going to build the first product of the
company: cloudstreetmarket.com which will be a wonderful
stock exchange platform with social capabilities. This project must be
an optimal beginning for this little ZipCloud start-up!
1
Choosing Maven secures these points and fulfills our project's need to make our project
reusable, secure, and testable (under automation).
Chapter 1
Getting ready
This first recipe could appear redundant or unnecessary in regard to your education or
experience. However, having a uniform configuration all along this book will provide you with
many benefits.
For instance, you will certainly avoid unidentified bugs (integration or development). You will
also experience the same interfaces as seen in the presented screenshots. Also, because
the third-party products are living, you will not have the surprise of encountering unexpected
screens or windows.
How to do it...
The whole first chapter in general requires a step by step cooperation. From the next chapter,
we will be using GIT and your active involvement will be lightened.
1. Download a distribution of the Eclipse IDE for Java EE developers:
2. Extract the downloaded archive into an eclipse directory from the steps:
on Windows
on Linux
Mac OS X
3. Select and download JDK 8:
4. Install JDK 8 on the operating system of your choice using the following instructions:
On Windows, this is a monitored installation initiated with an executable file:
1. Execute the downloaded file and wait until you reach the next installation step
2. On the installation-step window, pay attention to the destination directory
and change it to C:\java\jdk1.8.X_XX (X_XX refers to the latest current
version here. We will be using jdk1.8.0_25 in this book. Also, it won't be
necessary to install an external JRE, so uncheck the public JRE feature.)
On Linux/Mac, perform the following steps:
1. Download the tar.gz archive corresponding to your environment
2. Change the current directory to where you want to install Java. For easier
instructions, let's agree on the /usr/java directory
3. Move the downloaded tar.gz archive to this current directory
Chapter 1
4. Unpack the archive with the following command line targeting the name of
your archive: tar zxvf jdk-8u25-linux-i586.tar.gz (this example is
for a binary archive corresponding to a Linux x86 machine)
You must end up with the /usr/java/jdk1.8.0_25 directory structure that contains the
/bin, /db, /jre, /include subdirectories.
How it works
In this section we are going to provide more insights about the version of Eclipse we used and
about how we chose this specific version of JVM.
Choosing a JVM
The choice of the JVM implementation could be discussed over performance, memory
management, garbage collection, and optimization capabilities.
There are lots of different JVM implementations, including couple of open source solutions
such as OpenJDK and IcedTea (RedHat). The choice of JVM really depends on the
application's requirements. We have chosen Oracle Hotspot from experience and from
reference implementations deployed in production; this JVM implementation can be trusted
for a wide range of generic purposes. Hotspot also behaves very well if you have to run Java UI
applications. Eclipse is one of them.
Java SE 8
If you haven't already played with Scala or Clojure, it is time that you took the functional
programming train with Java! With Java SE 8, Lambda expressions reduce the amount of code
dramatically providing improved readability and maintainability. We won't implement this Java 8
feature, but since it is probably the most popular, it must be highlighted as it has given a massive
credit to the paradigm change. It is important, nowadays, to be familiar with these patterns.
Getting ready
Once the different products are installed, there are a couple of steps that we need to follow,
mainly to make Eclipse work properly with Java SE 8, Maven 3, and Tomcat 8. In this recipe,
we will also look at how to customize the Eclipse configuration file (Eclipse.ini) in order
to make the most of the platform that runs Java and to make sure that it will cope with any
significant growth of the application.
How to do it...
Let's take a look at the following steps to configure Eclipse on your desktop:
1. You can start by creating a shortcut on your desktop to point to the Eclipse
executable:
The Eclipse community recommends to specify the path to our JVM here.
Hence, depending on your system, add the following two lines at the top of
the file:
If your development machine has at least 2 GB of RAM, you can enter the
following options to make Eclipse run faster than the default settings. This
section is optional because Eclipse's default settings are already optimized
to suit most users' environment:
-vmargs
-Xms128m
6
Chapter 1
-Xmx512m
-Xverify:none
-Dosgi.requiredJavaVersion=1.6
-XX:MaxGCPauseMillis=10
-XX:MaxHeapFreeRatio=70
-XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode
-XX:+CMSIncrementalPacing
If your machine has less than 2 GB of RAM, you can still enter this set of options
without overriding the default Xms and Xmx arguments.
All the options under -vmargs are arguments that will be
passed to the JVM at startup. It is important not to mess
up the Eclipse options (the top part of the file) with the VM
arguments (the bottom part).
3. After this we will go through the following steps to start Eclipse and set the
workspace:
Launch the executable described in the Step 2.
on Windows
After completing these steps, you should end up with the following configuration:
5. For the User Settings field, create a settings.xml file in the .m2
directory: <home-directory>/.m2/settings.xml.
Chapter 1
6. Edit the settings.xml file and add the following block:
(You can also copy/paste it from the chapter_1/source_code/.m2
directory):
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0
http://maven.apache.org/xsd/settings-1.1.0.xsd">
<profiles>
<profile>
<id>compiler</id>
<properties>
<JAVA_HOME>C:\java\jdk1.8.0_25</JAVA_HOME>
</properties>
</profile>
</profiles>
<activeProfiles>
<activeProfile>compiler</activeProfile>
</activeProfiles>
</settings>
7.
Go back to the navigation panel and click on Maven. Follow the configuration
given in this screenshot:
Now we will install Tomcat 8 in the Eclipse IDE. For this, go through these steps:
1. Download a ZIP archive for the latest Core version of Tomcat8 from the
Tomcat website: http://tomcat.apache.org/download-80.cgi.
2. Extract the downloaded archive to the following directory:
10
Chapter 1
How it works...
We are going to review in this section the different elements and concepts that this recipe
took us through.
All lines after -vmargs are passed as arguments to the JVM; all arguments and
options for Eclipse must be specified before -vmargs (just like when you use
arguments on the command line)
This explains why we have inserted the vm option at the top
of the file.
11
Any use of -vmargs on the command line replaces all -vmargs settings in the .ini
file unless --launcher.appendVmargs is specified either in the .ini file or on the
command line
Preventing the garbage collector from pausing the application for more than 10 ms
(-XX:MaxGCPauseMillis=10)
Lowering the level from which the garbage collector starts to 30% of the occupied
memory (-XX:MaxHeapFreeRatio=70)
Imposing the garbage collector to run as a parallel thread, lowering its interference
with the application (-XX:+UseConcMarkSweepGC)
Choosing the incremental pacing mode for the garbage collector, which generates
breaks in the GC job so that the application can definitely stop freezing
(XX:+CMSIncrementalPacing)
The instantiated objects throughout the program's life cycle are stored in the Heap memory.
The suggested parameters define a JVM startup Heap space of 128 mb (-Xms) and an
overall 512 mb maximum heap space (Xmx). The heap is divided in two subspaces, which
are as follows:
f
Young generation: New objects are stored in this area. For the leading Hotspot or
OpenJDK JVMs, the young memory space is divided in two:
Eden: New objects are stored in this subdivision area. Objects with short
lives will be deallocated from here.
Survivor: This is a buffer between the young and old generation. The
survivor space is smaller than the Eden and it is also divided in two (the
FROM and TO areas). You can adjust the ratio between Eden and Survivor
objects with -XX:SurvivorRatio (here, -XX: SurvivorRatio=10
means YOUNG = 12, EDEN = 10, FROM = 1 and TO =1).
12
Chapter 1
The minimum size of the young area can be adjusted with
-XX:NewSize. The maximum size can be adjusted with
-XX:MaxNewSize.
f
Old generation: When objects in Eden or Survivor spaces are still referenced after
enough garbage collections, they are moved here. It is possible to set the Young area
size as a ratio of the Old area size with -XX:NewRatio. (That is, -XX:NewRatio=2
means HEAP = 3, YOUNG = 1 and OLD =2).
The maximum size for the new generation space -XX:MaxNewSize
must always remain smaller than half the heap space (-Xmx/2)
because the garbage collector may move all the Young space to the
Old space.
With Hotspot or OpenJDK, the permanent generation space was used to store information
related to the classes' definition (structure, fields, methods, and so on.). You may have already
encountered a PermGen space OutOfMemoryError exception when the loaded structure
becomes too big. In this situation, the solution is to increase the -XX:MaxPermSize
argument. It is no longer necessary with JDK8.
For this purpose, the Permanent Generation (PermGen) space has been replaced by a
metadata space that is not part of the heap but of the native memory. The default maximum
size of this space is unlimited. However, we can still restrict it with -XX:MetaspaceSize or
-XX:MaxMetaspaceSize.
Configuring Maven
Inside Eclipse, most of the Maven configuration comes from the m2eclipse plugin (also
called Maven integration for Eclipse). This plugin is included, by default, in Eclipse Luna. It
is then not necessary to download it manually. After the Maven configuration that we went
through, m2eclipse is also very helpful to trigger Maven operations from the IDE context and
to provide assistance to create Java Maven projects. You will learn more about m2eclipse in
the next section.
We then installed a basic settings.xml file. This file is used to configure Maven without
being bound directly to any projects. The most common uses of settings.xml are probably
profile definition and credential storage to access the repository manager(s).
13
A repository manager
A repository manager is a third-party application that manages all the required binaries and
dependencies that a developed application may need. Acting as a buffering proxy between
development environments and public repositories, a repository manager provides control
of critical parameters such as build time, availability of dependencies, visibility and access
restriction, and so on.
Famous solutions include Apache Archiva, Artifactory, Sonatype Nexus. In the context of our
application, we won't make use of a repository manager.
There's more...
f
14
Chapter 1
f
The Piotr Gabryanczyk article about the garbage collection optimization for IDEs can
be found at http://piotrga.wordpress.com/2006/12/12/intellij-andgarbage-collection
Getting ready
We will initially create two Eclipse projects: one for the application and one for the
components that ZipCloud as a company could share later on with other projects. Take a look
at the following image which presents the project components that we are going to build:
The application project cloudstreetmarket-parent will have three modules. Two of them will
be packaged as web archives (war): the main web application and the REST API. One of them
will be packaged as a jar dependency (cloudstreetmarket-core).
15
How to do it...
The following steps will help us create a Maven parent project:
1. From Eclipse, navigate to File | New | Other.
2. A New wizard opens up wherein you can select the type of project within a hierarchy.
Then, open the Maven category, select Maven Project, and click on Next.
The New Maven Project wizard opens as shown in the following screenshot:
3. Make sure to check the Create a simple project option. Click on Next.
4. Fill up the next wizard as follows:
edu.zipcloud.cloudstreetmarket as Group Id
cloudstreetmarket-parent as Artifact Id
0.0.1-SNAPSHOT as Version
pom as Packaging
The parent project must appear in the package explorer on the left-hand side of
the dashboard.
16
Chapter 1
We now have to tell m2eclipse which Java compiler version you plan to use in this
project so that it automatically adds the right JRE system library to the submodules
we are about to create. This is done through the pom.xml file.
5. Edit pom.xml file to specify the Java compiler version:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<verbose>true</verbose>
<fork>true</fork>
<executable>${JAVA_HOME}/bin/javac</executable>
<compilerVersion>1.8</compilerVersion>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<jvm>${JAVA_HOME}/bin/java</jvm>
<forkMode>once</forkMode>
</configuration>
</plugin>
</plugins>
</build>
17
3. Click on the Next button after which the next step shows up.
Enter the following entries in that new window:
Enter edu.zipcloud.cloudstreetmarket as Group Id.
Enter 0.0.1-SNAPSHOT as Version.
Select war as Packaging.
Enter CloudStreetMarket Webapp as Name.
Then click on the Finish button.
18
Chapter 1
7.
19
20
Chapter 1
Again, in the created pom.xml file, add the following block inside the <project>
node to create the underlying modules properly and to enable automatic test
execution. (You can also copy/paste this piece of code from the zipcloud-parent's
pom.xml file of the chapter_1 source code):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<verbose>true</verbose>
<fork>true</fork>
<executable>${JAVA_HOME}/bin/javac</executable>
<compilerVersion>1.8</compilerVersion>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<jvm>${JAVA_HOME}/bin/java</jvm>
<forkMode>once</forkMode>
</configuration>
</plugin>
</plugins>
</build>
Now, we are going to create one company-business core module, which will be a sub
module of the parent project we just created.
For this, navigate to File | New | Other. The selection wizard pops up. Open the
Maven category, select Maven Module, and click on Next.
1. In the New Maven Module wizard, enter the following details:
Check the Create a simple project option.
Enter zipcloud-core as Module Name.
Enter zipcloud-parent as Parent project.
21
In our study case, we will, for now, launch it using the m2eclipse modified Run
As menu: Right click on the zipcloud-parent project and click on Run As | Maven
Clean.
In the Maven console, you should now see this beautiful line
at the bottom:
[INFO] BUILD SUCCESS
Now, repeat the operation for the install build phase. You should now see the
following output in the console:
[INFO] ZipCloud Parent .......................SUCCESS [
0.313 s]
1.100 s]
22
0.313 s]
6.129 s]
Chapter 1
[INFO] CloudStreetMarket Core ................SUCCESS [
0.922 s]
7.163 s]
How it works...
In this section, we are going through quite a few concepts about Maven so that you can better
understand its standards
These lines allow Maven to use an external JDK for the compiler. It is better to have control
over which compiler Maven uses, especially when managing different environments.
Also, there were the following two lines that might look like an over configuration:
<source>1.8</source>
<target>1.8</target>
From a strict Maven point of view, these lines are optional when an external JDK is defined
with a specified compilerVersion. Initially, with these two lines, we can control which Java
version we want the default code to be compiled in. When maintaining older systems, the
existing code might still compile in a previous version of Java.
Actually, m2eclipse specifically expects these two lines in order to add JRE System
Library [JavaSE-1.8] to the build path of the jar and war modules. Now, with these
lines, Eclipse compiles these projects in the same way Maven does: in Java SE 8.
If this dependency still shows up as a different version of Java,
you may need to right-click on the module and then navigate to
Maven | Update Project.
Finally, if you open a parent project's pom.xml file, you should see the <modules> node
populated with the created submodules. This has been done automatically as well by m2eclipse.
We recommend that you keep an eye on this feature because m2eclipse doesn't always update
these <modules> nodes depending on which way you alter the project hierarchy.
24
Chapter 1
Description
This executes processes that are needed prior to the actual
project cleaning
clean
post-clean
Descriptions
This validates whether the project is correct and all necessary
information is available.
initialize
generate-sources
process-sources
This processes the source code, for example, to filter any values.
generate-resources
process-resources
compile
process-classes
generate-testsources
25
Descriptions
This processes the test source code, for example, to filter any
values.
generate-testresources
process-testresources
test-compile
This compiles the test source code into the test destination
directory.
process-testclasses
This post processes the generated files from test compilation, for
example, to perform bytecode enhancement on Java classes. For
Maven 2.0.5 and above.
test
This runs tests using a suitable unit testing framework. These tests
should not require the code to be packaged or deployed.
prepare-package
package
pre-integrationtest
integration-test
post-integrationtest
This performs the actions required after integration tests have been
executed. This may include cleaning up the environment.
verify
This runs checks to verify that the package is valid and meets the
quality criteria.
install
deploy
This copies and processes the resources into the test destination
directory.
Plugin goals
With the concept of plugins, Maven acquires a much wider dimension. Maven natively
provides built-in plugins, but external plugins can be introduced just as other dependencies
(identified by groupIds and artefactIds).
Each build phase can be attached to zero, one, or more plugin goals. A goal represents a
specific and concrete task responsible for building or handling a project in a certain manner.
Some phases have goals bound to them, by default, through native plugins.
26
Chapter 1
Built-in life cycle bindings
Now that we have seen the purpose of each phase in the presented two life cycles, we must
say that, for the default life cycle, depending upon which module packaging type we are
choosing, only some of these phases are potentially activated for goal execution.
Let's see the phases that we skipped in the default life cycle for different packaging types:
Default life cycle
Packaging type
jar/war/ejb/ejb3/rar
Activated phases
process-resources
ear
maven-plugin
generateresources
generate-resources
processresources
process-resources
compile
compile
process-test-resources
process-testresources
test-compile
test-compile
test
test
pom
package
package
package
package
install
install
install
install
deploy
deploy
deploy
deploy
In summary, calling: mvn clean install on a jar packaged-module will result in executing the
following phases: clean, process-resources, compile, process-test-resources, test-compile,
test, package, and install.
About Maven commands
When Maven is told to execute one or more phases targeting a specific project's pom.xml file,
it will execute the requested phase(s) for each of its modules.
Then, for every single requested phase, Maven will do the following:
f
Look for the packaging of the current module and identify the right life cycle binding
Execute all the phases in the hierarchy of the identified life cycle bindings, which are
located before the requested phase in the hierarchy
27
In summary, calling mvn clean install on a jar packaged module will execute the
following phases: clean, process-resources, compile, process-test-resources,
test-compile, test, package, and install.
There's more...
You may wonder why we have created these projects and modules in regard to
our application.
28
Chapter 1
Then, it is probably better to start big grained to refine later rather than thinking about
modules that may be implemented differently or even not implemented at all. In our case, we
are a start-up, and it is not silly to say that the 5 to 10 features we are going to implement can
constitute the core business of this application.
See also...
f
We also recommend that you install Code Style Formatters. Triggered from the Save
Event, we have, with these formatters, the ability to restyle our code automatically with
a uniform predefinition. Having such formatters in a team is much appreciated since it
guarantees the same rendering while comparing two files with a versioning tool.
Getting ready
Now that we have Eclipse ready and Maven configured properly, the fun can begin. We need
to specify all the necessary Spring dependencies in our pom.xml files, and we need to set up
Spring so that it loads and retrieves its context for every module.
We also need to organize and optionally expose web resources, such as JSPs, JavaScript files,
CSS files, and so on. If you've completed this configuration, we should end up with a static
welcome page provided by the Tomcat server, started without exceptions!
How to do it...
Our first set of changes relate to the parent projects:
1. We will define dependencies and build options for those parent projects. Lets do it
with the following steps:
1. Open the cloudstreetmarket-parent pom.xml from the chapter_1 source
code directory and select the pom.xml tab (underneath the main window).
Copy and paste into the cloudstreetmarket-parent's pom.xml file the
<properties>, <dependencyManagement>, and <build> blocks.
30
Chapter 1
2. Now, perform the same operation for cloudstreetmarket-api. Copy and
paste from the chapter_1 source code the entire src/main/webapp/*
branch into your cloudstreetmarket-api project. You need to end up with the
same webapp node and children as the chapter_1 source code:
If you still have Warnings in the project, your Eclipse Maven configuration may be out
of synchronization with the local repository
6. This step should clean your existing project warnings (if any):
31
Chapter 1
If you scroll up through these logs, you shouldn't have any
exceptions!
How it works...
Through this recipe, we have been moving across web resources and Maven dependencies
related to Spring, Spring MVC, and the web environment. Now, we will go through the way that
Maven dependency and plugin management are performed. We will then talk about the Spring
web application context and finally about the organization and packaging of web resources.
33
34
Chapter 1
The Spring Framework dependency model
As presented in the following diagram taken from the spring.io website, these days,
the Spring Framework is currently made of 20 modules that are grouped in different areas:
These modules have been included in the parent POMs as managed dependencies. This
will allow us, later on, to quickly cherry-pick the needed ones, narrowing down a selection
for our wars.
The Spring MVC dependency
The Spring MVC module is self-contained in the spring-webmvc jar. Spring MVC in a web
application is a fundamental element, as it handles incoming client requests and smoothly
monitors the business operations from controllers. It finally offers a number of tools and
interfaces capable of preparing responses in the format the clients expect them in.
All this workflow comes along with the spring-webmvc jar output HTML content or web services.
Spring MVC is entirely integrated in the Spring Framework, and all its components are
standard with regard to the Spring architecture choices.
Using Maven properties
In each parent pom.xml file, we have defined a <properties> block as part of the
<project> section. These properties are user-defined properties bound to a project, but we
can also define such properties within a Maven Profile option. Like variables, properties are
referenced in the POMs with their name surrounded by ${}.
35
To summarize, we can retrieve a node value defined in a POM and navigate the Maven model
hierarchy using a period-based expression language that targets the getters.
For example, ${project.name} references the current project.getName(),
${project.parent.groupId}, the current project.getParent().getGroupId(),
and so on.
Defining user properties that match an existing path of the Maven model is a way of overriding
its value. That's what we have done for project.build.sourceEncoding.
Maven also offers the possibility to reach properties defined in the settings.xml files such
as ${settings.localRepository}; but also environment variables such as ${env.
JAVA_HOME}; and Java System properties such as ${java.class.path}, ${java.
version}, ${user.home}, or ${user.name}.
The /WEB-INF/classes/ directory for servlet and utility classes. The classes in this
directory must be available to the application class loader.
36
Chapter 1
f
The /WEB-INF/lib/*.jar area for Java ARchive files. These files contain servlets,
beans, static resources, and JSPs packaged in a JAR file and other utility classes
useful to the web application. The web application class loader must be able to load
classes from any of these archive files.
It is good practice to create a jsp directory inside the WEB-INF folder so that the jsp files
cannot be directly targeted without passing through an explicitly defined controller.
JSP applications do exist, and by definition, they will not follow this practice. These type of
applications may be suited to certain needs, but they also don't specifically promote the use
of an MVC pattern nor a great separation of concerns.
To use JSPs in a web application, the feature must be enabled in web.xml with the definition
of a servlet of the org.apache.jasper.servlet.JspServlet type mapped to the JSP
files location.
The target runtime environment
We have experienced warnings in the index.jsp files. We have sorted them out by adding a
target runtime to our projects. We also saw that Tomcat comes with the Eclipse Compilator for
Java as a JAR library. To perform the JSP compilation, the tomcat8\lib directory must include
the following JAR libraries: jsp-api, servlet-api and el-api, and so on. Specifying a target
runtime for a project in Eclipse emulates and anticipates situation where the application will be
run from an external Tomcat container (setup with those libraries). This also explains why the
jsp-api and el-api dependencies are defined in the parent POMs with a provided scope.
The Spring web application context
In the web.xml files, we defined a special type of Servlet, the Spring MVC
DispatcherServlet, and we named it spring. This servlet covers the widest /*
URL pattern. We will revisit the DispatcherServlet in the next chapter.
A DispatcherServlet has its own discovery algorithm that builds up
WebApplicationContext. An optional contextConfigLocation initialization parameter
is provided that points to a dispatcher-context.xml file. This parameter overrides the
default expected filename and path (/WEB-INF/{servletName}-servlet.xml) for the
WebApplicationContext defined in the DispatcherServlet discovery logic.
With the load-on-startup attribute set to 1, as soon as the servlet container gets ready,
a new WebApplicationContext gets loaded and scoped only for the starting servlet. Now,
we don't wait for the first client request to load WebApplicationContext.
A Spring WebApplicationContext file usually defines or overrides the configuration and
beans that Spring MVC offers to the web application.
Still in the web.xml file, an org.sfw.web.context.ContextLoaderListener
listener is set up. The purpose of this listener is to start and shut down another Spring
ApplicationContext, which will be the root one following the container's life cycle.
37
Doing so allows us to load all the context files encountered in the classpath that match a
standard notation and location. This approach is appreciated for the consistency it imposes
but also for the way it targets context files in underlying jars.
The aggregation of all the matching context files creates an ApplicationContext root with
a much broader scope, and the WebApplicationContext inherits it. The beans we define
in the root context become visible to the WebApplicationContext context. We can override
them if needed. However, the DispatcherServlet context's beans are not visible to the
root context.
Plugins
Maven is, above all, a plugin's execution framework. Every task run by Maven corresponds
to a plugin. A plugin has one or more goals that are associated individually to life cycle
phases. Like the dependencies, the plugins are also identified by a groupId, an
artifactId, and a version. When Maven encounters a plugin that is not in the local
repository, it downloads it. Also, a specific version of Maven targets, by default, a number
of plugins that match the life cycle phases. These plugins are frozen on fixed versions and
therefore on a defined behavioryou need to override their definition to get a more recent
version or to alter their default behavior.
The Maven compiler plugin
The maven-compiler-plugin is a Maven core plugin. The core plugins are named as such
because their goals are triggered on Maven core phases (clean, compile, test, and so on.).
Noncore plugins relate to packaging, reporting, utilities, and so on. It is good practice to
redefine the maven-compiler-plugin to control which version of the compiler is to be used or to
trigger some external tools' actions (the m2eclipse project management tool, actually).
As its name suggests, the maven compiler plugin compiles the Java sources. For that, it
uses the javax.tools.JavaCompiler class and has two goals: compiler:compile
(triggered as part of the compile phase to compile the java/main source classes) and
compiler:testCompile (triggered as part of the test-compile phase to compile the
java/test source classes).
The Maven surefire plugin
The maven-surefire-plugin is also a Maven core plugin that has only one goal:
surefire:test. This is invoked as part of the default life cycle (the test phase) to run unit
tests defined in the application. It generates reports (*.txt or *.xml), by default, under the
${basedir}/target/surefire-reports location.
38
Chapter 1
The Maven enforcer plugin
The maven-enforcer-plugin is very useful to define environmental conditions as critical for
the project. It has two goals: enforcer:enforce (bound, by default, to the validate phase,
where it executes each defined rule once per module) and enforcer:display-info (it
displays the detected information on execution of the rules).
The most interesting standard rule is probably DependencyConvergence: it analyzes all
the used dependencies (direct and transitive) for us. In case of divergence of a version, it
highlights it and stops the build. When we face this kind of conflict, it is amazingly easy to
decide between the following:
f
We also quickly talked about the <pluginManagement> section, which was associated to
the maven-enforcer-plugin. In this case, this is because m2eclipse doesn't support this plugin.
Thus, to avoid a warning in Eclipse, it is necessary to add this section so that m2eclipse skips
the enforce goal.
The Maven war plugin
Using the maven-war-plugin, we redefined in our web POMs. We have again overridden
the default behavior of this plugin that is used to package web modules. This is definitely
necessary if you have a non-Maven standard project structure.
We may want to package our web resources in a different way that how it is organized in our
IDE. We may need, for some reason, to exclude some resources from the war packaging or we
may even want to give a name to the built war so that it can be used by the servlet container
that matches a specific context path in the application URLs (/api, /app, and so on). Filtering,
moving web resources around, and managing the generated war is the purpose of this plugin.
By default, the web resources are copied to the WAR root. To
override the default destination directory, specify the target
path *.
There's more...
This has been quite a broad overview about concepts that naturally require deeper interest:
f
About the way Maven manages its dependencies, we would suggest you to go through
the Maven documentation on this topic at:
http://maven.apache.org/guides/introduction/introduction-todependency-mechanism.html
39
The Sonatype ebook talks nicely about Maven properties. You can find this ebook
at: https://books.sonatype.com/mvnref-book/reference/resourcefiltering-sect-properties.html#resource-filtering-sectsettings-properties
Concerning the servlet 3.0 specification that we mentioned earlier, more information
can be found about the web.xml file definition and about the structure of a
WebArchive at: http://download.oracle.com/otn-pub/jcp/servlet-3.0fr-eval-oth-JSpec/servlet-3_0-final-spec.pdf
Finally, for more information about Maven plugins; we absolutely recommend you visit
the Maven listing at http://maven.apache.org/plugins
See also
f
The spring.io website from Pivotal, and especially the Spring Framework overview
page, can also refresh, or introduce a few key concepts. Follow the address:
http://docs.spring.io/spring-framework/docs/current/springframework-reference/html/overview.html
40
www.PacktPub.com
Stay Connected: