0
0
0
45,917

Spring MVC Tutorial

Spring MVC Tutorial

SpringMVC This is a tutorial on developing Spring enabled web-applications with Spring MVC. It provides a comprehensive cover of most of the features available in the 'official' Pivotal (ex-SpringSource) release, as well as integration with miscellaneous open-source extensions provided by Innovations Framework. You will learn how to: code web-controllers, configure your Spring application for a web-environment, write views, and much more.

Introducing Spring MVC

Spring Framework provides a set of modules to help in the development of Java web application. Spring MVC is web framework that follows the model-view-controller design-pattern. This allows separation of concerns and easy integration of applications services and domain object (the model), the views used to display content in web browsers, and the web controller that adapt the application services to the web environment.

MVC Architecture

In Spring MVC web architectures application domain (business) objects may be develop independent of the web context. This fosters modular development and easy porting of existing applications to web contexts. Additionally, the contents of web pages (views) is decoupled from the details of implementation of web-aware interfaces and services. This fosters division of work, with web-designers working of web page layouts and style, and programmers are responsible for the processing elements of the application. The implementation of MVC is packed in files spring-web.jar and spring-webmvc.jar.

MVC is categorized as request-driven framework, since programmers structure the design of the web service in terms of methods that handle individual HTTP request. Other frameworks fitting this category include: Struts and Struts2. Other web frameworks are based on compositional and reusable components. This includes JSpring Framework, the standard web framework specified in JEE6.

Figure below depicts the architecture of MVC framework. A DispatcherServlet dispatcher HTTP requests to controllers, to handle the request and implement application specific logic. Controllers output a view name and fill-up a model with attribute value used in generation of dynamic views. A ViewResolver maps logical view names to actual views (e.g.HTML and/or JSP pages). The DispatcherServlet then relays the view to client over the net.

Web MVC Architecture

Steps to develop a Spring MVC application

The following steps should be done to fully implement and deploy a Spring Framework-MVC based web application service:
  1. Initialize a Root Web Container
  2. Deploy the DispatcherServlet
  3. Implement one or more Controller (set of request handlers)
  4. Register Controller with the DispatcherServlet
  5. Implement set of Views
  6. Register a ViewResolver with the DispatcherServlet
  7. Deploy and test

Spring Applications in a Web Environment

To use Spring Framework in a web context, a specialized bean container and application context needs to be created. The interface WebApplicationContext extends ApplicationContext, for the web (HTTP access) environment. Since Spring Framework bean containers and application contexts may be organized hierarchically, MVC uses an may use two bean containers and application contexts in handling a HTTP request. A root context is used during the life-time of an application. Additional child contexts are created for handling individual HTTP requests.

The root WebApplicationContext is created by an Spring Framework provided listener of class type ContextLoaderListener. This listener is responsible to create a bean container once a MVC based web application is deployed or started. When a ContextLoaderListener is started it delegates work to a ContextLoader object to create a root context. By default, it creates a XmlWebApplicationContext object that uses XML files for configuration.

Configuring the Root Web Container

The standard tag <listener> is used in the context descriptor file WEB-INF/web.xml to declare and configure the ContextLoaderListener. The sub-tag <listener-class> is used to specify the fully qualified name for the class type for the listener servlet30.

By default the root context will search a configuration XML file named WEB-INF/applicationContext.xml. This may be changed by setting a global parameter for the application context named contextConfigLocation. The tag <context-param> and sub-tags <param-name> and <param-value> are used for this purpose~servlet30. Application configuration that is not specific to MVC and HTTP based access should be setup here (e.g. bean definitions and dependencies). Specific configuration for MVC should be placed in a separated file (e.g. web controllers). An error will be raised at run-time if no XML configuration file is found. Multiple XML files may also be specified in different lines. Wildcard patterns (Ant style) are also allowed.

An example configuration for a web root context is shown below:


<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/mywebapp-config.xml   
		/WEB-INF/mywebapp-security.xml   
	</param-value>
</context-param>

<listener>
	<listener-class>
	org.springframework.web.context.ContextLoaderListener 
	</listener-class>
</listener>

Custom Servlets

Although most web application are most likely to use the Spring MVC front-end Servlet, in is possible for application to write their own Servlets. In this case, it useful for Servlet to have access to the root web application context. For this purpose, Spring Framework provides a utility function to retrieve a reference to the root application context:


ApplicationContext appContext =
	WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);

The ServletContext is a standard object type of Servlet technology. It is made available to Servlets by the Servlet container in method init() or may be accessed using method GenericServlet.getServletContext(). An example Servlet is shown below:


public class MyServiceServlet extends HttpServlet {
	private MyService service;
	
	public void init() {
		ServletContext ServletContext = getServletContext();
		ApplicationContext appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
		service = appContext.getBean("myService", MyService.class);
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
		...
		service.doService(...);
		...
	}
}

The Dispatcher Servlet

A MVC dispatcher Servlet is an object of class type DispatcherServlet that coordinates request-handling activities. This Servlet ensures that incoming HTTP request are delivered to application provided controllers and handler methods. Responses sent as application provided view (or compositions of such views) are also relayed by this Servlet. It also uses strategy objects such as handler adapters and view resolvers, for easy configuration and extensability.

The DispatcherServlet is deployed, like every other Servlet, by setting it up in the web description file WEB-INF/web.xml. The standard way to perform this is using tag <servlet>, and sub-tags <servlet-name> and <servlet-class>. A Servlet parameter named contextConfigLocation may also be set to specify the location of a dedicated XML configuration file for the MVC dispatcher Servlet (separated from the configuration file for the root web container). This is the same parameter name as used for root web container, but the tag <init-param> is used this time (not <context-param>). If no location is specified then for Servlet name myapp the location /WEB-INF/myapp-servlet.xml is used. An error will be raised at run-time if no XML configuration file is found.

In addition to declare the MVC dispatcher Servlet, a URL mapping should also be defined. This is done with tag <servlet-mapping>. Inside tag <servlet-name> is used to specify the dispatcher Servlet name, and tag <url-pattern> to specify a URL pattern.

An example configuration for a dispatcher Servlet is shown below (set up in WEB-INF/web.xml).

<webapp>
...
<servlet>
	<servlet-name>myapp</servlet-name>
	<servlet-class>
	org.springframework.web.servlet.DispatcherServlet
	</servlet-class>
	<init-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
	/WEB-INF/myapp-servlet-config.xml	 <!-- default: /WEB-INF/myapp-servlet.xml -->
	</param-value>
</init-param>
</servlet>

<!--Map the DispatcherServlet to a URL pattern -->
<servlet-mapping>
	<servlet-name>myapp</servlet-name>
	<url-pattern>/mybase/*</url-pattern>
</servlet-mapping>
	...
</webapp>

myapp is the name assigned to the Servlet, and the /mybase/* is the pattern selected. If the root of the Servlet container is located a http://localhost:8080/, than this setting will map URL such as:

http://localhost:8080/myapp/mybase/list
http://localhost:8080/myapp/mybase/new
http://localhost:8080/myapp/mybase/show?id=1

Web Controllers

The core abstraction in Spring MVC is a controller. A controller is POJO that implements a set of methods that are invoked to handle HTTP requests. Since Spring Framework2.5, controller classes are annotated with @Controller. Previous version of Spring MVC required controllers to derive from an abstract controller class (as in other frameworks, such as Struts). This approach is now considered deprecated in Spring MVC.

HTTP Request Handlers

A request handler method is a public method of a MVC Controller. Each handler specifies the URL pattern, HTTP method, and other condition to select it for handling specific request. It may access to request parameters as arguments to the handler.

A handler method typically invokes application services (e.g.involving access to a data-base), populate a model with attributes that are use to generate a dynamic response, and select a view to be processed using that created model. The view is provided in the return value of the handler. Either as physical path or logical name returned as a java.lang.String, or a view object whose type derives from AbstractView.

Request Mapping

Each controller handler method maps to a specific URL or URL pattern defined with annotation @RequestMapping("URL-pattern"). An example controller is shown below with several handler method and URL patterns:


@Controller
public class MyController {

	//process request URLs: http://hostname/.../page1.htm
	@RequestMapping("/page1.htm")
	public String h1(Model model) {... }  //returns view name

	//using wildcard in URI mapping
	@RequestMapping("/page2/*/abc.htm")
	public String h2(Model model) {...}

	//inject HTTP-request parameter param
	@RequestMapping("/page2.htm")
	public String h3(@RequestParam("parm1") long i) {...}

	//using URI template to inject extracted segment
	@RequestMapping("/users/{userId}")
	public String show(@PathVariable("userId") long id) {...}

}

