Posts Tagged ‘mvc

28
Nov
09

Bullet Proof MVC using Maven Multi-Module Projects

ge { margin: 0.79in } P { margin-bottom: 0.08in } –>This page will describe the process of setting up a multi-module project where each component of the MVC architecture is separated into its own sub-module. Separating each component of the MVC into modules results in protecting the code from leakage of Concerns.

Background

The model view controller architecture has been discussed for years. It was first introduced back in 1979 by a developer working on Smalltalk language. http://en.wikipedia.org/wiki/Model▒??view▒??controller

But until recently implementing it religiously has been a challenge.

Requirements

  • Basic understanding of the Spring Framework
  • Basic understanding of MVC
  • Basic understanding of Maven2

Framework’s ability to enforce MVC

Although popular MVC framework claims to help developers separate concerns in software applications, they really don’t live up to the promise.

Developers end up implementing business logic within controllers and JSP’s. If you have developed professionally you know what I am talking about. We all share horror stories of JSP’s that look like they are controlling flow, and Controllers that look like they are making business decisions and executing JDBC queries directly and passing references to HttpServletRequest and HttpServlet into model objects.

What we got was implementations that were ▒??sort of▒?? adhering to the model view controller pattern.

Its not the framework’s fault directly but the simple fact of allowing a developer to do bad things while working with it.

Controller leaking into Model

If there were a way to prevent the Model from even recognizing HttpServletRequest class would be adequate to stop leaking controller concerns into the model.

Controller and Model leaking into View

Many times Beans would leak into JSP’s and cause JSP’s to look like controllers. Scripts with if and while loops are a prime example of this. To turn scripting off in JSP’s you may implement the following.

Using EL instead of scriptlets

The EL is intended to replace the use of Java scriptlets in developing JSP based web applications. It▒??s possible to disable the evaluation of scriptlets through configuration parameters. This allows a developer to make sure no one uses scriptlets. This allows best practices to be enforced at an application level.

<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <scripting-invalid>true</scripting-invalid>
    </jsp-property-group>
</jsp-config>

If someone were to introduce scripting elements they would get an error like this.

/results.jsp(13,5) Scripting elements ( <%!, <jsp:declaration, <%=, <jsp:expression, <%, <jsp:scriptlet ) are disallowed here.

Using Maven to enforce MVC

You will see shortly that Maven allowing with the techniques above allow to help enforce MVC. Maven allows system developers break up parts of MVC into their own sub modules. Since each module have their own dependencies you can customize what each module sees.

For example you can stop controller leaking its concerns into the model by not specifying the controller as a dependency in the Model project. To prevent the controller and Model from leaking their concerns to the view the view module does not have a Java source directory! (that’ll fix it). To prevent logic from appearing in JSP’s you may turn off scriptlets in JSP in favor of using EL.

All the components of the Model view controller come together when the application is built by Maven.

All components go into what is called the Maven Reactor. The dependencies are resolved and the final artifacts are written to the target folder. Artifacts like EAR, WAR, Jar, Tar, Zip files are written ready to be deployed.

The Demonstration

The demonstration will consist of an application that retrieves a list of products and displays them on the homepage. Although an application like this could have been implemented with just a few lines code, the point here is to demonstrate Maven’s ability separate MVC concerns into discrete modules for medium to large applications.

Key points to demonstrate

  • Exhibit that the Model is unaware of the controller and view.
  • Ability for the Controller to reference the Model
  • Ability for the view to reference the Model and Controller but only for the purpose of gluing it all together to create a single WAR file.
  • There will be no Java source directory in the view and scriptlets will be disabled in JSP’s.

Setting up the Parent Module

The parent project consists of the following sub-modules.

  1. test-model ▒?? Model layer contains a bean that retrieves data from the persistence layer.
  2. test-view ▒?? contains JSP’s and HTML files
  3. test-controller ▒?? contains servlets that will call the model layer.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart

groupId: testPackage

artifactId: test-parent

cd test-parent

edit the pom.xml file and change the package element to say “pom”.

<packaging>pom</packaging>

Setting up the Model

The model layer strictly contains the business logic. Model objects will also call persistence classes to store data. The model should be shielded from even the control logic because most control logic is implementation specific. For this reason the controller layer is not visible for this module.

