Creating a Spring MVC Maven web application with Java config from scratch

This tutorial describes how to create a simple Spring MVC web application statring from a basic Maven project. We set up the required directories and files by hand, almost nothing will be pre-generated. For configuration we use only java classes and no XML files (except for the pom.xml for Maven, of course).

Tools used:

  • Spring Tool Suite 3.7.3.RELEASE
  • Apache Maven 3.3.9
  • Java 8 (Update 60)
  • Tomcat 8.0.32

Looking for an XML configuration solution?

We have an article on that as well. You can check it out here: Creating a Spring MVC Maven web application from scratch.

Creating the Maven project

  1. In STS press Ctrl + N, this brings up the New wizard where you select what kind of project or file you would like to create. In the search box enter maven. From the filtered list select Maven Project.
  2. Click Next.
  3. Check the Create a simple project (skip archetype selection) checkbox.
  4. Click Next.
  5. Set the following properties:
    • Group Id: com.jtuts
    • Artifact Id: spring-mvc-maven-webapp-with-java-config-from-scratch
    • Packaging: war
    • Name: spring-mvc-maven-webapp-with-java-config-from-scratch
  6. Click Finish.

Of course the Group Id, Artifact Id and Name properties can be set to anything else, these are just example values. However the war value for the Packaging is mandatory, because we are creating a web application and the server which will run it (in our case Tomcat) expects a .war file.

The directory structure

STS will automatically create the basic directory structure for our application. This conforms to the basic structure that Maven expects. You can find more information about it on Maven’s Introduction to the Standard Directory Layout page.

The most important directories for us are:

  • src/main/java: Java source files.
  • src/main/resources: Other resources like property files and xml files.
  • src/main/webapp: Web application source files (e.g. JPSs, images, CSS files).
  • src/test/java: Test source files.
  • src/test/resources: Resources for tests.

By default, Maven expects you to have the above mentioned files in these directories. You can change this in Maven’s pom.xml but you should avoid it not to create confusion when other developers look at your project.

Here is what our final directory structure will look like:

directory-structure

The pom.xml

The pom.xml file is added automatically by STS when you create the Maven project. However, we made some additions that are needed for our webapp to work. This is what the final pom.xml looks like:

<?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>com.jtuts</groupId>
    <artifactId>spring-mvc-maven-webapp-with-java-config-from-scratch</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>spring-mvc-maven-webapp-with-java-config-from-scratch</name>

    <properties>

        <!-- Dependency versions -->

        <spring.version>4.2.5.RELEASE</spring.version>
        <servlet.api.version>3.1.0</servlet.api.version>

        <!-- Plugin versions -->

        <maven.compiler.plugin.version>3.5.1</maven.compiler.plugin.version>

        <!-- Misc versions -->

        <java.version>1.8</java.version>

    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.api.version}</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <finalName>spring-mvc-maven-webapp-with-java-config-from-scratch</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

In this file we include all the dependencies that are required by our example project:

  • The spring-mvc dependency will include all Spring related functionality.
  • The javax.servlet-api depencdecy contains the interfaces and classes that enables us to use servlets in our application.

The finalName will be the name of the .war file that is created.

Then, we have two plugins:

  1. The maven-compiler-plugin configures the compilation process of Maven. In this case we set that our source code must be compatible with at least Java 1.8, and we want our compiled program to be executable with Java 1.8 and above.
  2. The maven-war-plugin  is just there to set the failOnMissingWebXml property to false, because otherwise STS would report an error that we don’t have a web.xml.

Creating our application initializer class

Our application needs a point of entry where it’s startup process begins. We set up an application initializer class for this purpose. In case of Java config we don’t have a web.xml, so we need to define the application initializtion related stuff in a class. A class, that implements the WebApplicationInitializer interface, and Spring will call it’s onStartup method, when starting up the application. We create this, and further configuration classes in the com.jtuts.configuration package.

package com.jtuts.configuration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class CustomWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) throws ServletException {

        // Create the 'root' Spring application context
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(ApplicationConfiguration.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(DispatcherServletConfiguration.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));

        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }
}