The @RequestMapping annotation may be used at the level of individual handler methods, at the class level, or both. When a class level mapping is provided, it specifies the prefix to the URL pattern at method. If a @RequestMapping annotation is not used in a method than the method name is used as URL pattern.

If a mapping is not provided at the class level, then a convention based on class name may be used for the mapping. If controller class is named AbcController, then the controller maps to abc/* and abc. For requests with URL abc, further restriction are used to select the handler methods, such as: HTTP method type and presence of request parameters (see below). Class name based mapping also requires a ControllerClassNameHandlerMapping bean to be defined in the MVC configuration file.

Request Parameters

Annotation @RequestParam("param") may be used for arguments of handler methods to provides access to request parameter values. This are values provided by the user (e.g.from a HTML form), and coded in the query string of URL as: http://hostname/path?param1=value1&param2=value2&....

MVC framework makes the appropriate type conversion between the parameters values and the types of the handler arguments. This is true for argument of numeric types, String, Date and a few others. For new types it is necessary to use custom property editors. For parameters of type Date the annotation @DateFormat may be further used to specify the format of the values to expect.

Domain object may also be set as handler arguments. This requires the mapping between request parameters and form or domain object.


@RequestMapping(value="/url/path")
public String h(Model model, @PathVariable("day") @DateTimeFormat(iso=ISO.DATE) Date day)) {
	 ..
}

A request parameter may be specified as optional by siting attribute required, as follows: @RequestParam(value="param", required=false).

It also possible to get direct access to the request parameters from a HttpServletRequest object. This is done by specifying an argument of the handler method of type HttpServletRequest. Spring Framework automatically passes it to the handler properly initialized.

Request parameters may also be provided by a client as part of the request path, in stead of the query string. The parameter values of this kind may be obtained by using URL templates. This are identified as following: @RequestMapping("/path/{param}"). The sub-string inside {...} is the name assigned to the path segment, and the position of the name in the URL defines which part of the path is being named.

The annotation @PathVariable("param") is used for handler argument so it is initialized with the value of the path segment. As is the case of query string parameters, MVC framework makes the appropriate type conversion between the parameters values and the types of the handler arguments. Direct access to the URL value is also possible by using the methods of HttpServletRequest.

Restrictions on Handler Selection

The selection of a handler method may be restricted to a specific HTTP method code. This is done with attribute method for @RequestMapping annotation. This is further explored in implementing REST services (see section on REST-WS).


//Handles: GET /url/path
@RequestMapping(value="/url/path", method = RequestMethod.GET)
public String get(Model model, ..) { ..
</h3>

//Handles: POST /url/path
@RequestMapping(value="/url/path", method = RequestMethod.POST)
public String post(Model model, ..) { ..
}

The selection of a handler method may also be contingent on the presence of a request parameter and possibly its values. This is done by setting the attribute parms for the annotation @RequestParam(..).


//Handles: /url/path?param1=val
@RequestMapping(value="/url/path", params = {"param1"</b>)
public String h1(Model model) { ... }

//Handles: /url/path?param1=k
@RequestMapping(value="/url/path", params = {"param1=k"</b>)
public String h2(Model model) { ...
}

Autowiring Controllers

Annotation-Driven dependency injection can be used in web-controller to inject references to the services or repositories (DAOs) that the controller depends on. This is illustrate below:


@Controller
public class MyController {
	private MyService service;

	@Autowired
	public MyController(MyService service)  {//dependency injected by type
		this.service = service;
	}
	...
}

Table below summarizes the annotations of Spring MVC discussed so far, and others to be discussed further below.
Annotation Attribute(s) Description
@Controller Declared Controller
@RequestMapping URL pattern Define URL mapping for controllers' request handling methods
@RequestParam (Form) parameter name Argument gets parameter value
@PathVariable path segment Argument gets path segment
@ModelAttribute name of Model and request attribute to set with a domain/form object as value
@ResponseStatus HttpStatus HTTP response status
@ExceptionHandler Throwable Catch and translate exception
@RequestBody get object from HTTP request body
@ResponseBody send object in HTTP response body
@InitBinder Initialization method
MVC annotations in Spring Framework 3.0+

Setting Model Attributes

A model, in the context of MVC, is a map object that is used to store attribute---value pairs of class type Model. A model is created before invoking a handler method if the method has an argument o type Model. The handler uses the model to store attribute values that convey information to render dynamic views such as JSP.

The method Model.addAttribute(String name, Object obj) is used to map attribute names to object as attribute vales. The single argument method, Model.addAttribute(Object obj) automatically generate a name for the stored value. This name follows JavaBeans conventions --- uncapitalizing the short name of the object class name (e.g. pckg.A becomes a; pckg.AbcD becomes abcD; pckg.ABC becomes ABC). For arrays and collections the generated named is suffixed with List (e.g. an object of type ArrayList<A> or A[] is mapped to name aList).

Below, I show a handler method adding an object to the Model object:


@RequestMapping("/base/get")
public String get(@RequestParam("id") long id, Model model) {
	A a = myservice.get(id);	
	model.addAttribute(a);
	model.addAttribute("msg", "...");
	return "someView";
}

When the model is populated with a single object, then the object may be the return value of the handling method if annotation @ModelAttribute is used to annotated the return type. If a value attribute is used with the annotation it is taken as the name of the model attribute.


@RequestMapping("/base/list")
public @ModelAttribute("aList") List<A> list() {
	return aStore.findAll();
}

Controller Registration

A controller may be registered with the DispatcherServlet by defining a bean with the specifying the controller class. This is done in the dispatcher servelet configuration file (not /WEB-INF/web.xml). An example configuration is shown below:


<bean id="myController" class="myapp.MyController">
	<constructor-arg ref="MyService" />
</bean>

Alternatively, controllers may be scan across a packages as follows:


<context:component-scan base-package="myapp"/>

In both approaches, the controller needs to be annotated with @Controller. For component scanning, the MVC namespace tag <mvc:annotation-driven/> should be declared so that @Controller annotations are processed. This tag also instructs MVC to install additional MVC components such as conversion services, validators and HttpMessageConverters.

Testing Controllers

Test web application often require that the application be deployed in a Servlet container. Spring container and injection mechanism provides a comfortable way to test web controller without the need to deploy the controller. This is done by creating an instance of the application controller and calling handler method directly as if HTTP request were being received from the network. Since handlers depend on the a Model argument, the test method should an object that the handler can use. The class BindingAwareModelMap may be used for this purpose. An example is shown below. Method Model.asMap() is used to get a map collection for the attributes so that assertions may be performed on the values.


public class MyControllerTests {
	private MyController ctrl;

	@Before
	public void setUp() throws Exception {
		ctrl = new MyController(new MyDBStub());
	}

	@Test
	public void test1() throws Exception {
		Model model = new BindingAwareModelMap();
		ctrl.list(model);
		List<A> la = (List<A>) model.asMap().get("aList");
		assertEquals(1, la.size());
	}
}

View Technologies

In MVC architectures, the selection of the method to handle a request is logically separated from the selection of the view (the response send to a client). This is argued to increase flexibility, as application logic may select and configure a view on a per-request base.

Views

Spring MVC supports several types of view technologies and content types. The View interface specifies the services provide by a particular combination of view technology and content. A particular class implementation realizes a strategy for rendering. For dynamic view, static template data is combined with dynamic data provided by Model attributes. Below, I show the specification of the View interface. Method render(..) is used to produce the output to a response object using a map of model attributes as dynamic data.


interface View {
	String getContentType(); //get view content-type

	//render the view supported by a model
	void render(Map<String,?> model, HttpServletRequest request, HttpServletResponse response);
}

Abstract class AbstractView may be used to simplify the development of View implementation for specific view technologies and formats. Additional derived classes are also provided for specific technologies and formats, including: AbstractExcelView and AbstractJExcelView for EXCEL, AbstractPdfView for PDF, AbstractFeedView, AbstractUrlBasedView, AbstractXsltView, MappingJacksonJsonView, MarshallingView.

Table below summarizes the view technologies supported by Spring MVC.

View Kind Technology Format View Class ViewResolver
Display JSP (X)HTML/XML JstlView InternalResourceViewResolver
Tiles (X)HTML/XML TilesViewResolver
FreeMarker (X)HTML/XML FreeMarkerViewResolver
Velocity (X)HTML/XML VelocityViewResolver
File-generating POI Excel
jExcelApi Excel
Itext PDF
JasperReports JasperReportsViewResolver
XSLT (X)HTML/XML XsltViewResolver
Data-delivery JSON JSON
Object Marshalling Java Serialization
XML XmlViewResolver
Atom
RSS
View Technologies supported by MVC.
%AbstractCachingViewResolver %AbstractTemplateViewResolver %BeanNameViewResolver %ContentNegotiatingViewResolver %ResourceBundleViewResolver %UrlBasedViewResolver %VelocityLayoutViewResolver

View Selection

Several methods are available to select the view for a particular handler method, namely:

  • The handler method returns a view object of type AbstractView, such as JstlView("/WEB-INF/path/abc.jsp") or new MyPdf(), then the view object is used directly.
  • If the handler method returns a java.lang.String, the value it is interpreted as a logical name or a physical path of a view (e.g. a JSP page). The DispatcherServlet forwards the view name to a ViewResolver to get the file path for the page.
  • If the handler method has no return value or returns null, then conventions are used to generate the view name. The interface RequestToViewNameTranslator is used to realize a particular name generation strategy. The default implementation DefaultRequestToViewNameTranslator, removes hostname and application name, leading slash, and extension from the request URL to generate a view name (e.g http://hostname/webapp/path/page.htm produces view name /path/path). A ViewResolver is applied to the generated view name to get the physical path of the view page.

JSP Views

The common view technology for static content is HTML, while JSP (Java Server Pages) is used for dynamic content. For JSP, model attribute values can be obtained by using the syntax ${attr} or ${attr.field}, where attr is the model variable name, and field is a Java class field for the variable.

An example JSP view to create a dynamic HTML page is shown below. The JSP accesses model variables and its fields to produce dynamic content for the page.


<html>
<head><title>User Details</title></head>	
<body>
The user name = ${user.name}
The id = ${user.id}
The profile = ${user.profile}
</body>
</html>

Configuration Overview

The Spring MVC DispatcherServlet uses several strategy objects to influence the processing of HTTP client requests. Strategy objects are installed in Spring MVC by declaring a bean of the of the respective type. When the DispatcherServlet starts it will check the definition of beans of special recognized types and uses those beans for its configuration. Strategy objects themselves can be configured using usual beans configuration meachanisms of Spring, such as passing constructor arguments and seeting property values.

Configuration Strategies

Table below summarizes the strategy interfaces used by the DispatcherServlet. The table includes reference to the default implementation classes for all strategies.

So to keep the default strategy, when adding a new one, the bean for the default strategy should also be explicitly declared.
Strategy Interface Default Implementation Description
HandlerMapping DefaultAnnotationHandlerMapping Maps request URLs to Controllers based on annotations (@Controller and @RequestMapping)
HandlerAdapter AnnotationMethodHandlerAdapter Invoke handler methods injecting paremeter value based on annotations (@RequestParam and @PathVariable)
ViewResolver InternalResourceViewResolver Maps view names to file paths
HandlerExceptionResolver Maps exceptions to views
Strategy interfaces used in the configuration of Spring MVC DispatcherServlet

In a nutsheel, HandlerMapping is used to map the HTTP client request to some handler method. This is most often done based on some on request URL and the HTTP method, but may also include the request paremeters, request headers, or other custom factors.

HandlerAdapter is to to actually perform the invocation of the handler method. This includes injecting the right parameter values, doing the Java Reflection work to perform the invocation, and processing the return value.

The select default strategy specified above are not hard-wired in the DispatcherServlet code, but rather are defined in a property file: org/springframework/web/servlet/DispatcherServlet.properties. The value in this property file can be overriden directly, but this requires repackaging of Spring MVC. A simpler strategy is to configure beans in the Spring beans configuration file for Spring MVC.

Configuration Chains

Multiple strategy beans of the same kind may be installed, creating a chained infrastructure of beans. When setup in a chain of strategy object of the same base class or interface type, the first bean to return a valid answer will be used.

The order of invocation in the chain may be set with property order. This property is defined in interface Ordered which is implemented by most strategy objects. Most default and pre-shipped strategy implements the Ordered interface, so they can be easily configured in ordered chains. The general rule is that for strategies of the same base type, strategy beans set with a lower order property value are checked first. The default order value for default strategies is 0. To give higer precedence to a custom strategy the order value can be set to a negative value, such as -1s.

Below, I show an example of setting of an orderer chain of HandlerMapping strategies:


<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
	<property name="order" value="0">
</bean>

<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
	<property name="order" value="1">
</bean>

Configuration Support Classes

Table below summarizes further object types that are used by DispatcherServlet and the strategy interfaces.

Support Class Kind Description
HandlerInterceptor interface Intercept/veto handler invocation
HandlerExecutionChain class Aggregates handler and interceptors
ModelAndView class Encapsulates handler response
Support interfaces and classes used in by MVC DispatcherServlet

References and External Resources

MVC XML Namespace

Starting with Spring MVC 3.0, the XML namespace <mvc> may be used to simplify the XML configuration.

<mvc:annotation-driven>

The element <mvc:annotation-driven> is used to automatically install a variety of strategy and supports object. Below, I summarize the kinds of objects installed by <mvc:annotation-driven>.

  • HandlerMapping and HandlerAdapter strategies --- in addition to the default DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter other strategies are also installed
  • Type Conversion, Formatters and Validators
  • MessageConverters --- used to support (un)marshalling of object in REST applications

<mvc:view-controller>

The XML element <mvc:view-controller> is used to directly map a URL path to a view. No controller method is mapped or involved to process the request. This is specially useful to map static web pages, since no model is populated.


<mvc:view-controller path="/" view-name="home"/>

<mvc:resources>


<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>

<mvc:default-servlet-handler>


<mvc:default-servlet-handler/>

Handler Mapping

The HandlerMapping strategy is used to map the HTTP client request to some handler controller and/or method. This is done based on the request URL and the HTTP method, but may also include the request parameters, request headers, or other custom factors.

HandlerMapping Strategy Interface

The interface specification for HandlerMapping is show below:


public interface HandlerMapping {
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

The single method getHandler(.) maps a request object to a execution chain object of type HandlerExecutionChain. The execution chain object wraps the handler (controller or method). It may also contain a set of interceptor objects of type HandlerInterceptor. Each interceptor may veto the execution of the handling request.

Provided HandlerMapping Strategies

Spring MVC support several strategies to map HTTP request to controllers, including: annotation based, name conventions, and explicit mappings. The class DefaultAnnotationHandlerMapping provides the default annotation based mapping strategy. The class BeanNameUrlHandlerMapping is another default strategy that maps URL based on beans names of controllers. The strategy ControllerClassNameHandlerMapping is used to enable class name convention mapping.

To add or replace a HandlerMapping strategy, one or more beans of this type should be declared. By default, Spring MVC install the strategies DefaultAnnotationHandlerMapping and BeanNameUrlHandlerMapping. If a HandlerMapping is declared explictily in the configuration the default handler mapping no longer are installed, unless <mvc:annotation-driven> is specified.

DefaultAnnotationHandlerMapping

The DefaultAnnotationHandlerMapping finds controller class annotated with handler methods @RequestMapping to establish the mapping. The value attribute of the annotation specifies the URL to map to the handler method. A DefaultAnnotationHandlerMapping is installed automatically by Spring MVC, provided that no other HandlerMapping is explicitly specified in the configuration file of the application. If other HandlerMapping are specified it can still be installed by default with <mvc:annotation-driven />.

With the following configuration:


<mvc:annotation-driven />

The following controller will be mapped by DefaultAnnotationHandlerMapping.


@Controller
public class HomeController { 
	@RequestMapping("/")
	void public show() {
	}
}

An alternative and more explicty configuration is:


<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>

<bean class="myapp.web.HomeController" />

BeanNameUrlHandlerMapping

The BeanNameUrlHandlerMapping maps URLs to handlers based on the bean name of controllers. The bean name of the controller should start with a leading '/'. A BeanNameUrlHandlerMapping is installed automatically by Spring MVC, provided that no other HandlerMapping is explicitly specified in the configuration file of the application. If other HandlerMapping are specified it can still be installed by default with <mvc:annotation-driven />.


<mvc:annotation-driven />

<bean name="/welcome.htm" class="myapp.web.HomeController" />

Or more explicitly:


<bean class="org.springframework.web.servlet.handler.<b>BeanNameUrlHandlerMapping</b>"/>

<bean name="/welcome.htm" class="myapp.web.HomeController" />

BeanNameUrlHandlerMapping supports Ant-style patterns in the bean name. Below, are some examples:

<bean name="/show*" class="myapp.web.ShowController" />
<bean name="/account**" class="myapp.web.AccountController" />
<bean name="/product/**" class="myapp.web.ProductController" />

The first controller maps to URLs such as: /show, /showAccount, /showProduct, but not /show/Account. Thw second controller maps to URLs such as: /account, /account/show, and /account/address/show. The third controller maps to /product/, and /product/show, but not /product.

Table below summarizes these examples of mathing and non-matching URLs for the controller defined above (assuming BeanNameUrlHandlerMapping is configured).

Example Controller Pattern in Bean Name Matches No Match
ShowController /show* /show, /showAccount, /showProduct /show/Account
AccountController /account** /account, /account/show, /accounts /Account
ProductController /product/** /product/, /product/show /product
Pattern Matching with BeanNameUrlHandlerMapping

ControllerClassNameHandlerMapping

The ControllerClassNameHandlerMapping maps URL to handlers based on the class name of controllers. Controler classes should be suffixed with the word Controller, such as in HomeController or AccountController. The set of controller beans considered are those annotated with @Controller or that derive from class Controller.

The mapping convention is that the mapped URL is derived from the uncapitalized class name removed from the word Controller. More preciselly, HomeController is mapped to /home*.

ControllerClassNameHandlerMapping needs to be configured explicitly since it is not installed by default by SpringMVC.


<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/> 

The controller class below will be picked up by ControllerClassNameHandlerMapping:


@Controller
public class AccountController { 
	@RequestMapping("/")
	void public show(@RequestParam("id") Long id) {
		...
	}

	@RequestMapping
	void public list() {
		...
	}

}

The handler method show() is mapped to URL such as /account/?id=123, while method list() is mapped to URL /account/list.

Looking to the console output of Spring MVC log is a useful way to check the exact URLs that are setup for a given configuration:


INFO : org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping - Mapped URL path [/account] onto handler 'accountController'
INFO : org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping - Mapped URL path [/account/*] onto handler 'accountController'

The ControllerClassNameHandlerMapping can be used with controller with multiple handler methods, provided the the installed HandlerAdapter know how to deal with this.

SimpleUrlHandlerMapping

The SimpleUrlHandlerMapping provides a way to explicitly map URLs to controller beans by direct configuration. This is done by setting property mappings.


<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
		<props>
			<prop key="/showAccount">AccountController</prop>
			<prop key="/listAccounts">AccountController</prop>
			<prop key="/welcome*">WelcomeController</prop>
		</props>
	</property>
</bean>

The configuration above maps /showAccount and /listAccounts to AccountController, and /welcome* to WelcomeController. Because the Spring bean container (application context) has a PropertyEditor for the type java.util.Propery, the following alternative configuration can also be used:

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
		<value>
			/showAccount = AccountController
			/listAccounts = AccountController
			/welcome* = WelcomeController
		</value>
	</property>
</bean>

References and External Resources

Handler Adapters

The strategy interface HandlerAdapter takes the role of invoking handler methods selected by some HandlerMapping. If a HandlerMapping selects a controller, but not a specific method, then the HandlerAdapter also selects the handler method.

DispatcherServlet invokes controllers through HandlerAdapter strategy objects. This allows for different types of controllers use different method invokation strategies. and URL mapping strategies are possible.

Installing new types of handler invokation strategies requires an appropriate HandlerAdapter bean to be registered. When multiple HandlerAdapter are installed, the DispatcherServlet will invoke all to check the first that supports the handler object provided by the HandlerMapping strategy. The first HandlerAdapter that supports the handler object (controller or method) is used to invoke the handler.

HandlerAdapter Strategy Interface

Below, I show the definition of the HandlerAdapter interface (only key methods):

public interface HandlerAdapter {

	//Check if controller is supported
	boolean supports(Object handler);   

	//handle request
	ModelAndView handle(HttpServletRequest request,  HttpServletResponse response, Object handler) throws Exception;
}

Method supports(.) checks if the HandlerAdapter supports a particular kind of controller. The handler argument is initialized with the object returned by the HandlerMapping strategy. Method handle(..) handles a particular HTTP request, returning a ModelAndView as the result of the handler invocation

Available HandlerAdapter Strategies

Spring MVC supports several types of controllers, including: annotation defined controllers (with @Controller), the WebFlow FlowExecutor, and Adobe BlazeDS MessageBroker.

AnnotationMethodHandlerAdapter

AnnotationMethodHandlerAdapter adapts HTTP requests to handler methods annotated with @RequestMapping. It introspects required input arguments for handlers, and interprets output values. This the HandlerAdapter configured by default.

The AnnotationMethodHandlerAdapter can be used with controller with multiple handler methods in a variety of powerful ways. Below, I show how method is used to desambiguate among handler methods:


@Controller
@RequestMapping("/account")
public class AccountController { 
@RequestMapping
void public show() { //maps from: /account/show
...
}

@RequestMapping
void public create() { //maps from: /account/create
...
}  
}

Desambiguation can also be done by HTTP request method as show below:


@Controller
@RequestMapping("/account")
public class AccountController { 
	@RequestMapping(method=RequestMethod.GET)
	void public show() {					 //maps from: GET /account
		...
	}

	@RequestMapping(method=RequestMethod.POST)
	void public create() { 					//maps from: POST /account
		...
	}  
}

A more subtle desambiguation approach is show below:

@Controller
@RequestMapping("/account")
public class AccountController { 
	@RequestMapping("/")
	void public show() { //maps from: GET /account/
		...
	}

	void public list() { //maps from: POST /account
	...
	}  
}

AnnotationMethodHandlerAdapter allow handler methods to have flexible signature, including the type, ordering and number of arguments. Several types are recognized and injected automatically. Table below summarizes the types of objects that are recognized and passed values.

Type Description Created By
Model Map of attributes and values Spring MVC
HttpServletRequest HTTP Request Servlet Container
HttpServletResponse HTTP Response Servlet Container
HttpSession HTTP Session Servlet Container
Locale Request preferred locale Servlet Container
Principal User identify Servlet Container
SessionStatus Session status Spring MVC
WebDataBinder Data-binding and validation control Spring MVC
(domain object) subject to data-binding Spring MVC or application
Argument types of handler methods recognized by AnnotationMethodHandlerAdapter.

Handler Interceptors

The HandlerInterceptor interface defines the type of objects to be inserted in a HandlerExecutionChain, to intercept and possibly veto handler method execution. HandlerInterceptor objects are particularly useful when the same functionality need to be applied to a set of controller and/or handler methods. Possible applications include: add common model attributes (e.g.preferences, layout menus configuration); set response headers; audit requests; and measure the performance of request handling (e.g. to compare controller vs. rendering time).

The definition of interface HandlerInterceptor is shown below:


public interface HandlerInterceptor {

	//invoked before controller handler invocation
	boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	//invoked after controller handler invocation
	void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception;

	//invoked after view rendering
	void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
}

Method preHandle(..) is invoked before a handler is invoked. It may perform custom pre-processing on the request and produce some response. It it returns true it will veto/cancel the invocation of the handler, since the DispatcherServlet assumes that the request was already handled by the interceptor.

Method postHandle(..) is invoked after a handler is invoked but before the view is rendered to the response object. A ModelAndView object is provided, that contains the view name returned by the handlers, and a map with all attributes and values set in the handler model.

Method afterCompletion(..) is invoked after the handler is invoked and the view is rendered.

A HandlerInterceptor is similar to a Filter as specified in the Servlet2.5 API, in that it is invoked just before a request is handled by the application. HandlerInterceptor are somewhat more limited since a Filter may exchange the request and response objects handed down a filter/interception chain. A HandlerInterceptor simply allows custom per-processing and post-processing, with the option of vetoing the execution of the handler. Note also, that Filter objects are configured in the application deployment descriptor WEB-INF/web.xml while HandlerInterceptor are configured in the MVC application context.

Configuration of Handler Interceptors

Handler interceptors are installed in a HandlerMapping by setting the property interceptors with a list object. The tag <list> may be used to specify the property value as a set of anonymous beans.


<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
	<property name="interceptors">
		<list>
			<bean class="pckg.MyInterceptor1"/>
			<bean class="pckg.MyInterceptor2"/>
		</list>
	</property>
</bean>

Interceptors may also be installed globally using the mvc namespace tag <mvc:interceptors>. Interceptor beans declared inside this tag are applied to all handler mappings


<mvc:interceptors>
	<bean class="pckg.MyInterceptor1"/>
	<bean class="pckg.MyInterceptor2"/>
</mvc:interceptors>

View Resolvers

A ViewResolver is a strategy and factory object used to map logical view names to actual view resources. The interface for ViewResolver is shown below. The single method resolveViewName(..) maps a logical view name together with the request locale to a View instance.


public interface ViewResolver {
	View resolveViewName(String viewName, Locale locale);
}

The default view resolver implementation is of type InternalResourceViewResolver that treats the view name as a application-relative path to a JSP file. It creates view of type JstlView. Registering a ViewResolver is done by defining a bean to be found by the DispatcherServlet, in the MVC configuration file.

An example of configuring a InternalResourceViewResolver is shown below. Properties prefix and suffix are use to specify how view logical names are mapped to actual JSP files. With the settings below a view named abc is mapped to file path /WEB-INF/views/abc.jsp.


<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/WEB-INF/views/" />
	<property name="suffix" value=".jsp" />
</bean>

Applications may also register new ViewResolver instances. The advantage of allowing configuration of a ViewResolver is the ability to switch between viewing technologies, without changing the controllers implementation.

Direct View Access

Some views don't need a controller and views may delivered directly. The tag <mvc:view-controller> is used to declare such as view. The attribute path specifies the URL to resolve, and attribute view-name specifies the view resource on the application file tree. An example is shown below:


<mvc:view-controller path="/login" view-name="/WEB-INF/login.jsp"/>
<mvc:view-controller path="/welcome" view-name="/WEB-INF/welcome.jsp"/>

Exception Handling

Exception Resolver

During the execution of controller handler, exceptions may by thrown (Throwable instances, more precisely). The MVC strategy interface HandlerExceptionResolver is responsible to provided adequate treatment to exceptions. It selects an error view, possibly based on exception type and request information, and prepares a Model if the error view contains dynamic information.

The specification for the interface HandlerExceptionResolver is shown below. The single method resolveException(..) is invoked to handle the exception passed as argument. It returns a ModelAndView with the name and model attributes for the error view. If returns null then a HTTP status/error code is sent as response.


public interface ViewResolver {
	ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}

Error views are analogous to the error page JSPs defined with directive @page. MVC error pages, however, provide more fine-grained mappings possibly contingent on exception type, handler type, and request information. It can also be used with any kind of exception including checked exceptions.

Built-in Strategies

SimpleMappingExceptionResolver is an implementation of HandlerExceptionResolver that maps exception class names to view names. It also add a model attribute named exception with the thrown exception object as value. It also logs a message for each exception occurrence.

SimpleMappingExceptionResolver may be configured with a set of property. Property exceptionMappings is set with a Map that has entries mapping exception class names to view names. The property defaultErrorView is the view name for exceptions not explicitly mapped. The property defaultSatusCode is the HTTP status/error code sent in a response when the exception resolution does not provide a view (method resolveException returns null).


<bean class="org.springframework.web...SimpleMappingExceptionResolver">
	<property name="exceptionMappings">
<map>
	<entry key="DataAccessException" value="databaseError"/>
	<entry key="RuntimeException" value="internalError"/>
</map>
</property>
	<property name="defaultErrorView" value="error"/>
	<property name="defaultStatusCode" value="500"/>
</bean>

Custom Strategies

SimpleMappingExceptionResolver may also be used as a base to implement custom exception resolving strategies. Method getModelAndView(..) may be override to add additional model attributes to be accessed by view page. (The base implementation only populates the model with a single attribute exception.) Method buildLogMessage(..) may also be overridden to use custom log messages.


public class MyExceptionResolver extends SimpleMappingExceptionResolver {

	protected String buildLogMessage(Exception e, HttpServletRequest req) {
		return "My log message...";
	}

	protected ModelAndView getModelAndView(String viewName, Exception e) {
		ModelAndView mv = super.getModelAndView(viewName, e);

		// Add model attributes for the error view
		mv.add(...);
		return mv;
	}
}

Exception Handling Methods

An alternative or additional approach to deal with exceptions, is to annotated specific controller methods with @ExceptionHandler. Methods with a matching exception type (in the controller serving the request), are invoked to handle thrown exceptions. Like request handlers, exception handlers may have flexible signatures so that is easy to access request information and response stream.

Messages and Internationalization (i18n)

Views often need to externalized text messages, such as error codes, and provide internationalization support. Spring MVC supports the standard Java resource bundle to access locale-specific text messages in property files.

Java Resource Bundles

A ResourceBundle is the Java abstraction to get locale-specific resources such as objects and text strings. A ResourceBundle has a backing file-system artifact such as a Java class file or a properties files. Class files allow getting arbitrary locale-specific objects, while property files are specific to map message keys to locale-specific messages.

ResourceBundle are organized in families, such that each bundle in the family should provide about the same resources but in a locale-specific way. A Locale specifies the language, country, and variation for resources. Each ResourceBundle family has a basename that is used to generate the location and names of file-system artifacts. For example, if a family is named myMessages then for locale EN (for the english language), the properties file for this family and locale will be named myMessages_en.properties.

The file extention used is .class for class files, and .properties for property files. For each of generated name, a class file is first search for and then a properties files.

In Java a localized resource bundle can be obtained with one of several static methods, as shown below:


Locale locale = ...
ResourceBundle resources = ResourceBundle.getBundle("myMessages", locale);

Obtained ResourceBundle are also organied in parent-child relationships. Parent ResourceBundle are more generic, while child ResourceBundle are more specific to locale setting. If a resource can not be resolved in a ResourceBundle, then its parent its checked for the same resource name. All ancestors are checked until resolution is possible or no more ResourceBundle are available.

If current locale setting are (language1, country1, and variant1) and the default locale is (language0, country0, and variant0), then following the artifacts names (plus extention) are search for:

  • baseName + "_" + language1 + "_" + country1 + "_" + variant1
  • baseName + "_" + language1 + "_" + country1
  • baseName + "_" + language1
  • baseName + "_" + language0 + "_" + country0 + "_" + variant0
  • baseName + "_" + language0 + "_" + country0
  • baseName + "_" + language0
  • baseName

MessageSource

A MessageSource is the Spring MVC abstraction to resolves locale-specific messages. The provided implementations wrap the ResourceBundle abstraction of Java. By convention, a bean implementing MessageSource should have name messageSource when setup in an application context.

Below, I shown selected methods of the interface MessageSource.


public interface MessageSource {
	//Resolve message based on arguments
	String getMessage(String code, Object[] args, Locale loc);
	String getMessage(String code, Object[] args, String defaultMsg, Locale loc);

	String getMessage(MessageSourceResolvable rslv, Locale loc);
	...
}

Methods getMessage() are used to resolve message from messages codes. Messages are returned as plain String. An array of object arguments can also be provided to replace positional argument markers such as {0}. A default message may also be specified, and be used when resolution of the message code is not possible using available resource bundles. The Locale argument localizes the returned message.

An alternative way to resolve message is to provide a MessageSourceResolvable. This interface allow an array of alternative code to be used, according to preference order. The API for MessageSourceResolvable is shown below:


public interface MessageSourceResolvable {
	//Get array of codes/keys in order of decreasing preference
	String[] getCodes();

	//Argument for message resolutoin
	Object[] getArguments();

	//Get default message
	String getDefaultMessage();  
}

Built-in Strategies

The class ResourceBundleMessageSource is provided as a MessageSource implementation. The property basenames takes a list of basenames for resource bundle families. Below, I show a typical configuration of a ResourceBundleMessageSource.


<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basenames">
		<list>
			<value>/WEB-INF/messages/msg<value/>
		</list>
	</property>
</bean>

In the example, /WEB-INF/messages/msg is used as basename for the resource bundle family. For a english language locale, the basename is transformed in file path /WEB-INF/messages/msgs_en by adding suffix _en. For other language a similar transformation applies (e.g.fr for French, es for Spanish, pt for Portuguese).

An alternative implementation of a MessageSource is class ReloadableResourceBundleMessageSource. This class automatically reloads messages from resource bundles, according to a setup policy. The property cacheSeconds is used to specify the time (in seconds) a loaded resource bundle is kept before checking for a new reload. A value of -1 keeps resource bundle cached forever. A value of 1 or more is recommended for good performance in message resolution. This class also accepts file base prefixes in basenames (e.g. classpath:, file:).

Resolving Messages in Java


@Controller
public class MyController {
	private MessageSource msgSrc;

	@Autowired
	public void AccountsController(MessageSource msgSrc) {
		this.msgSrc = msgSrc;
	}

	@InitBinder
	public String initBinder(WebDataBinder binder, Locale loc) {
		String datePat = msgSrc.getMessage("date.pattern", null, "MM-dd-yyyy", loc);
		...
	}
}

Resolving Messages from JSP

A MessageSource is accessed from JSP file using JSTL tag library for formating messages. As follows:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<fmt:message key="mymsgs.welcome"/>
<fmt:message key="mymsgs.msg2"/>

Layout and View Composition Overview

Pages in web application often follow a common layout structures and share elements for parts of the layout. The layout structure specifies where the page elements are placed relative to each other and the overall page, and their relative or absolute sizes. The shared elements allow reused of design solutions across pages, and provide a consistent appearance and a intuitive navigation experience to the application. Typical shared elements include: header, footer, navigation menu, and decoration elements such as frames and backgrounds. At least one part of a layout need to be changed across pages, typically the main content part. Other components such as menus explodes, may also vary across pages.

Tiles Integration

Spring MVC provides support for configuring and using Tiles in a simple way.

Configuring Tiles

Class TilesConfigurer is used to bootstrap Tiles from a set of Tiles configuration files. It is installed by defining a bean of this class in the MVC XML configuration file. Property definitions takes a list of strings with names of Tiles configuration files. Each such file will declared a set of Tiles definitions.


<bean id="tilesConfig" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
	<property name="definitions">
		<list>
			<value>/WEB-INF/tiles.xml</value>
			<value>/WEB-INF/myapp/tiles.xml</value>
		</list>
	</property>
</bean>

Views

Class TilesView defines a MVC View that interprets logical view names as Tiles definition files. A TilesViewResolver should also be installed in replacement for the default InternalResourceViewResolver.


<bean class="org.springframework.web.servlet.view.tiles2.TilesViewResolver"/>
	<property name="prefix" value="/WEB-INF/"/>
	<property name="suffix" value=".jsp"/>
</bean>

Form Processing

Data forms are UI components that allow a use to providing information in input widgets to be processed by an application. In the context of distributed application, the processing of form data is often mostly by a server since it depends to resources stored at the server. For web application, data form are presented as widgets inside browser windows. The most used technology to visualize form at the client side is HTTP Form, although other technologies are possible.

HTML Forms

HTML Forms are implemented with the tag <form> and specific input widgets are inserted an sub-tags. The tag <form> takes required attributes action that specifies a relative or absolute URL for the resources that handles the form data. Attribute method specifies the HTTP method to send in the request. Current HTTP specification, requires method POST to be provided. A special command widget is activated by the user to send the form data to the web server. Section below reviews the structure and tags used in HTML forms.


<form method="POST" action="url-path">
	<!-- input and command widgets -->
</form>

Form Processing Workflow

A form editing starts with an initial HTTP GET to the web server to present the form. Often, it is desirable that form be filled up with values previously provided by the user, or default value if it is the first time the user will filling up the form. This process of fill form values at the server side before sending the form page to a client is known as form data binding.

HTML/HTTP Form Processing Workflow

When a user completes form editing or otherwise submits the form to the specified URL, form data is send to the client in some way. For HTTP and web applications, the standard way to do this is send send data as request parameters chained together in a query string --- as the trailing part of the request URL. The general format of a URL is as follows:

http://<host>:<port><request pab>?{query}

The query string where form data is encoded follow the following syntax:

param1=value1,param2=value2,...

When a server receive form data, the web application usually applies the form/request parameters to the properties of local bean object. Since parameter values are encoded as text strings and and bean properties are typed, the server need to perform conversion and validation of the data provided by the user.

Binding
The process of mapping form (query/request) parameters to properties in an form or domain object. Allows an object or object tree to be initialezed withou manually lookup of each individual parameter and property.
Conversion
The process of transforming the string representation of individual parameters to typed values before initializing an object property. A conversion service or a custom conversion method can be used.
Validation
The process of checking if the individual properties and overall state of an object respects the constraints imposed by the application and domain. (e.g. min and max string size, minimum password size, numeric ranges, non-empty values, or if time-date is valid and well formated). Validation is performed after the binding and conversion.

If request parameters are successfully binded, converted and validated, the form data may be further processed. This often involves saving the information in persistent database, either to update information or create new data records.

If conversion or validation fails, is desirable that the user is informed of this. This involves resending the form page to the user, possibly with error message mingled with input widgets at points where data conversion or validation failed.

On success, the user browser or application is redirected to a confirmation page. (POST-Redirect-GET).

Search form may have a different treatment as they do not change server state, i.e. the request does not have side-effects. Thus, HTTP GET method may be used to present and submit the form with the search criteria. The result layout may also be depends on search results. If the result consists of a single hit, then a redirect may be send directly to the found resource. If multiple hits where found, then a dynamic page should render and link to the result hits.

Form Objects

Form objects are the applications object (e.g. Java Beans) that are updated or created whenever a form is submitted and the request is successfully validated. Domain objects (a.k.a. business objects, in the context of enterprise applications) may be used directly as used as form object. This, however, may posse potential security concern. One must be careful in specifying what properties or fields are allowed to be bound to request parameter during data binding. User permission may be have to be taken in consideration. Domain objects need also follow bean convention (i.e. mandatory default constructor, and property getters and setters). This may also be problematic if domain objects pre-exist to the development of the web layer. Additionally, domain object may be blotted with information relevant with information related to the web.

An alternative approach is to use dedicated form objects that map to domain objects. This is particularly useful when the content of form pages differs significantly from domain objects. For example, forms data may aggregate and refer multiple domain domain objects, only a small subset of the fields is required, or form object need to be adapted to UI-specific needs. With dedicated form objects web integration concerns, such as presentation details, conversion, and validation, are made separated from the rest of the application. Form objects will also implement the logic to copy or convert information from domains object to the form representation.

Form TagLib

The Spring MVC provides a custom JSP tag library, to simplify building form pages. The features of this tag lib include: populate HTML form fields with formatted values, render field-specific error messages, and simulate form submits with HTTP PUT or DELETE.

Importing the Form TagLib

To use the form tag library the standard JSP <@taglib> directive should be used. Its common practice to used the prefix <form> for this library.

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

Form Tag

Tag <form:form> tag, replaces html tag form. It takes the addition attribute <modelAttribute> which is the name of the form object whose properties are used to populate the form. It may specify any attribute added to the Model object by the controller handler that selects the form view.


<form:form method="POST" action="url-path" modelAttribute="a">
	...
</form:form>

Text Input and Output Tags

The tag <form:input> is used for text input, and replaces the HTML tag input. It introduces the extra attribute path that specifies the field or field path to be accessed, relative to the form model object (specified in modelAttribute). It is similar to the attribute value in HTML, however in JSP/HTML a EL or JSP expression is specified accessing a data bean or variable introduced by a custom tag. This is the basic mechanism used for data binding from domain objects to form values.


<form:input path="prop1" />


<hidden />
<label />
<password />
<textarea />

Multi-Option Selection Tags

Multiple option selection is declared with tag <form:select>. This tag is usually rendered as a combo-box. As in the <form:input>, the attribute path specifies the field or field path of the model object. Individual options are declared with tag <form:option>. Attribute label specifies the text rendered for the option. The attribute value specifies the corresponding value in the form object. When the tag is translated to HTML tag <option>, the attribute selected is inserted automatically based on the value of the path variable as returned by the controller handler.


<form:select path="a">
	<form:option label="5" value="5" />
	<form:option label="10" value="10" />
</form:select>

The set of option to select may also be discovered from a collection model attribute.

<form:select path="la" items="${aList}" itemLabel="name" itemValue="number" />

Boolean check-boxes are inserted with tag <checkbox>.

<checkbox />
<checkboxes />

Multi-Option selection with radiobuttons is defined with tag <radiobox>.

<radiobutton />
<radiobuttons />

Error Handling

<form:errors> tag

Table below summarizes the tags and attributes of the Spring MVC form tag lib.

Tag <form:* Attributes Description
<form> method|action (all input tags) Form Definition
modelAttribute
<input> path Single-Line text input
<label> Text Label
<password> Password Entry
<textarea> Multi-line text editing area
<hidden> Hidden variable
<select> path|items|itemLabel|itemValue <option> Multi-option selection
<option> label|value Selection Item
<checkbox> Boolean checkbox
<checkboxes> Set of Boolean checkboxs
<radiobutton> Radio Button
<radiobuttons> Set of radio buttons
<errors> Error message
Summary of tags and attributes for the Spring MVC form taglib <form>.

Other Tags

<spring:url/> tag is a replacement for JSTL <c:url> tag. It allows the creation of template URLs, with encoded URI variables.

<spring:url value="/users/{id}">
<spring:param name="user" value="${users.id}" />
</spring:url>

Simulating PUT/DELETE HTTP Methods in Forms

Spring MVC form tag library allows forms to be specified with HTTP methods PUT/DELETE. This is done by generating a HTTP form that uses method POST, but includes an additional hidden parameter for the original HTTP method. The reserved parameter named _method is used in a hidden text field.

The Spring MVC form below:


<form:form method="PUT" action=".." modelAttribute="..">
...
</form:form>

It transformed to a HTML form:

<form method="POST" action="...">
<input type="hidden" name="_method" value="PUT" />
...
</form>

Additionally, a filter of type HiddenHttpMethodFilter needs to be installed to intercept POST requests and transform them back to the original HTTP method. This explained in the next section.

URL Rewriting

A filter of type HiddenHttpMethodFilter needs to be installed to intercept POST requests and transform them back to the original HTTP method. The Filter works by modifying the HttpServletRequest, when a query strings contains parameter _method with values. If values PUT or DELETE are specified the request HTTP method is modified accordingly. Below, I show the declaration in the application deployment file to install the filter WEB-INF/web.xml.


<filter>
	<filter-name>hiddenMethodFilter</filter-name>
	<filter-class>
		org.springframework.web.filter.HiddenHttpMethodFilter
	</filter-class>
</filter>

Type Conversion and Formating

Type conversions occurs when rendering form values, or when binding HTTP request values to a form object. Previous versions of Spring MVC relied on java.beans.PropertyEditor for type conversion and data-binding. However, this was abandoned since this objects are state-full and don't use generics. Spring MVC 3.0 introduces a new type conversion system as an alternative based on Formatters objects.

Formatters

Formatters convert values of any Object type to and from a String.

Generic interface Printer<T> defines method print(..) to convert from a form object field value to a String. Generic interface Parser<T> defines method parse(..) to perform the reserve operation of transforming a String value to a field type value. Interface Parser<T> inherits and combines the two interfaces. All interfaces are defined in package org.springframework.context.


public interface Formatter<T> extends Printer<T>, Parser<T> {}

public interface Printer<T> {
	String print(T fieldValue, Locale locale);
}

public interface Parser<T> {
	T parse(String clientValue, Locale locale) throws ParseException;
}

Formating Annotations

Formatters may be assigned to properties of form objects by using annotations. The annotation may be applied to controller method arguments and form object fields. Table below summarizes the build-in Formatter and respective annotations.

Formatter Annotation Description
NumberFormatter @NumberFormat Numerics Formating
DateFormatter @DateTimeFormat Time-Date Formating
CurrencyFormatter Currency Formating
PercentFormatter Percent Formating
Formatter Annotations.

Custom Formatters

It is also possible to define and install custom formatter implementations:


public class MyFormatter<T> implements Formatter<T> {
	public String print(T value, Locale locale) {
		...
	}

	public T parse(String s, Locale locale) throws ParseException {
		 ...
	}
}

A set of custom formatter is registration using a FormattingConversionServiceFactoryBean:

public class MyFormattingConversionService extends FormattingConversionServiceFactoryBean {
	protected void installFormatters(FormatterRegistry reg) {
		super.installFormatters(reg);
		//resister custom formatters
		Formater formater = ..
		reg.register(formater)
	}
}

A conversion service should be pluged-in using the MVC custom namespace.


<mvc:annotation-driven conversionService="myConversionService"/>

<bean id="myConversionService" class="com.acme.myapp.MyFormattingConversionService" />

The bean definition for the conversion service can be made optional if its definition is annoted with @Component.

Formatting Annotations

One of the best features of the new type conversion is the ability to use annotations for a better control over formatting in a concise manner. Annotations can be placed on model attributes and on arguments of @Controller methods that are mapped to requests. Out of the box Spring provides two annotations NumberFormat and DateTimeFormat but you can create your own and have them registered along with the associated formatting logic. You can see examples of the DateTimeFormat annotation in the Spring Travel and in the Petcare along with other samples in the Spring Samples repository.

The @DateTimeFormat annotation implies use of Joda Time. If that is present on the classpath the use of this annotation is enabled automatically. By default neither Spring MVC nor Web Flow register any other date formatters or converters. Therefore it is important for applications to register a custom formatter to specify the default way for printing and parsing dates. The @DateTimeFormat annotation on the other hand provides more fine-grained control where it is necessary to deviate from the default.

Data Binding

Field Names as EL Expressions

Spring MVC binds request parameters to the form objects by converting strings values to field values. Request parameters names may specify a field name or, more generally, and EL expression to access a field relative to the form base model object. EL expression are useful to access fields of form objects that are collections such as java.util.List or java.util.Map. Below, I show some examples of EL expressions used in accessing collection fields.


public class A {
	String name;	//(SP)EL: name
	
	int id;	//EL: id 
	
	Map<String, A> m;	//(SP)EL: m["abc"].name
	
	List<A> l;	//(SP)EL: l["abc"].id
}

Binding to Handler Arguments

HTTP request parameters are bound to form or domain objects, by specifying an argument of that object type in a handler method. DispatcherServlet and its strategies ensure that the form object is created, initialized, and passed as argument. If some request parameter can not be bound to an object field an exception is raised and the handler method is not invoked. The annotation @ModelAttribute may optionally be applied to the input argument to specify the model attribute name (specified in the attribute modelAttribute of MVC tag <form:form>). If not specified, it is assumed a name according to JavaBeans property name conventions.

Below, I shown an example controller with two form handlers and form objects bound to request parameters. Note that HTTP method PUT is specified.


@Controller
public class MyController {
	@RequestMapping(method=RequestMethod.PUT)
	public String handle1(A a) { 
		...
	}
	
	@RequestMapping(method=RequestMethod.PUT)
	public String handle2(@ModelAttribute("a") A a) {
		...
	}
}

Control of Field Data Binding

It possible to establish an access control policy to bind of fields in form and domain objects. Namely, fields may be disallowed and allowed for data binding on an individual bases. This is useful as an integrity constraint and security measure. This is done my annotating a method of a controller with @InitBinder. Such methods are invoked on controller initialization and get injected with argument of type WebDataBinder. Method setAllowedFields(..) declares the set of fields or properties that are allowed to be bound to request argument. Method setAllowedFields(..) declares the set of field not allowed in data binding. These methods take a variable argument list of field names or wild-card patterns to apply to field names.


@InitBinder
public void initBinder(WebDataBinder binder) {
	binder.setAllowedFields("prop1", "prop2", ...);
	binder.setDisallowedFields("id", "*Id"); //wild-card pattern
}

Handling Data Binding Errors

It is possible to get information about the outcome of the data binding process by specifying an argument of type BindingResult in controller handlers. If this the case, then a binding error does not result in an exception. The specification of this interface and its parent interface is shown below (only a small sub-set of methods is presented). Method Errors.hasErrors() is used to find if any error occurred. Details of errors can be obtained with method getAllErrors().


public interface Errors {
	List<ObjectError> getAllErrors(); 	//Get all Errors
	
	int getErrorCount();
	
	boolean hasErrors(); 
	...
</h3>

public interface BindingResult extends Errors {
...
}

Below, I shown an example of a controller handler queering a BindingResult object passed as argument.


@RequestMapping(method=RequestMethod.PUT)
public String h(A a, BindingResult br) {
if (br.hasErrors()) { 
return "a/edit";  //page in case of errors
}
...
}

Data Binding Errors Tags and Messages

Errors message may be rendered in a JSP page with tag <form:errors>.

<form:form modelAttribute="a">
<form:input path="name"/>
<form:errors path="a"/>
</form:form>

Customize Binding Error Messages

Messages relative to data binding errors (rendered with <form:errors>) may be configured with property files. The key Type Mismatch is holds the value for the generic binding error message. Binding errors for specific fields, sub-fields, or types are specified with matching suffixes on key name. To the error messages property file it should be configured into the installed application MessageSource. The generic file format and content is illustrated below:


//All type conversion errors
typeMismatch = Invalid value
//Type conversion errors for a named field or sub-field
typeMismatch.a = Invalid value
typeMismatch.a.b = Invalid value
//Type conversion errors for all field of a Type
typeMismatch.A = Invalid A field value

Data Validation

During validation values bound to field of form data objects are checked for value conditions. Annotations are used to specifiy what Validator and arguments should be applied to each field. Spring MVC 3.0 supports the Java standard for Bean Validation JSR 303. Hibernate Validator is the reference implementation, and is used by Spring MVC. Both API and implementation must be on the classpath of the application for it to be used.

MVC tag <mvc:annotation-driven> automatically registers a bean of type LocalValidatorFactoryBean. This bean enables JSR-303 in Spring MVC. (Hibernated Validator dependencies JAR files must be on the classpath.)

Validation Annotations

Table below summarizes most used annotations to specify Validation. The last table column indicates if an annotations is specified in standard JSR 303 or if is specific to Hibernated Validator.

Annotation Type(s) Description JSR 303
@NotNull Object Field cannot be null Yes
@Size(min, max) String Field must have length in range [min,max] Yes
@Min Numeric Field minimum value Yes
@Max Numeric Field maximum value Yes
@Pattern String Field matches pattern Yes
@NotEmpty Object Field length is non-zero No
Validation Annotations.

Below, I show an example domain or form class with validation annotations:


import javax.validation.constraints.*;

public class Account {

	@Pattern(regexp="[a-zA-Z]*")
	@Size(min=1, max=128) 
	private String name;

	@Pattern(regexp="d{16</b>")
	private String code;

	@Size(min=1)
	private String about;

	@Min(0)
	private double balance;

	@NotNull
	private Date lastLogin;
}

Validating Request Parameters

To validate a request parameter, the annotation @Valid is specified in the corresponding handler method argument.


@RequestMapping(method=RequestMethod.PUT)
public String h(@Valid A a, BindingResult br) {
if (br.hasErrors()) {
return "form-error-view";
}
...
}

Validation errors, like data binding errors, are registered in the BindingResult object. A single BindingResult is used and combines these two types of errors. It may be reference as an handler argument.

Customize Validation Error Messages

Messages relative to validation errors (rendered with <form:errors>) may be configured with property files. Similarly to data binding error messages, the property file it should be configured into the installed application MessageSource. For each validation annotation there is a corresponding key in the property file that may be set for an error message. Validation error for specific fields, sub-fields, or types are specified with matching suffixes on key name. A example is shown below:


//@NotNull validation failure for all types
NotNull = Required value
//@NotNull validation failure for a named field or sub-field
NotNull.a = Required a value
NotNull.a.b = Required b value
//@NotNull validation failure for all fields of a Type
NotNull.A = Required A value

//@Size, @Min, and @Max validation failure for all types
Size = Invalid Size
Min = Value out-of-bound
Max = Value out-of-bound

//Other Validator
Pattern = Invalid Pattern
NotEmpty = Empty value not allowed

Custom Validation

Custom validators and validation annotation may be defined via JSR-303 constraint annotations. Custom annotations may be specified at the field or class-level.

Custom validation may also be specified through Spring MVC, by regestering a validator in WebDataBinder.


@InitBinder
public void initBinder(WebDataBinder binder) {
	binder.setValidator(new MyValidator());
}

It also possible to perform validation explicitly in handler methods. As follows:


@Controller
public class MyController {
	AValidator av = new AValidator();

	@RequestMapping(method=RequestMethod.PUT)
	public String h(A a, BindingResult br) {
		if (!v.validateA(a, br)) {
			return "form-error-view";
		}
		...
	}

	void validate(A a, BindingResult bindingResult) {
		if (!av.validateProp1(a.prop1)) {
			bindingResult.rejectValue("prop1", "error.code1");    
		}
		...
	}
}

Form Object Management

A Form workflow includes getting the initial form page (with method GET) and one or more submissions (with method POST). At the server side, this requires access to respective form object. It is useful that objects be shared across the form workflow. Form objects may also shared between requests from the same user, to keep user provided information.

There are a few alternative approaches to manage the form object. The simplest solution is to create it on every form request. The limitation of this approach is that a form needs to contains all required data. Below, I show an example:


@Controller
public class MyController {

	@RequestMapping(method=RequestMethod.GET)
	public String formNew(Model model) {
		model.add(new A()); //Create a new object form initial GET
	}

	@RequestMapping(value="/path/form", method=RequestMethod.POST)
		public String formSubmit(A a) { ... }
	}
}

A form object may also be create on first request and retrieve from following requests. Spring MVC annotation @ModelAttribute is useful here, since a method annotated @ModelAttribute is invoked before any handler to add the return value as a model attribute. A form object may then be returned as value get from a database repository. This works well when editing existing object and persistence is required.


@Controller
public class MyController {

	@ModelAttribute
	public A addToModel(@PathVariable String name) {
		return db.find(name);
	}
	...
}

Finally, a form object may be stored in as a session scoped attribute. Thus, be accessed between requests. This performs better than using database access, but doesn't scale as well since session state is stored in memory. Below, I shown an example of this approach. Note the use of a SessionStatus object and method setComplete() used to discard session objects when a form is successfully submitted.


@Controller
@SessionAttributes("a")
public class MyController {
	@RequestMapping(method=RequestMethod.GET)
	public String formNew(Model model, String id) {
		//Create a new object form initial GET
		model.add(db.find(id));
	}

	@RequestMapping(method=RequestMethod.POST)
	public String formSubmit(A a, SessionStatus status) {
		db.update(a);
		status.setComplete(); //discard session object(s)
	}
}

Themes

Themes define the general look-and-feel of web pages, including the style, images, and in some cases some aspects of the layout. In Spring MVC themes are supported by a combination of three mechanisms: theme-aware resource bundles; theme resolvers; and theme change interceptor.

Mapping Theme Names to Resource Bundles

When a WebApplicationContext starts it looks for a bean named themeSource implementing the interface ThemeSource. A ThemeSource is basically a selector that maps theme names to MessageSource.

The default implementation for the ThemeSource a ResourceBundleThemeSource, that selects a different property file for each theme. An instance of ResourceBundleThemeSource is created automatically by the WebApplicationContext. So, unless special configuration is required, this should be good enough.

The ResourceBundleThemeSource strategy to resolve theme-aware message names is to look for theme-specific property file. This file should be located by default in the root of the class path /WEB-INF/classes. Each theme has it own dedicate property file. So if an application has support a theme named fantasy and another called serene, then the files /WEB-INF/classes/fantasy.properties and /WEB-INF/classes/serene.properties are expected to be available. ResourceBundleThemeSource will selected a property file and resolve messages according to preferences of each user at the time of the request.

Storing Theme Information

Theme specific information includes in the most cases stylesheet and image file location. In some cases it may also include the location of shared components used in page layout such as header, footer, or menu. The approach used by ResourceBundleThemeSource is to look for theme information in property file storing key=value pairs.

Below, I show an example of a property file for a theme named fantasy:


#Theme: fantasy
styleGlobal = /themes/fantasy/style/global.css
styleLocal = /themes/fantasy/style/local.css
banner = /themes/fantasy/img/banner.png
footer = /themes/fantasy/jspx/footer.jspx

Theme Resolvers

In addition to a bean named themeSource, the WebApplicationContext also searches for a bean named themeResolver. This bean should implement the interface ThemeResolver. A ThemeResolver can be queried about the name of the current theme, and configured based on the current HttpServeltRequest. Concrete implementation use different strategies to update the current theme. The default implementation is FixedThemeResolver that change theme name only is set explicitly. For pratical porpurses the implementation SessionThemeResolver or CookieThemeResolver should be used.

Below, I show an example configuration of CookieThemeResolver.


<bean id="themeResolver" class="org.springframework.web.servlet.theme.CookieThemeResolver">
	<property name="defaultThemeName" value="fantasy"/>
	<property name="cookieMaxAge" value="3600"/>
</bean>

The property defaultThemeName sets the default theme name, and property cookieMaxAge specifies the maximum time the cookie THEME is kept alive.

Table below summarizes the available implementations of ThemeResolver.

ThemeResolver Description
FixedThemeResolver Updates theme name only if explicitly asked (property defaultThemeName)
CookieThemeResolver Updates theme name from Http cookie (named THEME)
SessionThemeResolver Saves and updates theme name in a session attribute
Implementations of ThemeResolver.

Theme Change Interceptor

To use a ThemeSource and ThemeResolver effectively some other bean needs to actively set the current theme. The class ThemeChangeInterceptor does this by checking the Http Request parameters. By default, it will look for the parameter named theme. A bean instance of ThemeChangeInterceptor should be explicitly defined as a Spring MVC interceptor:


<mvc:interceptors>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
</mvc:interceptors>

Getting Theme Information

A RequestContext object is used throughout Spring MVC to make information available to view. To make an instance of this object avaiable the property requestContextAttribute should be set on the used ViewResolver. Below, I show an example with InternalResourceViewResolver:


<bean id="themeResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="requestContextAttribute" value="requestContext"/>
</bean>

Below, I show an example of a JSP page fragement that has a link to switch between themes based on the current theme name:


<c:choose>
	<c:when test="${requestContext.theme.name == 'fantasy'}">
		<a href="?theme=serene">Serene</a>
	</c:when>
	<c:otherwise>
		<a href="?theme=fantasy">Fantasy</a> 
	</c:otherwise>
</c:choose>

Using Themes

The JSP tag <spring:theme> can be used to resolve keys to messages according to the current theme. <spring:theme> was similiar behavior as <fmt:message> except that resource bundle to used depends on the current theme.

Locales

Locale Resolvers

Locale Change Interceptor


<mvc:interceptors>
	<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>

Using Locales


1 Comment

12/16/14

Post Your Comment

Login (or Register)
Contribute Feedback