To implement the model layer we will be using the Spring framework. We will write a simple bean that will call a Data Manager in the persistence layer that returns a list of Products.

In the test-parent directory

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart
groupId: testpackage
artifactId: test-model
cd test-model
Create src/main/resources folder for the applicationContext.xml file.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
        "-//SPRING//DTD BEAN//EN"
        "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
        <bean id="testModel" class="testpackage.TestModelImpl">
                <property name="testDataManager" ref="testDataManager"/>
        </bean>

        <bean name="testDataManager" class="testpackage.TestDataManagerImpl"/>
</beans>

Product.java

package testpackage;

public class Product {
        private Integer id;
        private String name;

        public Product(int id, String name) {
                this.id = id;
                this.name = name;
        }

        public Integer getId() {
                return id;
        }
        public void setId(Integer id) {
                this.id = id;
        }
        public String getName() {
                return name;
        }
        public void setName(String name) {
                this.name = name;
        }
}

TestDataManager.java

package testpackage;
import java.util.List;
public interface TestDataManager {
        public abstract List<Product> fetchProductList();
}

TestDataManagerImpl.java

package testpackage;
import java.util.ArrayList;
import java.util.List;
public class TestDataManagerImpl implements TestDataManager {
        public List<Product> fetchProductList() {
                List<Product> productList = new ArrayList<Product>();
                productList.add(new Product(1, "test 1"));
                productList.add(new Product(2, "test 2"));
                productList.add(new Product(3, "test 3"));
                return productList;
        }
}

TestModel.java

package testpackage;
import java.util.List;
public interface TestModel {
        public abstract List<Product> fetchProducts(String userId);
}

TestModelImpl.java

package testpackage;

import java.util.List;

public class TestModelImpl implements TestModel {
        private TestDataManager testDataManager;

        public TestDataManager getTestDataManager() {
                return testDataManager;
        }

        public void setTestDataManager(TestDataManager testDataManager) {
                this.testDataManager = testDataManager;
        }

        /* (non-Javadoc)
         * @see testpackage.TestModel#fetchProducts(java.lang.String)
         */
        public List<Product> fetchProducts(String userId) {
                // identify the access level based on user id
                // ...

                // call the dataManger to get the filtered list of
                // products.
                List<Product> productList = getTestDataManager().fetchProductList();

                return productList;
        }
}

Setting up the View

This module will be made up of JSP, HTML, XML. It will be void of all control logic. Control logic belongs in the controller module which we will define next. Since this is strictly view only module there is no place to put Java code.

In the test-parent folder type:
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp
groupId: testPackage
artifactId: test-view
cd test-view

open pom.xml and change packaging to war.
It should look like this:

<?xml version="1.0"?>
<project
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
        xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <artifactId>test-parent</artifactId>
                <groupId>testpackage</groupId>
                <version>1.0-SNAPSHOT</version>
        </parent>
        <artifactId>test-view</artifactId>
        <packaging>war</packaging>
        <name>test-view Maven Webapp</name>
        <url>http://maven.apache.org</url>
        <build>
                <finalName>test-view</finalName>
                <plugins>

                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-compiler-plugin</artifactId>
                                <version>2.0.2</version>
                                <configuration>
                                        <source>1.5</source>
                                        <target>1.5</target>
                                </configuration>
                        </plugin>

                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-eclipse-plugin</artifactId>
                                <configuration>
                                        <downloadSources>true</downloadSources>
                                        <downloadJavadocs>true</downloadJavadocs>
                                        <wtpapplicationxml>true</wtpapplicationxml>
                                        <wtpversion>1.5</wtpversion>

                                        <classpathContainers>
                                                <classpathContainer>org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v6.0</classpathContainer>
                                                <classpathContainer>org.eclipse.jst.j2ee.internal.web.container</classpathContainer>
                                                <classpathContainer>org.eclipse.jst.j2ee.internal.module.container</classpathContainer>
                                        </classpathContainers>
                                        <additionalProjectFacets>
                                                <jst.web>2.5</jst.web>
                                        </additionalProjectFacets>
                                </configuration>
                        </plugin>
                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-war-plugin</artifactId>
                        </plugin>

                        <plugin>
                                <groupId>org.mortbay.jetty</groupId>
                                <artifactId>jetty-maven-plugin</artifactId>
                                <version>7.0.0.v20091005</version>
                                <configuration>
                                        <scanIntervalSeconds>1</scanIntervalSeconds>
                                </configuration>
                        </plugin>
                </plugins>
        </build>
        <dependencies>
                <dependency>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                        <version>3.8.1</version>
                        <scope>test</scope>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-web</artifactId>
                        <version>2.5.6</version>
                </dependency>
                <dependency>
                        <groupId>testpackage</groupId>
                        <artifactId>test-controller</artifactId>
                        <version>${version}</version>
                </dependency>
                <dependency>
                        <groupId>testpackage</groupId>
                        <artifactId>test-model</artifactId>
                        <version>${version}</version>
                </dependency>
                <dependency>
                        <groupId>javax.servlet</groupId>
                        <artifactId>jstl</artifactId>
                        <version>1.1.2</version>
                </dependency>
                <dependency>
                        <groupId>taglibs</groupId>
                        <artifactId>standard</artifactId>
                        <version>1.1.2</version>
                </dependency>
        </dependencies>