In this method we do the following:

  1. First we create a root WebApplicationContext for the application. This application context will contain and manage all the beans defined. We also tell the container the manage the lifecycle of this application context.
  2. In the following lines we create a dispatcher context. Based on this context, we create a servlet called DispatcherServlet and add it to the container. The job of the DispatcherServlet is to take an incoming URL and find the right combination of handlers (generally methods on Controller classes) and views (generally JSPs) that combine to form the page or resource that’s supposed to be found at that location.
  3. Then we set the loadOnStartup value. A value of >=0 means that the servlet is loaded when the web-app is deployed or when the server starts. A value < 0 means that the servlet is loaded whenever the container feels like. Also, the container must guarantee that servlets marked with lower integers are loaded before servlets marked with higher integers. The container may choose the order of loading of servlets with the same loadOnStartup value.
  4. Finally, we map the DispatcherServlet to the root path (/). This makes it the default servlet, that means, that it will handle all requests that does not match another servlet’s mapping.

This completes the initialization process. But as you might have noticed, we have registered two classes. The ApplicationConfiguration will contain configuration for the application context and the DispatcherServletConfiguration will contain configuration for the dispatcher servlet. Let’s look at them in detail.

The DispatcherServletConfiguration class

package com.jtuts.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.jtuts.controller")
public class DispatcherServletConfiguration {

    @Bean
    ViewResolver setupViewResolver(){
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");

        return resolver;
    }
    
}

In this class using the @ComponentScan annotation we configure the location of our Controller beans.

We also set up a view resolver that will determine how to map view names into JSP files. The prefix property’s value will be prepended to the name of every view we request and the suffix property’s value will be appended to the requested view name. For example if our controller returns the view name “login“, it will be mapped to the jsp: “/WEB-INF/views/login.jsp“.

The @EnableWebMvc is the same as the <mvc:annotation-driven /> in the XML version.  It enables a couple of spring features like mapping requests to controllers using the @RequestMapping annotation, validating form data with the @Valid annotation and so on.

The ApplicationConfiguration class

package com.jtuts.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class ApplicationConfiguration extends WebMvcConfigurerAdapter  {

}

This class will contain the configurations related to the application context. Anything that is not related directly to handling incoming requests. Currently it is empty.

The HomeController class

We have a very simple controller, that is mapped to the /home path, and returns the “home” view name.

package com.jtuts.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HomeController {
    
    @RequestMapping("home")
    public ModelAndView home() {
        return new ModelAndView("home");
    }
    
}

The home JSP

We have a very simple JSP for the home page. It only contains some basic content so we know that our application is running fine.

<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Spring MVC web application from scratch</title>
</head>
<body>
    <h1>Welcome to the home page.</h1>
</body>
</html>

The running application

When you deploy the application to a Tomcat8 server, it will show you the following result if you navigate to the homepage:

welcome-to-the-homepage

To deploy the application to a Tomcat8 server you just have to copy your .war file located in the target folder, into tomcat-installation-path\webapps . Then start up the server by launching startup.bat (windows) or startup.sh (linux).

Download

You can download the working project here.

How to get new HttpSession after invalidating the current one in Spring controller?

When you invalidate your current session you can no longer perform actions on it, like adding attributes. What if you would like to add attributes to your session after you invalidated it? Of course in this case you will be adding the attributes to a new session, because the invalidated one is not longer accessible.

Because of this you could get an exception like this:

java.lang.IllegalStateException: setAttribute: Session [24420949034523442D2704B180E4342] 
has already been invalidated

To solve this, just call the request.getSession() method on your HttpServletRequest. This method will return the current session if there is one, otherwise it will create a new one, and returns that.

Here is a short example:

@RequestMapping(value = { "/doSomething"}, method = RequestMethod.POST)
public String doSomething(final HttpServletRequest request) {

    // ... some more code 

    HttpSession oldSession = request.getSession();
    oldSession.invalidate(); 

    // The session has been invalidated in the previous call so we need to get the new one.
    HttpSession newSession = request.getSession();
    newSession.setAttribute("attribute-name", "attribute-value");

    // ... some more code 
}

You can check the documentation for: getSession().

Why setting lazy bean loading in Spring does not improve a web application’s startup speed?

Lazy initialization

By default, when a Spring web application starts up, all of the defined beans are instantiated automatically. If you have a huge application with thousands of beans, this could take a considerable amount of time.

One idea to speed up the application startup could be to set the loading of beans to lazy. That means, that most beans won’t be created at the application startup. They will be created when they are required for the first time by some other code. If you are using XML configuration you can tell Spring to initialize all beans lazily by default using the default-lazy-init attribute:

