Book Image

Spring MVC Cookbook

By : Alexandre Bretet, Alex Bretet
Book Image

Spring MVC Cookbook

By: Alexandre Bretet, Alex Bretet

Overview of this book

Spring MVC is a lightweight application framework that comes with a great configuration by default. Being part of the Spring Framework, it naturally extended and supported it with an amazing set of recognizable annotations. External libraries can be plugged in and plugged out. It also possesses a request flow. Complete support of REST web services makes the Spring architecture an extremely consistent choice to support your front-end needs and Internet transformations. From the design of your Maven modules, you will achieve an Enterprise-standard for a stateless REST application based on Spring and Spring MVC with this book. This guide is unique in its style as it features a massive overview of practical development techniques brought together from the Spring ecosystem, the new JEE standards, the JavaScript revolution and Internet of Things. You will begin with the very first steps of Spring MVC's product design. Focused on deployment, viability, and maintainability, you will learn the use of Eclipse, Maven, and Git. You will walk through the separation of concerns driven by the microservices principles. Using Bootstrap and AngularJS, you will develop a responsive front-end, capable of interacting autonomously with a REST API. Later in the book, you will setup the Java Persistence API (JPA) within Spring; learn how to configure your Entities to reflect your domain needs, and discover Spring Data repositories. You will analyze how Spring MVC responds to complex HTTP requests. 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, including logging and monitoring.
Table of Contents (16 chapters)
Spring MVC Cookbook
Credits
About the Author
About the Reviewer
www.PacktPub.com
Preface
Index

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:

  1. We will define dependencies and build options for those parent projects. Let’s 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.

      Now, repeat the operation for zipcloud-parent.

    2. Open the zipcloud-parent's pom.xml file from the chapter_1 source code and click on the pom.xml tab.

    3. 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.

  2. Now, we will define dependencies and build options for web modules:

    1. Open the cloudstreetmarket-api's pom.xml from the chapter_1 source code and select the pom.xml tab.

    2. Copy and paste into your cloudstreetmarket-api's pom.xml the <build> and <dependencies> blocks.

    3. Now, repeat the operation for cloustreetmarket-webapp.

    4. Open the cloudstreetmarket-webapp's pom.xml from the chapter_1 source code directory and click on the pom.xml tab.

    5. Copy and paste into your cloudstreetmarket-webapp's pom.xml file the <build> and <dependencies> blocks.

  3. After this, we define dependencies for jar modules:

    1. Open the cloudstreetmarket-core's pom.xml from the chapter_1 source code and click on the pom.xml tab.

    2. Copy and paste into your cloudstreetmarket-core's pom.xml the entire <dependencies> block.

  4. Then, we place the web resources:

    1. 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:

    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:

  5. Now, we target a runtime for the web modules:

    1. In Eclipse, right-click on the cloudmarket-api project.

    2. Select the Properties menu.

    3. On the navigation panel, select Targeted Runtimes.

    4. On the central window, check the Server Apache Tomcat v8.0 option.

    5. 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.

  6. This step should clean your existing project warnings (if any):

    In this case, perform the following steps:

    1. Select all the projects in the project hierarchy, except the servers, as follows:

    2. Right-click somewhere in the selection and click on Update Project under Maven. The Warnings window at this stage should disappear!

  7. Let's deploy the wars and start Tomcat:

    Add the servers view in Eclipse. To do so, perform the following operations:

    1. Navigate to Window | Show view | Other.

    2. Open the Server directory and select servers. You should see the following tab created on your dashboard:

  8. To deploy the web archives, go through the following operations:

    1. Inside the view we just created, right-click on the Tomcat v8.0 Server at localhost server and select Add and Remove….

    2. In the next step, which is the Add and Remove window, select the two available archives and click on Add and then on Finish.

  9. To start the application in Tomcat, we need to complete these steps:

    1. In the Servers view, right-click on the Tomcat v8.0 Server at localhost server and click on Start.

    2. 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 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 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 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:

  • 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:

See also

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.