You are on page 1of 12

10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.

html
Sponsored by:

This story appeared on JavaWorld at


http://www.javaworld.com/javaworld/jw-04-2009/jw-04-springmvc.html

Mastering Spring MVC


Enjoy Spring-based Web development with the Spring MVC module
By Steven Haines, JavaWorld.com, 04/28/09

Model-View-Controller Web frameworks for Java are plentiful, and most of them integrate with Spring, but the tightest integration can be found in Spring's own MVC
module. Get started with Spring MVC in this introductory article by Steven Haines, who begins with a history of the Model-View-Controller paradigm in Java Web
development. He then introduces the Spring Framework and explains how it leverages the concepts of Spring, including dependency injection. Finally, Steven guides you
through a programming tutorial that demonstrates the core features of Spring MVC in an easy-to-follow, hands-on format. Level: Beginner

In the ongoing evolution of Java EE technologies, the Spring Framework has emerged as a top choice for the middle, or business tier of enterprise application development.
Spring's lightweight paradigm for developing enterprise applications has won it a large following that today rivals that of the standard Java EE platform. As a result, most
MVC (Model-View-Controller) Web frameworks integrate with Spring, including Spring's in-house module, Spring MVC. If you're developing Spring applications for the
Web, familiarity with Spring MVC will help you step up your game while also leveraging all the familiar benefits of the Spring Framework.

The MVC framework landscape

Java Web developers can choose from numerous MVC frameworks, including Struts, Wicket, JavaServer Faces (JSF), Seam, and Spring MVC, introduced in this article.

To provide a context for understanding Spring MVC, I'll start with a brief history of Java Web applications, followed by an overview of the Spring Framework and its
business value. I'll then introduce Spring MVC and walk you through a development project: a mini content-management system (CMS) that demonstrates how to build and
deploy a Spring MVC application. You can download the source code any time.

Java Web applications: A brief history


This brief history begins with Java's entry into Web application development: the Servlet API, introduced in 1997. Before then, developing dynamic Web applications with
disparate APIs and programming models proved to be challenging. (I'll resist the urge to recap the old days of CGI, the futile battle between Netscape Server plug-ins and
ISAPI plug-ins, and all the homegrown APIs.) The Servlet API provided a standard on which vendors could build Web containers and developers could implement a simple
programming model for constructing Web pages.

With servlets, dynamically constructing HTML documents became easy. But because the documents were constructed inside Java source code, maintenance was challenging.
For example, changing a font or moving a piece of content within a page required you to update the HTML inside the servlet code and then recompile and redeploy it to the
container.

Sun resolved this issue in 1999 by introducing JavaServer Pages (JSP). Rather than implementing presentation code inside servlets, JSPs lets you build HTML-like documents
that interweave snippets of Java code to support dynamic content. At runtime, JSPs are translated to servlet source code, compiled, and then deployed to a Web container
dynamically. If you change any part of the JSP, the container detects the change, recompiles the page, and redeploys it. This architecture was called page-driven or Model 1.

In page-driven applications, each page not only contains the business logic required to generate the dynamic content, but also the control logic to determine application flow.
Control logic became difficult to maintain because there was no central location or design paradigm to help you understand how a user passed from one page to the next. And
as business requirements evolved to include features like authentication and authorization, page code became convoluted with additional logic that usually had to be
duplicated across pages, even if it was irrelevant to the page being constructed. On a site with 1,000 pages, all with authorization mechanisms, who wants to update all 1,000
pages when those authorization mechanisms change?

The solution was to separate programmatic responsibilities into the technologies best suited for them. Servlets are great for writing Java code, acting as a central point for
managing application flow and invoking business methods, but horrible at presentation; JSPs are great at presentation but are a horrible place to embed all of your business
logic. Thus was born the Model 2 architecture, which adheres to the MVC Smalltalk design pattern:

The model represents your data or the objects with which your application is interacting.
The view is a visualization of your model.
The controller manages application flow and makes calls into business objects.

In Java systems, the model is typically a loose JavaBean, or Plain Old Java Object (POJO) that has getters and setters to manipulate its contents. It can be a very simple object
or a very complicated one with dozens of subobjects, but it's just an object nonetheless.

The view is usually a JSP page, but countless other technologies and templating languages can be used, such as FreeMarker, Velocity, XML/XSLT, JasperReports, and so on.
After the business logic is complete and the model has been generated, the controller passes the model to the view to be presented to the user.

The controller is typically implemented by a servlet that calls into business services to perform some action. The controller usually hosts additional logic such as authentication
and authorization: it controls which actions a user can execute. For example, you might not allow a user who hasn't first logged in to post a message to a message board. If the
controller notices that the user is trying to access the "post" page, it redirects the user to a login page first.