<beans xmlns="..." xmlns:xsi="..." xsi:schemaLocation="..." default-lazy-init="true">
    ...
</beans>

Why it may not work?

In theory, this could work, and save us some time during the startup process. In reality however, it is possible that despite our efforts to use lazy loading, almost all beans are created at the time of startup. Let’s see why.

I mentioned earlier that lazy loading means that beans are only created when they are first required. But what if almost all beans are required at the time of application startup?

In a Spring web application controllers are responsibe for serving incoming requests.  The controllers are also Spring beans, and their methods are annotated with the routes they are mapped to. So in order to know which Controller and which method to call when a request comes in, all controllers must be instantiated during application startup.

These are just the controllers yet, but they start a “chain reaction”. Controllers require services to do their job, so the services will also get instantiated and injected into the controllers. These services probably require some kind of repositories to get data from a database. So when a service is instantiated, the referenced repositories are also created. And due to this chain reaction, we will quite surely reach the majority of the beans present in a web application. At the end of the process we have an instance of most of the beans as if we didn’t use lazy initialization.

When could it work?

If you have beans in your application that are not required directly or indirectly by beans that are created on startup, then you could benefit from lazy initialization.

This can happen for example when you are running a test case without your controllers. In this situation it is possible that almost no beans are created when the application starts up. Other possibility is if you have some kind of factories in your code that create beans based on a condition. If the condition is not met for some of your beans, they may not get created until later time.

Sources

How to create a custom Spring form errors tag

Spring has a tag library that helps you in building forms. It also has a tag called errors that lets you output validation errors in a formatted way.  However, this tag has some limitations. When multiple errors are displayed at the same time, you can only control the styling of the outside container and not the styling of each of the errors. So for example it is not possible to display the error messages as an unordered list.

This tutorial describes how to create a custom errors tag that has some extra customization attibutes compared to the basic Spring form errors tag.

The steps we will take include the following:

  • Creating a Tag Library with our custom tag definition in it.
  • Creating a custom class that specifies how our new tag will work.
  • Include the tag library in a sample JSP and use it to display errors.

Creating the Tag Library

A tag library definition is contained in a .tld file and also each tag has a class which contains the logic that results in some kind of output when we use the tag. We are using the basic Spring error tag’s definition as a starting point, but add two extra attributes to it. The added attributes are highlighted in the code below.

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd">
    <tlib-version>1.0</tlib-version>
    <short-name>Jtuts common tags</short-name>
    <uri>http://jtuts.com/taglib/tags</uri>
    <tag>
          <description>Renders field errors wrapped in a specified tag.</description>
          <name>errors</name>
          <tag-class>jtuts.tag.CustomSpringFormErrorsTag</tag-class>
          <body-content>JSP</body-content>
          <variable>
               <name-given>messages</name-given>
               <variable-class>java.util.List</variable-class>
          </variable>
          <attribute>
               <description>Path to errors object for data binding</description>
               <name>path</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Standard Attribute</description>
               <name>id</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>Enable/disable HTML escaping of rendered values.</description>
               <name>htmlEscape</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>Specifies the HTML element that is used to render the individual errors.</description>
               <name>innerElement</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
               <attribute>
               <description>Specifies the CSS class that the element has that is used to render the individual errors.</description>
               <name>innerElementCssClass</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>Delimiter for displaying multiple error messages. Defaults to the br tag.</description>
               <name>delimiter</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>Equivalent to "class" - HTML Optional Attribute</description>
               <name>cssClass</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>Equivalent to "style" - HTML Optional Attribute</description>
               <name>cssStyle</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Standard Attribute</description>
               <name>lang</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Standard Attribute</description>
               <name>title</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Standard Attribute</description>
               <name>dir</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Standard Attribute</description>
               <name>tabindex</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onclick</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>ondblclick</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onmousedown</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onmouseup</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onmouseover</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onmousemove</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onmouseout</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onkeypress</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onkeyup</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>HTML Event Attribute</description>
               <name>onkeydown</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
               <description>Specifies the HTML element that is used to render the enclosing errors.</description>
               <name>element</name>
               <required>false</required>
               <rtexprvalue>true</rtexprvalue>
          </attribute>
          <dynamic-attributes>true</dynamic-attributes>
     </tag>
</taglib>

One of the new attributes is innerElement. It can be used to specify an HTML element that will be used to wrap every single error message individually. The other new attribute is the innerElementCssClass. This specifies the CSS class or classes that will be applied to each of the inner wrapping elements.

