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.
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
The following steps should be done to fully implement and deploy a Spring Framework-MVC based web application service:
DispatcherServlet
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.
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>
Although most web application are most likely to use the Spring MVC front-end Servlet
, in is possible for application to write their own Servlet
s. 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 Servlet
s 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(...);
...
}
}
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
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.
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
.
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.
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. This is is explained in detail in section dedicated to forms.
@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
.
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, ..) { ..
//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"`)
public String h1(Model model) { ... }
//Handles: /url/path?param1=k
@RequestMapping(value="/url/path", params = {"param1=k"`)
public String h2(Model model) { ...
}
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+
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();
}
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
.
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());
}
}
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.
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 | ||||
JasperReports | JasperReportsViewResolver | |||
XSLT | (X)HTML/XML | XsltViewResolver | ||
Data-delivery | JSON | JSON | ||
Object Marshalling | Java Serialization | |||
XML | XmlViewResolver | |||
Atom | ||||
RSS |
View Technologies supported by MVC.
Several methods are available to select the view for a particular handler method, namely:
AbstractView
, such as JstlView("/WEB-INF/path/abc.jsp")
or new MyPdf()
, then the view object is used directly.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.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.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>
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.
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.
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>
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
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>
.
DefaultAnnotationHandlerMapping
and AnnotationMethodHandlerAdapter
other strategies are also installed<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/>
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.
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.
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.
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.`BeanNameUrlHandlerMapping`
<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``
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.
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>
BeanNameUrlHandlerMapping
exampleControllerClassNameHandlerMapping
Configure the handler mapping priority
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.
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
HandlerAdapter
StrategiesSpring MVC supports several types of controllers, including: annotation defined controllers (with @Controller
), the WebFlow FlowExecutor, and Adobe BlazeDS MessageBroker.
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() { //URI: /account/show
...
}
@RequestMapping
void public create() { //URI: /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
.
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.
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>
<bean class="pckg.MyInterceptor2"></bean>
</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>
<bean class="pckg.MyInterceptor2"></bean>
</mvc:interceptors>
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.
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" />
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.
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>
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;
}
}
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.
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.
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
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();
}
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:
).
@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);
...
}
}
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" />
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.
Spring MVC provides support for configuring and using Tiles in a simple way.
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>
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>
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 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>
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.
![](form-processing.png" style="width:600px 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.
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 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.
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.
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" %>
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>
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 />
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 />
Table below summarizes the tags and attributes of the Spring MVC form
tag lib.
Tag <form:*> | Attributes | Sub-Tags | 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 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>
.
<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>
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.
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 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 convert values of any Object
type to and from a String
.
Printer<T>
defines method print(..)
to convert from a form object field value to a String
.Parser<T>
defines method parse(..)
to perform the reserve operation of transforming a String
value to a field type value.Parser<T>
inherits and combines the two interfaces.All these 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;
}
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.
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
.
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.
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
}
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) {
...
}
}
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
}
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();
...
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
}
...
}
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>
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
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.)
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`")
private String code;
@Size(min=1)
private String about;
@Min(0)
private double balance;
@NotNull
private Date lastLogin;
}
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.
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 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 registering 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");
}
...
}
}
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 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.
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.
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
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
.
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>
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>
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.
Comments and Discussion