</project>

The following is what is in web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">

  <display-name>Archetype Created Web Application</display-name>

        <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:testpackage/applicationContext.xml</param-value>
        </context-param>

<!-- starts the spring framework for the model layer -->
        <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>

        <servlet>
                <servlet-name>testServlet</servlet-name>
                <servlet-class>testpackage.TestServlet</servlet-class>
                <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
                <servlet-name>testServlet</servlet-name>
                <url-pattern>*.do</url-pattern>
        </servlet-mapping>

        <welcome-file-list>
                <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
        <jsp-config>
            <jsp-property-group>
                <url-pattern>*.jsp</url-pattern>
                <scripting-invalid>true</scripting-invalid>
            </jsp-property-group>
        </jsp-config>
</web-app>

The following is the JSP that displays the results.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
  <title>XHTML 1.0 Strict Template</title>
  <meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
  <meta http-equiv="Content-Language" content="en-us" />
 </head>

 <body>
        <table border="1">
                <%--  <%="testing 123" %> Uncomment this to verify that scripts are disallowed --%>
                <h3>Products</h3>
                <c:forEach items="${productList}" var="product" varStatus="status">
                        <c:if test="${status.first}"><tr><th>Id</th><th>Name</th></tr></c:if>
                        <tr><td><c:out value="${product.id}"/></td><td><c:out value="${product.name}"/></td></tr>
                </c:forEach>
        </table>
</body>
</html>

Setting up the Controller

To keep things simple will define an application using standard servlets. Persistence layer won’t be visible from here

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart
groupId: testPackage
artifactId: test-controller
cd test-controller

web.xml

<?xml version="1.0"?>
<project
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
        xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <artifactId>test-parent</artifactId>
                <groupId>testpackage</groupId>
                <version>1.0-SNAPSHOT</version>
        </parent>
        <artifactId>test-controller</artifactId>
        <name>test-controller</name>
        <url>http://maven.apache.org</url>
        <dependencies>
                <dependency>
                        <groupId>testpackage</groupId>
                        <artifactId>test-model</artifactId>
                        <version>1.0-SNAPSHOT</version>
                </dependency>
                <dependency>
                        <groupId>org.apache.geronimo.specs</groupId>
                        <artifactId>geronimo-servlet_2.5_spec</artifactId>
                        <version>1.2</version>
                        <type>jar</type>
                        <scope>compile</scope>
                </dependency>
                <dependency>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                        <version>3.8.1</version>
                        <scope>test</scope>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring</artifactId>
                        <version>2.5.6</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-web</artifactId>
                        <version>2.5.6</version>
                </dependency>
        </dependencies>
</project>

The following is the servlet.

package testpackage;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class TestServlet extends HttpServlet {
        private TestModel testModel;

        @Override
        public void init(ServletConfig config) throws ServletException {
                ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
                testModel = (TestModel) context.getBean("testModel");
                super.init(config);
        }
        // Direct access to the data persistence layer is prevented
        // class is not visible
        // private TestDataManagerImpl testDataManager;

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                        throws ServletException, IOException {
                System.out.println("servlet was called.");
                List<Product> productList = testModel.fetchProducts("test123");
                req.setAttribute("productList", productList);
                req.getRequestDispatcher("/results.jsp").forward(req, resp);
        }
}

