- Spring MVC Cookbook
- Alex Bretet
- 3205字
- 2021-07-16 13:03:19
Installing Spring, Spring MVC, and a web structure
In this recipe, we will add third-party dependencies to our pom.xml
files using inheritance. We will load Spring application contexts
and create the first controller of our application. Finally, we will deploy and start the web app in Tomcat.
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:
- We will define dependencies and build options for those parent projects. Let’s do it with the following steps:
- Open the cloudstreetmarket-parent
pom.xml
from thechapter_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.Now, repeat the operation for zipcloud-parent.
- Open the zipcloud-parent's
pom.xml
file from the chapter_1 source code and click on the pom.xml tab. - Copy and paste into your zipcloud-parent's pom.xml the
<properties>
and<dependencyManagement>
blocks. You should already have copied over the<build>
section in the third recipe.
- Open the cloudstreetmarket-parent
- Now, we will define dependencies and build options for web modules:
- Open the cloudstreetmarket-api's
pom.xml
from the chapter_1 source code and select the pom.xml tab. - Copy and paste into your cloudstreetmarket-api's
pom.xml
the<build>
and<dependencies>
blocks. - Now, repeat the operation for cloustreetmarket-webapp.
- Open the cloudstreetmarket-webapp's
pom.xml
from the chapter_1 source code directory and click on the pom.xml tab. - Copy and paste into your cloudstreetmarket-webapp's pom.xml file the
<build>
and<dependencies>
blocks.
- Open the cloudstreetmarket-api's
- After this, we define dependencies for jar modules:
- Open the cloudstreetmarket-core's
pom.xml
from the chapter_1 source code and click on the pom.xml tab. - Copy and paste into your cloudstreetmarket-core's pom.xml the entire
<dependencies>
block.
- Open the cloudstreetmarket-core's
- Then, we place the web resources:
- From the chapter_1 source code, copy and paste the entire src/main/webapp/* directory into your cloudstreetmarket-webapp project. You need to end up with the same webapp directory structure as the chapter_1 source code:
- 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:
- From the chapter_1 source code, copy and paste the entire src/main/webapp/* directory into your cloudstreetmarket-webapp project. You need to end up with the same webapp directory structure as the chapter_1 source code:
- Now, we target a runtime for the web modules:
- In Eclipse, right-click on the cloudmarket-api project.
- Select the Properties menu.
- On the navigation panel, select Targeted Runtimes.
- On the central window, check the Server Apache Tomcat v8.0 option.
- Click on OK and repeat the fifth operation on cloudstreetmarket-webapp.
Note
A few Eclipse warnings in the index.jsp files must have disappeared after this.
If you still have Warnings in the project, your Eclipse Maven configuration may be out of synchronization with the local repository.
- This step should clean your existing project warnings (if any):
In this case, perform the following steps:
- Select all the projects in the project hierarchy, except the servers, as follows:
- Right-click somewhere in the selection and click on Update Project under Maven. The Warnings window at this stage should disappear!
- Select all the projects in the project hierarchy, except the servers, as follows:
- Let's deploy the
wars
and start Tomcat:Add the servers view in Eclipse. To do so, perform the following operations:
- Navigate to Window | Show view | Other.
- Open the Server directory and select servers. You should see the following tab created on your dashboard:
- To deploy the web archives, go through the following operations:
- Inside the view we just created, right-click on the Tomcat v8.0 Server at localhost server and select Add and Remove….
- In the next step, which is the Add and Remove window, select the two available archives and click on Add and then on Finish.
- To start the application in Tomcat, we need to complete these steps:
- In the Servers view, right-click on the Tomcat v8.0 Server at localhost server and click on Start.
- In the Console view, you should have the following at the end:
INFO: Starting ProtocolHandler ["http-nio-8080"] Oct 20, 2014 11:43:44 AM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["ajp-nio-8009"] Oct 20, 2014 11:43:44 AM org.apache.catalina.startup.Cata.. start INFO: Server startup in 6898 ms
Note
If you scroll up through these logs, you shouldn't have any exceptions!
Finally, if you try to reach http://localhost:8080/portal/index.html
with your browser, you should receive the following HTML content:

Note
A static access to an HTML page remains a modest visual achievement for this chapter. All along this book, you will discover that we haven't diminished the importance of the environment and the context Spring MVC acts in.
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.
Inheritance of Maven dependencies
There are two strategies concerning the inheritance of dependencies between parent projects and children modules. They both are implemented from the parent project. On the one hand, we can choose to define these dependencies directly from the <dependencies>
node, shaping a basic inheritance in this way. On the other hand, to set up a managed inheritance, we can define the <dependencies>
node as a child node of <dependencyManagement>
. Let's have a look at the differences between the two.
Basic inheritance
With a basic inheritance, all the dependencies specified in the parent's pom.xml
file are automatically inherited into the child module with the same attributes (scope, version, packaging type, and so on) unless you override them (redefining these dependencies with the same couple groupId
/artifactId
).
On the one hand, it provides the option of using the versions of the dependencies we want in the modules we want. On the other hand, we can end up with a very complex dependencies schema and huge pom.xml
files in the children modules. Also, managing version conflicts with external transitive dependencies can be a pain.
Tip
A transitive dependency is a required dependency with the needed dependency. Transitive dependencies have been automatically imported since Maven 2.0.
There are no standards in this inheritance type for external dependencies.
Managed inheritance
With the < dependencyManagement>
mechanism, dependencies defined in the parent pom.xml
are not automatically inherited in children modules. However, the dependency attributes (scope, version, packaging type, and so on) are pulled from the parent dependency's definition, and therefore, the redefinition of these attributes is made optional.
This process drives us towards a centralized dependency definition where all the children modules use the same versions of dependencies unless a specific dependency requires a custom one.
Including third-party dependencies
Among the dependencies copied over, you might have noticed a few Spring modules, some test, web, logging, and utility dependencies.
The idea has been to start with a basic web development tool box, which is enhanced with all the Spring modules. We will visit most of the dependencies actually included when we face a particular situation.
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 ${…}.
There is a standard on defining property names using periods as word separators. More than a standard, it is a uniform notation to access both user-defined variables and attributes of objects that constitute the Maven model. The Maven model is the public interface of Maven and starts from the project level.
The POM XML Schema Definition (xsd) is generated from this Maven model. It can sound abstract but in the end, the Maven model is only a set of POJOs with getters and setters. Have a look at the JavaDoc of the Maven model from the URL below, to identify concepts, specific to pom.xml files (Build, Dependency, Plugin, and so on.):
http://maven.apache.org/ref/3.0.3/maven-model/apidocs/index.html
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 resources
If you remember, we copied/pasted the entire src/main/webapp
directory from the chapter_1
source code. The webapp
directory name is a Maven standard. The webapp
folder in Eclipse doesn't need to be tagged as a source folder for the build path, as it would create a complex and useless package hierarchy for static files. Preferably, it appears as a plain directory tree.
The webapp
directory must be seen as the document root of the application and positioned at the root level of the WAR. The public static web resources under webapp
, such as HTML files, Javascript, CSS, and image files, can be placed in the subdirectories and structure of our choice. However, as described in the Servlet 3.0 Specification, the WEB-INF
directory is a special directory within the application hierarchy. All its contents can never be reached from outside the application; its content is accessible from the servlet code calling for getResource
or getResourceAsStream
on ServletContext
. The specification also tells us that the content of a WEB-INF
directory is made up of the following:
- The
/WEB-INF/web.xml
deployment descriptor. - The
/WEB-INF/classes/
directory for servlet and utility classes. The classes in this directory must be available to the application class loader. - 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.
To load more than one spring context file easily, the trick here is to use the classpath notation (which is relative) and the star (*
) character in the resource path:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/META-INF/spring/*-config.xml</param-value> </context-param>
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 inpidually 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 behavior—you 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.
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 pergence 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:
- Excluding the lowest version from the classpath
- Not upgrading the dependency
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.
Tip
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:
- 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-to-dependency-mechanism.html
- The Sonatype ebook talks nicely about Maven properties. You can find this ebook at: https://books.sonatype.com/mvnref-book/reference/resource-filtering-sect-properties.html#resource-filtering-sect-settings-properties
- The Maven model API documentation can again be found at:
http://maven.apache.org/ref/3.0.3/maven-model/apidocs/index.html
- 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.0-fr-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
- 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/spring-framework-reference/html/overview.html
The Maven checkstyle plugin
One other interesting enough plugin which could also be highlighted here is the maven-checkstyle-plugin. When a team is growing, we sometimes need to guarantee the maintenance of certain development practices or we may need to maintain specific security-related coding practices. Like the maven-enforcer-plugin, the maven-checkstyle-plugin makes our builds assertive against this type of violation.
Find out more about this plugin, again in the Maven documentation, at: http://maven.apache.org/plugins/maven-checkstyle-plugin.
- Embedded Linux Projects Using Yocto Project Cookbook
- Learning Chef
- 零基礎學Scratch少兒編程:小學課本中的Scratch創意編程
- 跟老齊學Python:輕松入門
- C語言程序設計
- Create React App 2 Quick Start Guide
- Microsoft 365 Certified Fundamentals MS-900 Exam Guide
- C語言程序設計與應用(第2版)
- RocketMQ實戰與原理解析
- Learning Concurrency in Python
- Python GUI Programming Cookbook(Second Edition)
- Hadoop Blueprints
- Python深度學習與項目實戰
- 劍指大數據:企業級電商數據倉庫項目實戰(精華版)
- 高性能MVVM框架的設計與實現:San