The other attributes are just copied from the original Spring form errors tag.

Creating the tag class

The tag class specifies what kind of output will the tag produce based on it’s attribute values. Here is the full class for the new tag.

package jtuts.tag;

import javax.servlet.jsp.JspException;

import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.tags.form.ErrorsTag;
import org.springframework.web.servlet.tags.form.TagWriter;


/**
 * The Spring form:errors tag extended with attributes which allow to use an inner element with a
 * css class which wraps every individual error item.
 */
public class CustomSpringFormErrorsTag extends ErrorsTag {

    private static final long serialVersionUID = 24723583545L;

    private String innerElement;
    private String innerElementCssClass;

    @Override
    protected void renderDefaultContent(TagWriter tagWriter) throws JspException {
        tagWriter.startTag(getElement());
        writeDefaultAttributes(tagWriter);
        String delimiter = ObjectUtils.getDisplayString(evaluate("delimiter", getDelimiter()));
        String[] errorMessages = getBindStatus().getErrorMessages();

        for (int i = 0; i < errorMessages.length; i++) {
            String errorMessage = errorMessages[i];
            if (i > 0) {
                tagWriter.appendValue(delimiter);
            }

            if (innerElement != null)
                tagWriter.appendValue(startTagForInnerElement());

            tagWriter.appendValue(getDisplayString(errorMessage));

            if (innerElement != null)
                tagWriter.appendValue(endTagForInnerElement());
        }
        tagWriter.endTag();
    }

    private String startTagForInnerElement() {
        StringBuilder stringBuilder = new StringBuilder("<" + innerElement);

        if (innerElementCssClass != null)
            stringBuilder.append(" class=\"" + innerElementCssClass + "\"");

        stringBuilder.append(">");

        return stringBuilder.toString();
    }

    private String endTagForInnerElement() {
        return "</" + innerElement + ">";
    }

    public String getInnerElement() {
        return innerElement;
    }

    public void setInnerElement(String innerElement) {
        this.innerElement = innerElement;
    }

    public String getInnerElementCssClass() {
        return innerElementCssClass;
    }

    public void setInnerElementCssClass(String innerElementCssClass) {
        this.innerElementCssClass = innerElementCssClass;
    }

}

You can see that it extends the basic error tag (org.springframework.web.servlet.tags.form.ErrorsTag).  We override the renderDefaultContent method that creates the output of the tag. Anything that you pass to this method will be appended to the output produced when someone uses this tag.

As you can see the extra logic that we have added is pretty simple. We just print an opening and closing tag around each error if the user provided the innerElement attribute and we also add the CSS classes to the opening tag if the innerElementCssClass attribute is specified.

We have also set up some extra methods, but they are just there to simplify the renderDefaultContent method.

The outer element that encloses all the errors is just displayed the same way as it was in the super implementation (startTag, endTag, writeDefaultAttributes calls).

Using the tag