In a Spring MVC architecture, you implement controllers that make calls into Spring service beans to perform business actions and then send a model object to one of your
views for presentation. But I'm getting a bit ahead of myself. First we'll do a quick high-level review of Spring.

Spring: An overview
During the early days of Enterprise JavaBeans (EJB), developers led by Rod Johnson created the Spring Framework as a lightweight alternative to Java EE's complexity.
Spring is many things -- entire books have been written about it -- but one of the key benefits that it pioneered is dependency injection (DI). DI is a design pattern, coined by

www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 1/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html
Martin Fowler, that separates an application's dependencies (and dependency configuration) from the code that uses those dependencies. Spring implements DI by allowing
you to "wire" together an application from beans, using either an XML configuration file or annotations. For example, if your application needs to access a database, you can
configure your database connection pool in a Spring configuration file and tell Spring to "inject" a DataSourcefrom that pool into your data-access object (DAO) bean; then
you can inject that DAO into a service bean. The point is that your application should focus on solving its business problems rather than on the overhead required to construct
resources and objects. Spring creates your objects for you and makes them available at runtime.

Another important point to understand about DI is how your objects are written. Consider a service bean that accesses a DAO object for data persistence:

public class MyService {


private MyDao dao;
public void setMyDao( MyDao dao ) {
this.dao = dao;
}
public Widget businessMethod() {
return dao.doBusinessThing();
}
}

In traditional applications you would probably create a DAO factory object that, through a configuration file, creates the appropriate instance of the DAO on your behalf. In
this example, Spring creates the correct MyDaoinstance (as you define it in the configuration file), creates the MyServiceobject, and invokes the setMyDao()method to inject
the DAO into the service. You write your application assuming that the DAO object is valid and is the correct implementation. Your service bean should not be concerned
with creating the DAO object, but rather with invoking the correct method on the DAO object to accomplish the business objective.

The core business value in adopting Spring is the separation between code and configuration, which leads to a more manageable application.

Introducing Spring MVC


The aptly named Spring MVC is a full MVC implementation that follows the patterns and paradigms that Spring is known for, including DI. Spring provides a front controller
servlet named DispatcherServlet. To build an application, you construct the following components:

One or more controllers that invoke business logic and create a ModelAndViewobject
A visualization component such as a JSP
XML or annotation configuration to wire the components together

Spring provides various controllers for you to use as base classes for creating your own controllers, depending on your needs. Among them are ones that:

Redirect to static views


Provide basic servlet-like functionality
Process commands
Process shared actions
Handle forms
Provide wizard-like functionality to process multipage forms

The rest of this article will be a hands-on introduction to Spring MVC, by way of a programming exercise. Together, we'll build a CMS that presents a list of articles, allows
users to read articles, and allows users to post new articles. It's simple, but it demonstrates how to use a basic controller that accepts no parameters, a command controller that
accepts the identifier of an article to display, and a form controller that processes an article submission.

Listing 1 shows the source code for the homepage controller. This simple controller accepts no request parameters and returns a ModelAndViewobject that contains a list of
news articles.

Listing 1. HomePageController.java

package com.geekcap.geeknews.web;

import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import com.geekcap.geeknews.core.GeekNewsService;
import com.geekcap.geeknews.core.NewsArticle;

/**
* The HomePageController is responsible for building the model of data to display
* on the home page, which at this point contains a list of article overviews.
*
* @author shaines
*
*/
public class HomePageController extends AbstractController {
/**
* Provides access to GeekNews business methods
*/
private GeekNewsService service;

/**
* Responsible for translating a web request into a ModelAndView object for presentation
*/
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse res) throws Exception {

// Use the service to load the articles


List<NewsArticle> articles = service.getArticleOverviews();

// Send the articles to the "home" view


return new ModelAndView( "home", "articles", articles );
}

/**
* Injected by Spring
www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 2/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html
* Injected by Spring
* @param service
*/
public void setGeekNewsService( GeekNewsService service ) {
this.service = service;
}
}

The HomePageControllerextends Spring's AbstractController, which provides simple servlet-like functionality. It implements a single method --
handleRequestInternal()-- which accepts HttpServletRequestand HttpServletResponseobjects, just as a servlet's service()method would. You could read
parameters from the HttpServletRequest, but later I'll show you an easier alternative. The purpose of the AbstractControlleris to invoke business functionality and to
generate a ModelAndViewobject from it.

In MVC vernacular, the model and view are separate entities, so you might wonder why a ModelAndViewobject seemingly pairs the two. In Spring MVC, the ModelAndView
object is a container that hosts the model and provides insight to Spring's view resolver about how to locate the view. In the HomePageController, the ModelAndViewis
created with three parameters:

"home": The message that is sent to the view resolver to tell it to show the page identified by home(which I'll explain below).
"articles": An identifier for the model. When the view receives the model, it will be able to access it in the request through the "articles"key.
articles: The model itself.

The business logic, in this case, is delegated to the GeekNewsService, which Spring injects after it creates the HomePageController(shown below).

With the HomePageControllerbuilt and a service bean that can be used to access back-end data, let's review the configuration of a Spring MVC application to observe how
a request arrives at the Web container and then makes its way to the controller.

The primary entry point for a Spring application is the DispatcherServlet, so this first step is to create a DispatcherServletin the web.xmlfile:
<servlet>
<servlet-name>geeknews</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

Next, that DispatcherServletneeds to be mapped to a URI pattern. You can choose any pattern that you want, but most Spring applications map requests to pages ending
in .htm. Add the following to your web.xmlfile:
<servlet-mapping>
<servlet-name>geeknews</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>

In this case, all requests that end in .htmwill be sent to the geeknewsDispatcherServlet. By default, Spring looks for your Spring beans in a file whose name starts with
the servlet name followed by -servlet.xml. So we need to create a geeknews-servlet.xmlfile that contains the HomePageController, our URL mapping strategy (to
map URLs to controllers), and our view resolver, and place it in the WEB-INFdirectory. Listing 2 shows the contents of the geeknews-servlet.xmlfile.

Listing 2. geeknews-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">


<property name="mappings">
<props>
<prop key="/home.htm">homePageController</prop>
</props>
</property>
</bean>

<bean id="homePageController" class="com.geekcap.geeknews.web.HomePageController">


<property name="geekNewsService" ref="geekNewsService" />
</bean>

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">


<property name="prefix">
<value>/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>

The geeknews-servlet.xmlfile defines the HomePageControllerwith the name homePageController. It injects the geekNewsServicebean (as a reference, which
means this is not a Stringvalue, but rather a reference to another bean) into its geekNewsServiceattribute. The geekNewsServicebean is created in the geeknews-
service.xmlfile (discussed below). In addition to defining the homePageController, the geeknews-servlet.xmlfile defines the urlMappingbean and the
viewResolverbean.

The urlMappingbean is responsible for translating a URL pattern to a controller. There are several URL mappers:

BeanNameUrlHandlerMapping: Maps a URL to a bean based on the name of the controller's bean, as defined in the bean's XML definition.
SimpleUrlHandlerMapping: Maps a URL to a bean based on a list of properties. (In Listing 2, the SimpleUrlHandlerMappingclass is used to map /home.htmto the
www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 3/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html
bean with the ID of homePageController.)
ControllerClassNameHandlerMapping: Maps a URL to a bean based on the bean's class name. For example, HomePageControllerwould be mapped to
/homePage*, such as /home.htm.
ControllerBeanNameHandlerMapping: Similar to the BeanNameUrlHandlerMappingmapper, but does not expect bean names to follow the URL convention. Also
supports Controllerannotations.
CommonsPathMapHandlerMapping: Maps URLs to a controller based on Jakarta Commons Attributes metadata.
DefaultAnnotationHandlerMapping: Maps URLs to a controller for methods that implement the RequestMappingannotation.

The view resolver is responsible for translating the view name in the ModelAndViewinto a component, such as a JSP, that renders the view. The several available view
resolvers are mostly based on the type of view they are forwarding to. View resolvers exist for FreeMarker, Jasper Reports, Velocity, XML, XSLT, and of course JSPs via
URL paths. Listing 2 defines the InternalResourceViewResolver, which prefixes the view name with /and suffixes it with .jsp. Thus when the HomePageController
returns the view name home, it is resolved to /home.jsp.

Putting it all together:

1. The DispatcherServlethandles all requests that end in .htm, so it handles /home.htm.


2. The SimpleUrlHandlerMappingmaps /home.htmto the HomePageController.
3. The HomePageControllerloads a list of articles from the GeekNewsServiceand returns those articles in a ModelAndViewobject whose destination is home.
4. The InternalResourceViewResolverprefixes homewith /and suffixes it with .jsp, which means that it is forwarded to /home.jspfor presentation.

Listing 3 shows the complete web.xmlfile.

Listing 3. web.xml

<?xml version="1.0" encoding="UTF-8"?>


<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"
version="2.4">

<display-name>SpringMVC</display-name>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/geeknews-services.xml
/WEB-INF/geeknews-dao.xml
</param-value>
</context-param>

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

<servlet>
<servlet-name>geeknews</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>geeknews</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>

<taglib>
<taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/tld/c.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>http://java.sun.com/jstl/fmt</taglib-uri>
<taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
</taglib>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

</web-app>

The DispatcherServletautomatically loads the geeknews-servlet.xmlfile, but when you build Spring applications it's a good practice to divide bean XML files into
their logical components. In Listing 3, the contextConfigLocationcontext parameter defines two additional Spring XML files that should be loaded: geeknews-
services.xmland geeknews-dao.xml. The ContextLoaderListenerclass is responsible for loading resources and reads the contextConfigLocationparameter to
determine which configuration files to load. Finally, the web.xmlfile imports two components of the Java Standard Tag Library (JSTL) that will be used in the JSP file.

Listing 4 shows the source code for the home.jspfile.

Listing 4. home.jsp

<?xml version="1.0" encoding="UTF-8" ?>


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="com.geekcap.geeknews.core.*,java.util.List"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Geek News</title>
www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 4/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html
<title>Geek News</title>
<link type="text/css" rel="stylesheet" href="css/geeknews.css" />
</head>

<body>

<%@ include file="header.jsp" %>

<div id="mainContent">

<p><a href="post.htm">Post</a></p>

<c:forEach items="${articles}" var="article">

<div class="article">
<p><a href="article.htm?id=<c:out value="${article.id}"/>"><c:out value="${article.title}" /></a>
by <span class="articleAuthor"><c:out value="${article.author}" /></span>
on <span class="articleDate"><fmt:formatDate value="${article.date}" type="both" /></span>
</p>

<p class="articleSummary"><c:out value="${article.summary}" /></p>


</div>

</c:forEach>

</div>

<%@ include file="footer.jsp" %>

</body>
</html>

The details of the HTML and CSS presentation are unimportant for this discussion; what's important is that the request object has an articlesvariable in it. The following
snippet demonstrates how the JSTL core library is used to iterate over all articles and display an article's author, title, publication date, and summary:
<c:forEach items="${articles}" var="article">

<p><a href="article.htm?id=<c:out value="${article.id}"/>">


<c:out value="${article.title}" /></a>

by <c:out value="${article.author}" />


on <fmt:formatDate value="${article.date}" type="both" />
</p>

<p class="articleSummary"><c:out value="${article.summary}" /></p>

</c:forEach>

Figure 1 shows a screenshot of the Geek News homepage.

Figure 1. Geek News home page (Click to enlarge.)

The header consists of the words GEEK NEWS, hyperlinked to the home page. The body consists of a Post link, which brings up a form (which you'll implement later) for
posting new articles, and then one section for each article that includes the title, author, publication date, and summary, followed by a horizontal line (implemented as a CSS
bottom border on the article <div>). A footer (not shown) has copyright information (for "Fictitious Company," so don't worry, the code is yours to keep).

The header and footer are imported in the home.jsppage through the JSP includedirective. They are both JSPs themselves. In their current state, they could be simple
HTML documents, but in the future you might want to add a login link to the header or administration links to the footer.

Setup and deployment


Before you can compile and deploy the HomePageController, you need to download, decompress, and install the latest Spring Framework version (as of this writing,
version 2.5.6) and its dependencies.

Spring partitions its functionality into several JARfiles, so your WARfile can include only the functionality you need. It's up to you to track down all of the JARfiles that you do
need. The sample application needs the following Spring resources in its WEB-INF/libfolder, which you can find in Spring's dist/modulesdirectory:

spring-beans.jar
spring-context.jar
spring-core.jar
spring-web.jar
spring-webmvc.jar

It also needs these resources, located in Spring's libsubdirectories:

commons-codec.jar(lib/jakarta-commons)
commons-logging.jar(lib/jakarta-commons)

www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 5/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html
jstl.jar(lib/j2ee)
standard.jar(lib/jakarta-taglibs)
log4j-1.2.15.jar(lib/log4j)

Finally, the Daoclass uses JDOM, so you need to download JDOM. Then add jdom.jar(in JDOM's builddirectory) and xerces.jar(in JDOM's libdirectory) to your
WARfile.

With these JARfiles in your CLASSPATH, you can compile the sample application with the Ant build.xmlfile included in the source-code download. This file loads a
build.propertiesfile that defines the following properties (which you must update to match your environment):

tomcat.home: The location where you have Tomcat installed; if you want to use a different application server then you may need to update the build.xmlfile to
include the JARfile that contains the Servlet API..
jdom.home: The location where you have JDOM 1.1 installed
spring.home: The location where you have Spring installed.

In the end your WARfile should contain the following files:


index.html
article.jsp
footer.jsp
header.jsp
home.jsp
post.jsp
postSuccess.jsp
css/geeknews.css
images/articlebackground.jpg
images/blockquotebackground.gif
images/codebackground.gif
WEB-INF/web.xml
WEB-INF/geeknews-dao.xml
WEB-INF/geeknews-services.xml
WEB-INF/geeknews-servlet.xml
WEB-INF/classes/log4j.properties
WEB-INF/classes/com/geekcap/geeknews/core/GeekNewsService.class
WEB-INF/classes/com/geekcap/geeknews/core/NewsArticle.class
WEB-INF/classes/com/geekcap/geeknews/dao/FileSystemNewsArticleDaoImpl.class
WEB-INF/classes/com/geekcap/geeknews/dao/NewsArticleDao.class
WEB-INF/classes/com/geekcap/geeknews/web/HomePageController.class
WEB-INF/classes/com/geekcap/geeknews/web/LoadArticleController.class
WEB-INF/classes/com/geekcap/geeknews/web/PostArticleFormController.class
WEB-INF/classes/com/geekcap/geeknews/web/command/ArticleCommand.class
WEB-INF/classes/com/geekcap/geeknews/web/validator/NewsArticleValidator.class
WEB-INF/lib/commons-codec.jar
WEB-INF/lib/commons-logging.jar
WEB-INF/lib/jdom.jar
WEB-INF/lib/jstl.jar
WEB-INF/lib/log4j-1.2.15.jar
WEB-INF/lib/spring-beans.jar
WEB-INF/lib/spring-context.jar
WEB-INF/lib/spring-core.jar
WEB-INF/lib/spring-web.jar
WEB-INF/lib/spring-webmvc.jar
WEB-INF/lib/standard.jar
WEB-INF/lib/xerces.jar
WEB-INF/tld/c.tld
WEB-INF/tld/fmt.tld
WEB-INF/tld/fn.tld
WEB-INF/tld/permittedTaglibs.tld
WEB-INF/tld/scriptfree.tld
WEB-INF/tld/sql.tld
WEB-INF/tld/x.tld

If you're running Tomcat, you can deploy the application by invoking the Ant deploytarget in the project build script. The deploytarget copies the WARfile to Tomcat's
webappsdirectory.

Start Tomcat, open your Web browser, and open http://localhost:8080/GeekNews/home.htm. Or you can exclude home.htmfrom the URL to invoke the index.html
file, which automatically redirects you to the home page.

To make the example clearer, I decided to store articles in XML files in the directory of your choice, rather than in a database. To make it work properly, you must create an
article directory and update the articleDirectoryproperty defined on the newsArticleDaobean in the geeknews-dao.xmlfile. When you first launch the application, it
won't have any content. So, after you build the source code for the entire project, click on Post and complete the form (the date needs to be of the format: MM/DD/YYYY
HH:MM AM or PM, for example: "03/10/2009 09:00 PM"). The content will be dropped right onto the Web page, so you are free to use HTML markup such as <p>,
<blockquote>, <pre>, <code>, and so forth. I don't recommend adding extra <html>or <div>tags, but the basics work.

Adding more controllers


The HomePageControllerthat you've finished building is essential for the mini-CMS application, but it's only a start. The full application also needs a controller that
responds to request parameters, and one for submitting content. Next you'll build the LoadArticleController, which responds to a single request parameter; after that,
you'll implement the form controller for article submissions.

Command controllers
The LoadArticleControlleraccepts a single request parameter -- id-- and uses the GeekNewsServiceto load the contents of the article that has that identifier. Looking
back at the HomePageController, you could simply obtain the idparameter from the request object as you would do in a servlet:

String id = ( String )request.getAttribute( "id" );

But Spring provides a more elegant controller that obtains that parameter (and any others you need) from the request, in the form of a command object. Listing 5 shows a
command object that wraps the idattribute.
www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 6/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html
Listing 5. ArticleCommand.java

package com.geekcap.geeknews.web.command;

public class ArticleCommand {

private String id;

public ArticleCommand() {
}

public ArticleCommand(String id) {


this.id = id;
}

public String getId() {


return id;
}

public void setId(String id) {


this.id = id;
}
}

ArticleCommandis a simple POJO with a single parameter: id. When the POJO is paired with the appropriate controller type, Spring examines the request and tries to
populate each field in the POJO. For a single parameter this might seem like overkill, but if you had 10 parameters of varying types, you would otherwise need to extract them
manually as Stringsand convert them to the appropriate types. You might as well take advantage of Spring's capability to do this for you.

Listing 6 shows the source code for the LoadArticleController.

Listing 6. LoadArticleController.java

package com.geekcap.geeknews.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractCommandController;
import com.geekcap.geeknews.core.GeekNewsService;
import com.geekcap.geeknews.core.NewsArticle;
import com.geekcap.geeknews.web.command.ArticleCommand;

public class LoadArticleController extends AbstractCommandController {

/**
* Provides access to GeekNews business methods
*/
private GeekNewsService service;

public LoadArticleController() {
setCommandName( "article" );
setCommandClass( ArticleCommand.class );
}

@Override
protected ModelAndView handle(HttpServletRequest req, HttpServletResponse res, Object command, BindException errors ) throws Exception {

// Load our article command


ArticleCommand articleCommand = ( ArticleCommand )command;

// Load the article from the GeekNewsService


NewsArticle article = service.getArticle( articleCommand.getId() );

// Build and return our ModelAndView


return new ModelAndView( "article", "article", article );
}

/**
* Injected by Spring
* @param service
*/
public void setGeekNewsService( GeekNewsService service ) {
this.service = service;
}
}

LoadArticleControllerextends Spring's AbstractCommandController. In two steps, you configure AbstractCommandControllerto auto-populate the command
POJO of your choice:

1. In the constructor, call setCommandClass()and pass it the command's Classobject. The additional call to setCommandName()makes the command object available
to the view, in the model, under the specified name.
2. Implement the handle()method. The handle()method includes a command object that can be cast to your command class.

Now, the GeekNewsServicecan be invoked to find the article with the specified identifier by calling the command's getId()method.

The LoadArticleControlleris defined in the Spring XML configuration file in much the same way as the homePageController: define the bean with the injected
GeekNewsServiceand add it to the urlMapping:

<bean id="loadArticleController" class="com.geekcap.geeknews.web.LoadArticleController">


<property name="geekNewsService" ref="geekNewsService" />
</bean>

www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 7/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/home.htm">homePageController</prop>
<prop key="/article.htm">loadArticleController</prop>
</props>
</property>
</bean>

The LoadArticleControllerreturns a NewsArticleobject in the model, which is redirected to the "article" page. Recall that the view resolver prefixes articlewith /
and suffixes it with .jsp, so the view page can be found at /article.jsp. The article.jsppage -- shown in Listing 7 -- is similar to the home.jsppage, except that it
shows only one article and displays its content rather than its summary.

Listing 7. article.jsp

<?xml version="1.0" encoding="UTF-8" ?>


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="com.geekcap.geeknews.core.*,java.util.List"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Article: <c:out value="${article.title}" /></title>
<link type="text/css" rel="stylesheet" href="css/geeknews.css" />
</head>

<body>

<%@ include file="header.jsp" %>

<div id="mainContent">

<p><a href="home.htm">Home</a></p>

<div id="articleContentHeading">

<h2><c:out value="${article.title}" /></h2>


<p>By <span class="articleAuthor"><c:out value="${article.author}" /></span>
on <span class="articleDate"><fmt:formatDate value="${article.date}" type="both" /></span>
</p>

</div>

<div id="articleContent">
<c:out value="${article.content}" escapeXml="false" />
</div>

</div>

<%@ include file="footer.jsp" %>

</body>
</html>

Figure 2 shows a screen shot of the article page.

Figure 2. Reading a Geek News article

Form controllers
Now you'll build the PostArticleFormController, which handles a form posting, complete with simple form validation. Figure 3 shows a screen shot of the Geek News
article-submission page.

www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 8/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html

Figure 3. Posting a Geek News article

The submission page prompts the user for an article title, author, submission date, summary, and content (with HTML markup). It is backed by a NewsArticleobject, which
is a POJO that wraps these parameters, shown in Listing 8.

Listing 8. NewsArticle.java

package com.geekcap.geeknews.core;

import java.util.Date;

public class NewsArticle implements Comparable {

private String id;


private String title;
private String author;
private String summary;
private String content;
private Date date;

public NewsArticle() {

public NewsArticle(String title, String author, Date date, String summary, String content ) {

this.title = title;
this.author = author;
this.summary = summary;
this.content = content;
this.date = date;
}

public NewsArticle(String id, String title, String author, Date date, String summary, String content) {

this.id = id;
this.title = title;
this.author = author;
this.date = date;
this.summary = summary;
this.content = content;
}

public String getId() {


return id;
}

public void setId(String id) {


this.id = id;
}

public String getTitle() {


return title;
}

public void setTitle(String title) {


this.title = title;
}

public String getAuthor() {


return author;
}

public void setAuthor(String author) {


this.author = author;
}

public Date getDate() {


return date;
}

public void setDate(Date date) {


this.date = date;
}

www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 9/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html

public String getSummary() {


return summary;
}

public void setSummary(String summary) {


this.summary = summary;
}

public String getContent() {


return content;
}

public void setContent(String content) {


this.content = content;
}

/**
* Sorts article by descending dates
*/
public int compareTo(Object o) {

// Comparing the other date to ours should order descending


int result = ( ( NewsArticle )o ).getDate().compareTo( date );
if( result == 0 ) {
// Ensure that we don't lose any articles that have the same date
return 1;
}
return result;
}
}

The NewsArticleclass is a straightforward POJO. The only thing unusual about it is that it is Comparableand implements the compareTo()method. This enables articles to
be sorted by their date, from most recent to least recent.

Listing 9 shows the source code for the PostArticleFormController.

Listing 9. PostArticleFormController.java

package com.geekcap.geeknews.web;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.validation.BindException;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

import com.geekcap.geeknews.core.GeekNewsService;
import com.geekcap.geeknews.core.NewsArticle;

public class PostArticleFormController extends SimpleFormController {

/**
* Provides access to GeekNews business methods
*/
private GeekNewsService service;

public PostArticleFormController() {
setCommandClass( NewsArticle.class );
setCommandName( "newsArticle" );
}

protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {


SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy hh:mm aa");
binder.registerCustomEditor(Date.class, new CustomDateEditor(format, true));
}

protected ModelAndView onSubmit(Object command, BindException bindException) throws Exception {

NewsArticle article = ( NewsArticle )command;

service.addArticle( article );

return new ModelAndView( getSuccessView() );


}

/**
* Injected by Spring
* @param service
*/
public void setGeekNewsService( GeekNewsService service ) {
this.service = service;
}
}

The PostArticleFormControllerextends Spring's SimpleFormControllerand registers the NewsArticleas its command class, which in turn will be the container for its
form data. The SimpleFormControllerclass behaves differently depending on whether the Web request sent to it is a GET or a POST. If the request is a GET, it redirects
the request to the form to be completed. If the request is a POST, the form object (NewsArticlein this example) is optionally validated and then passed as the command
object to the onSubmit()method. In the PostArticleFormController, the onSubmit()method, knowing that its article is valid, simply invokes the GeekNewsService's
addArticle()method to add the article to the CMS repository and then returns a ModelAndViewobject that references the getSuccessView()view.

www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 10/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html
The SimpleFormControllerdefines two views: the form view and the success view. Users who have not successfully completed the form are redirected to the form view,
otherwise, on successful submission, they are redirected to the success view. The form and success views are defined in the XML bean definition:
<bean id="postArticleFormController" class="com.geekcap.geeknews.web.PostArticleFormController">
<property name="formView" value="post" />
<property name="successView" value="postSuccess" />
<property name="geekNewsService" ref="geekNewsService" />
<property name="validator">
<bean class="com.geekcap.geeknews.web.validator.NewsArticleValidator" />
</property>
</bean>

Understanding how the view resolver works, you can probably already determine that the form view resolves to /post.jspand the success view resolves to
/postSuccess.jsp. The GeekNewsServiceis injected as usual, but there is a new property: validator. The validator defines a class that's responsible for validating the
command object (NewsArticlein this example.) Listing 10 shows NewsArticleValidator's source code.

Listing 10. NewsArticleValidator.java

package com.geekcap.geeknews.web.validator;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.geekcap.geeknews.core.NewsArticle;

public class NewsArticleValidator implements Validator {

@Override
public boolean supports( Class clazz ) {
return clazz.equals( NewsArticle.class );
}

@Override
public void validate( Object command, Errors errors ) {

NewsArticle article = ( NewsArticle )command;

// Validate required fields


ValidationUtils.rejectIfEmptyOrWhitespace( errors, "title", "article.missingTitle", "A title must be specified" );
ValidationUtils.rejectIfEmptyOrWhitespace( errors, "author", "article.missingAuthor", "An author must be specified" );
ValidationUtils.rejectIfEmptyOrWhitespace( errors, "summary", "article.missingSummary", "A summary must be specified" );
ValidationUtils.rejectIfEmptyOrWhitespace( errors, "content", "article.missingContent", "Content must be specified" );

}
}

Validators must report the classes that they validate through the supports()method. The NewsArticleValidatorcompares the class passed to it with the NewsArticle
class. If the classes are the same, then it returns true, meaning that Spring can safely invoke validate()on this validator, passing it a NewsArticle.

The NewsArticleValidatorperforms only simple validation checking to see if the title, author, summary, and contents have values in them. You might want to extend this
validation to look for invalid characters in the title, validate that the author currently exists in the system, validate that the date is valid and after "now," and so forth. This is
your entry point to do so. The validator makes use of Spring's ValidationUtilsclass, which provides a handful of helper methods to check whether or not fields are
populated. Spring also supports the Jakarta Commons Validator library's more-robust validation capabilities. The important thing to note about this example is that the errors
object is updated with an error condition if a problem occurs. This tells the SimpleFormControllerto redirect the user back to the form, with error messages.

Internationalization support

The third parameter passed to the ValidationUtilsmethods is a key into a properties file from which Spring can look up the value to display as the error message. This is
for internationalization, which is beyond the scope of this article. Just know that Spring supports internationalization, and this is one example of where it does so.

Listing 11 shows the source code for the post.jspfile.

Listing 11. post.jsp

<?xml version="1.0" encoding="UTF-8" ?>

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="com.geekcap.geeknews.core.*,java.util.List"%>


<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Post a New Article</title>
<link type="text/css" rel="stylesheet" href="css/geeknews.css" />
</head>

<body>

<%@ include file="header.jsp" %>

<div id="articleForm">

<p><a href="home.htm">Home</a></p>

<p id="articleFormInstructions">Enter the information for an article posting and press "Post"</p>

<form:form action="post.htm" method="POST" commandName="newsArticle" >

www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 11/12
10/15/12 http://www.javaworld.com/javaworld/jw042009/jw04springmvc.html

<table>
<tr>
<th rowspan="2">Title:</th>
<td><form:input path="title" size="60" /></td>
</tr>
<tr>
<td><form:errors path="title" cssClass="validationError"/></td>
</tr>
<tr>
<th rowspan="2">Author:</th>
<td><form:input path="author" size="60" /></td>
</tr>
<tr>
<td><form:errors path="author" cssClass="validationError"/></td>
</tr>
<tr>
<th rowspan="2">Date:</th>
<td><form:input path="date" size="60" /></td>
</tr>
<tr>
<td><form:errors path="date" cssClass="validationError"/></td>
</tr>
<tr>
<th rowspan="2">Summary:</th>
<td><form:textarea path="summary" rows="3" cols="90"></form:textarea></td>
</tr>
<tr>
<td><form:errors path="summary" cssClass="validationError"/></td>
</tr>
<tr>
<th rowspan="2">Content:</th>
<td><form:textarea path="content" rows="20" cols="90"></form:textarea></td>
</tr>
<tr>
<td><form:errors path="content" cssClass="validationError"/></td>
</tr>
<tr>
<th></th>
<td><input type="submit" value="Post" /></td>
</tr>
</table>

</form:form>

</div>

<%@ include file="footer.jsp" %>

</body>

</html>

The important observation to make about post.jspis that it uses Spring form tags as opposed to HTML form tags. It begins by importing the Spring form tag library:

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

Then it's possible to preface normal form tags with form:. For example, the <form>tag is substituted with <form:form>. These tags also include some additional parameters:

The <form:form>tag's additional commandNameparameter should match up to your SimpleFormController's setCommandName()parameter.


The <form:input>and <form:textarea>tags have a pathparameter instead of a nameparameter. The pathparameter is used during form validation to repopulate
the value of a tag if the form needs to be redisplayed. If you look at the generated HTML, you can see that it is translated to name.

There's also a new element: <form:error>. If an error occurs during form validation, the error tag for the specified path is populated with the error message defined by the
form validator. In the post.jsppage, the errors are presented in new table rows that follow the field, but you are free to put them anywhere, such as at the top of the form.
Use the strategy that fits best into your user interface design.

In conclusion
In a few easy lessons, you've built a fully functioning Spring MVC application from scratch. You started by using a simple controller to construct a model and pass it to a JSP
file for presentation. Then you added a command controller and a form controller for form validation.

Spring MVC is a highly capable framework and a powerful extension to the Spring Framework. It provides several ways to map request URIs to controllers, defines several
controller base classes to suit your business needs, and gives you multiple options for mapping view names to views. If you are building Spring applications, Spring MVC
certainly should be at the top of your short list of Web frameworks.

About the author


Steven Haines is the founder and CEO of GeekCap, Inc., which provides technical e-learning solutions for software developers. Previously he was the Java EE Domain
Expert at Quest Software, defining software used to monitor the performance of various Java EE application servers. He is the author of Pro Java EE 5 Performance
Management and Optimization, Java 2 Primer Plus, and Java 2 From Scratch. He is the Java host on InformIT.com and a Java Community Editor on InfoQ.com. Steven has
taught Java at the University of California, Irvine, and Learning Tree University.

Read more about Tools & Methods in JavaWorld's Tools & Methods section.

All contents copyright 1995-2012 Java World, Inc. http://www.javaworld.com

www.javaworld.com/cgibin/mailto/x_java.cgi?pagetosend=/export/home/httpd/javaworld/javaworld/jw 12/12

You might also like