Running the project

If you are using jetty to run the project then place the following into the test-view modules pom.xml

At this point you have 2 options to run the project. You can run it it Jetty. This is the easiest way but you need to do a mvn install on the parent each time you make a change to the code.

mvn install

cd test-view

mvn jetty:run

Or you can read the following page and setup the project to run in Tomcat 6 using Eclipse WTP.

Navigate to http://localhost:8080/ if using jetty and /test-view/a.do if you are using tomcat 6 in WTP.

Conclusion

The project we just ran demonstrates the ability to separate the various components of the MVC into modules. It was also demonstrated that these modules are moderately protected by leakage of concerns.

Taking it a step further

The Model object above contains the business logic and its all clumped together in one module (jar). There is nothing really stopping anyone from creating multiple modules each representing a different concept. For example if you are creating a portal project for a sky diving company. You can write one module to handle the weather forecasting section, another one to handle scheduling and the other to handle life insurance calculations. In this scenario each model component is protected from one model leaking its concerns to the other.

This site is a collaborative effort! The complete text and sourcecode for this is available on GitHub. Corrections and enhancements are welcome, please make the change and submit a pull request in the comment area below.
01
Aug
09

Spring MVC Validation using Commons Validator

This site is a collaborative effort! The complete text and sourcecode for this is available on GitHub. Corrections and enhancements are welcome, please make the change and submit a pull request in the comment area below.

This article will show you how to integrate Spring MVC with the commons validator framework.

Requirements:
If you have not done so already please read the following link to get started.

The commons validator is a core set of classes responsible for validating data. The down side of commons validation is that you can not use it directly out of the box. Typically there is some wrapper code that is necessary. Struts provided this wrapper code in the org.apache.struts.validator package.

Instead of packaging this code into Spring MVC the developers of the framework decided to included it as a module ontop of the Spring framework.

The spring validation module provides support modules that allows the commons validator to be integrated with the spring framework.

insert the following dependency in pom.xml and regenerate your eclipse project.

 		 <dependency>
			<groupId>org.springmodules</groupId>
			<artifactId>spring-modules-validation</artifactId>
			<version>0.8</version>
 		</dependency>
 		<dependency>
			<groupId>commons-validator</groupId>
			<artifactId>commons-validator</artifactId>
			<version>1.1.4</version>
 		</dependency>

This will get the spring-modules-validation onto your machine as well as commons-validator. The main class in the spring validator module is the FieldChecks this class contains almost all the necessary items that you may need to implement in your commons-validator code.

At the time of this writing the following were the methods and the necessary code to include into the validator-rules.xml file.

All the methods have the same signature except

  • requiredIf
  • requiredWhen

You need to include the following in whatever resource bundle your web application uses…

Read my article on Web Application Resource Bundles

   errors.required={0} is required.
   errors.minlength={0} can not be less than {1} characters.
   errors.maxlength={0} can not be greater than {1} characters.
   errors.invalid={0} is invalid.

   errors.byte={0} must be a byte.
   errors.short={0} must be a short.
   errors.integer={0} must be an integer.
   errors.long={0} must be a long.
   errors.float={0} must be a float.
   errors.double={0} must be a double.

   errors.date={0} is not a date.
   errors.range={0} is not in the range {1} through {2}.
   errors.creditcard={0} is an invalid credit card number.
   errors.email={0} is an invalid e-mail address.

This is what validator-rules will look like if you are using the Spring MVC framework with commons loggingâ?¦

/WEB-INF/validator-rules.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE form-validation PUBLIC
          "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
          "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">