For demonstration purposes I have created a very simple registration form that uses the newly created tag.

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="jtuts" uri="/WEB-INF/tags/jtuts.tld" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Registration form with a custom errors tag.</title>
    <style>
        .error-message { color: #CC3344; }
    </style>
</head>
<body>
    <h1>Register</h1>
    <form:form commandName="userForm" action="${pageContext.request.contextPath}/register" method="post">
        <jtuts:errors path="*" element="ul" innerElement="li" delimiter="" cssClass="error-message" />
        <table>
            <tr>
                <td>First Name:</td>
                <td><form:input path="firstName" /></td>
            </tr>
            <tr>
                <td>Last Name:</td>
                <td><form:input path="lastName" /></td>
            </tr>
            <tr>
                <td>User Name:</td>
                <td><form:input path="userName" /></td>
            </tr>
            <tr>
                <td>Email Address:</td>
                <td><form:input path="emailAddress" /></td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="Save User" />
                </td>
            </tr>
        </table>
    </form:form>
</body>
</html>

Notice the taglib definition with the taglib directive and the usage of our new jtuts:errors tag.

The POM, the Controller, the form class and validation

For the sake of completeness I also show you the remaining parts of the sample application.

The pom.xml looks like this:

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>how-to-create-a-custom-spring-form-errors-tag-20150126</groupId>
    <artifactId>how-to-create-a-custom-spring-form-errors-tag-20150126</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>how-to-create-a-custom-spring-form-errors-tag-20150126 Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <spring.version>4.1.4.RELEASE</spring.version>
        <javax.validation.validation-api.version>1.1.0.Final</javax.validation.validation-api.version>
        <hibernate-validator.version>5.1.3.Final</hibernate-validator.version>
        <servlet-api.version>2.5</servlet-api.version>
        <jsp-api.version>2.2</jsp-api.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>${javax.validation.validation-api.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>${hibernate-validator.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>${servlet-api.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>${jsp-api.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <path>/jtuts</path>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

I just included the minimum dependencies required for this project. I also used the Tomcat Maven plugin to be able to deploy the app easily.

The Controller class:

package jtuts.controller;

import javax.validation.Valid;

import jtuts.form.UserForm;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;


@Controller
public class RegisterController {
 
    @RequestMapping(value="register", method = RequestMethod.GET) 
    public ModelAndView registerGet() {
        ModelAndView model = new ModelAndView();
        
        model.setViewName("register");
        model.addObject("userForm", new UserForm());
        
        return model;
    }

    @RequestMapping(value="register", method = RequestMethod.POST) 
    public ModelAndView registerPost(@Valid @ModelAttribute("userForm") UserForm userForm, BindingResult result) {
        ModelAndView model = new ModelAndView();
        
        model.setViewName("register");
        
        return model;
    }
}

In the controller we are just running the form through some basic validation. The validation rules are set up in the form class which looks like this:

package jtuts.form;

import org.hibernate.validator.constraints.NotEmpty;

public class UserForm {

    @NotEmpty(message="The first name may not be empty.")
    private String firstName;
    
    @NotEmpty(message="The last name may not be empty.")
    private String lastName;
    
    @NotEmpty(message="The user name may not be empty.")
    private String userName;
    
    @NotEmpty(message="The email address may not be empty.")
    private String emailAddress;

    
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
}

The Spring configuration for the validator to work:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
         
    <context:component-scan base-package="jtuts" />
    <mvc:annotation-driven validator="validator" />
  
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
  
</beans>

The working application

This is what the working application looks like when we try to submit an empty form. Notice that we are displaying the error messages as an unordered list which was not possible with the original version of the errors tag.

how-to-create-a-custom-spring-form-errors-tag-20150126-registration-form

Download

You can download the whole working source code from here.

 

Validating dates in spring form objects

Validating dates on a form managed by Spring is a bit more tricky than checking a simple string attribute for emptiness.

You can use the org.springframework.format.annotation.DateTimeFormat annotation on the field that you would like to validate. This annotation has an attribute called pattern that allows you to set a the pattern to validate against. Example usage of the annotation:

public class PostForm {
    
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @NotNull(message = "Please provide a date.")
    private Date date;
    
    private String contents;
    
    // getters and setters...
}

So far it was similar to using other validation annotations. However, you might notice that this annotation does not have a message attribute, so you can’t specify what message should be printed. Let’s see what error message we get back if we use the annotation. I used 2014-99-11 as the date and yyyy-MM-dd as the pattern to validate against.

Failed to convert property value of type java.lang.String to 
required type java.util.Date for property date; 
nested exception is org.springframework.core.convert.ConversionFailedException: 
Failed to convert from type java.lang.String to type @org.springframework.format.annotation.DateTimeFormat 
@javax.validation.constraints.NotNull java.util.Date for value 2014-99-11; 
nested exception is java.lang.IllegalArgumentException: Unable to parse 2014-99-11

You can see that this results in not too nicely looking error message that explains what is the problem in detail…but users may expect a bit more concise message.

To override the default message, you need to have a messageSource and in that a message with a specific key that corresponds to the validated attribute.

Our message source is set up like this in the application context:

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <value>classpath:i18n/messages</value>
    </property>
</bean>

Of course we have a messages.properties file in the i18n folder under our classpath. Our messages.properties file looks like this:

typeMismatch.postForm.date=Please enter a valid date.

The name of the message key is very important. It is structured like this: {ValidationClass}.{modelObjectName}.{field}. You don’t necessarily need to specify the whole key, because the resolving happens in the following way in our case:

  1. First the typeMismatch.postForm.date key is looked up.
  2. If it is not found, the typeMismatch.postForm key is looked up.
  3. If it is not found, the typeMismatch key is looked up.
  4. If it is not found, the default message will be rendered.

Download

You can download the source code of an example application here.