<form-validation>
	<global>
		<validator name="required"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateRequired"
			methodParams="java.lang.Object,
                        org.apache.commons.validator.ValidatorAction,
                        org.apache.commons.validator.Field,
                        org.springframework.validation.Errors"
			msg="errors.required">
		</validator>
		<validator name="requiredif"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateRequiredIf"
			methodParams="java.lang.Object,
                               org.springframework.validation.ErrorsAction,
                               org.apache.commons.validator.Field,
                               org.springframework.validation.Errors"
			msg="errors.required" />

		<validator name="validwhen" msg="errors.required"
			classname="org.apache.struts.validator.validwhen.ValidWhen" method="validateValidWhen"
			methodParams="java.lang.Object,
                       org.springframework.validation.ErrorsAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors" />

		<validator name="minlength"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateMinLength"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.minlength"
			jsFunction="org.apache.commons.validator.javascript.validateMinLength" />

		<validator name="maxlength"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateMaxLength"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.maxlength"
			jsFunction="org.apache.commons.validator.javascript.validateMaxLength" />

		<validator name="mask"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateMask"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.invalid" />

		<validator name="byte"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateByte"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.byte" jsFunctionName="ByteValidations" />

		<validator name="short"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateShort"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.short" jsFunctionName="ShortValidations" />

		<validator name="integer"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateInteger"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.integer" jsFunctionName="IntegerValidations" />

		<validator name="long"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateLong"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.long" />

		<validator name="float"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateFloat"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.float" jsFunctionName="FloatValidations" />

		<validator name="double"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateDouble"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.double" />

		<validator name="date"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateDate"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.date" jsFunctionName="DateValidations" />

		<validator name="intRange"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateIntRange"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="integer" msg="errors.range" />

		<validator name="floatRange"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateFloatRange"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="float" msg="errors.range" />

		<validator name="doubleRange"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateDoubleRange"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="double" msg="errors.range" />

		<validator name="creditCard"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateCreditCard"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.creditcard" />

		<validator name="email"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateEmail"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.email" />

		<validator name="url"
			classname="org.springmodules.validation.commons.FieldChecks" method="validateUrl"
			methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
			depends="" msg="errors.url" />
	</global>
</form-validation>

In the validation.xml all the forms that will be used in the application will be defined. The layout of this file is very similar to the validation-rules.xml however we don’t have have anything in the global section.

validation.xml

<!DOCTYPE form-validation PUBLIC
          "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.4//EN"
          "http://jakarta.apache.org/commons/dtds/validator_1_1_4.dtd">
<form-validation>

	<formset>
		<form name="address">
			<field property="name" depends="required">
				<arg0 key="info.name" />
			</field>
			<field property="city" depends="required">
				<arg0 key="info.city" />
			</field>
			<field property="street" depends="required">
				<arg0 key="info.street" />
			</field>
			<field property="state" depends="required">
				<arg0 key="info.state" />
			</field>
			<field property="zip" depends="integer">
				<arg0 key="info.zip" />
			</field>
		</form>
	</formset>
</form-validation>

In the item above the first argument for each property is the key to the resource bundle entry that will display the error.

Insert the following into the resource bundle property file

nameEmpty=Name is empty
info.name=Name
info.city=City
info.street=Street Address
info.state=State

I needed to insert the following into my spring-servlet.xml and change the validator for my SimpleFormController to the commons validator.

<bean id="validatorFactory"
      class="org.springmodules.validation.commons.DefaultValidatorFactory">
<property name="validationConfigLocations">
	<list>
      <value>/WEB-INF/validation.xml</value>
      <value>/WEB-INF/validator-rules.xml</value>
    </list>
  </property>
</bean>

<bean id="beanValidator" class="org.springmodules.validation.commons.DefaultBeanValidator">
<property name="validatorFactory" ref="validatorFactory"/>
</bean>

That’s All!!! You now have a fully configured Spring MVC system with Commons Validator

Special Notes:
Currently the client side javascript code generation and validation is not working. This issue is discussed at the following url:
http://jira.springframework.org/browse/MOD-402
I would encourage you guys to register with that site and vote for the issue to get fixed.

This site is a collaborative effort! The complete text and sourcecode for this is available on GitHub. Corrections and enhancements are welcome, please make the change and submit a pull request in the comment area below.



Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 75 other followers

May 2017
S M T W T F S
« Mar    
 123456
78910111213
14151617181920
21222324252627
28293031  

Blog Stats

  • 813,774 hits