SlideShare a Scribd company logo
1 of 79
Download to read offline
Spring MVC
Matt Raible
mraible@virtuas.com

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Introductions
Your experience with Spring?
Your experience with J2EE?
What do you hope to learn today?
Open Source experience: Ant, XDoclet, Hibernate?
Favorite IDE? Favorite OS?

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Who is Matt Raible?
Developing websites since 1994 - Developing J2EE
webapps since 1999
Committer on several open source projects:
AppFuse, Roller Weblogger, XDoclet, Struts Menu,
Display Tag
J2EE 5.0 and JSF 1.2 Expert Group Member
Author: Spring Live (SourceBeat) and contributor to
Pro JSP (Apress)

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Part I
Spring MVC Overview

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Controller Interface
Has handleRequest() method that returns a ModelAndView
Base interface for all controllers: handleRequest() can be
called in unit tests
ModelAndView: a class that holds both Model and a View
AbstractCommandController: use for populating a
command object with request parameters
MultiActionController: allows for many methods in same
class

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
ModelAndView
Many constructor options make it easy to use
View names are logical names that are configured
by ViewResolvers
Model can be Map or a JavaBean object
public ModelAndView(String viewName) {
this.viewName = viewName;
}
public ModelAndView(String viewName, Map model) {
this.viewName = viewName;
this.model = model;
}
public ModelAndView(String viewName, String modelName, Object modelObject) {
this.viewName = viewName;
addObject(modelName, modelObject);
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Controller
public class UserController implements Controller {
private final Log log = LogFactory.getLog(UserController.class);
private UserManager mgr = null;
public void setUserManager(UserManager userManager) {
this.mgr = userManager;
}
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return new ModelAndView("userList", "users", mgr.getUsers());
}

JSP
<display:table name="users" class="list" requestURI="" id="userList" export="true">

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
ControllerTest
public class UserControllerTest extends MockObjectTestCase {
private UserController c = new UserController();
private Mock mockManager = null;
protected void setUp() throws Exception {
mockManager = new Mock(UserManager.class);
c.setUserManager((UserManager) mockManager.proxy());
}
public void testGetUsers() throws Exception {
// set expected behavior on manager
mockManager.expects(once()).method("getUsers")
.will(returnValue(new ArrayList()));
ModelAndView mav =
c.handleRequest((HttpServletRequest) null,
(HttpServletResponse) null);
Map m = mav.getModel();
assertNotNull(m.get("users"));
assertEquals(mav.getViewName(), "userList");
// verify expectations
mockManager.verify();
}
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Configuration
Configured as a bean definition in actionservlet.xml where action is the name of the
DispatcherServlet in web.xml
<bean id="/users.html" class="org.appfuse.web.UserController">
<property name="userManager"><ref bean="userManager"/></property>
</bean>

OR
<bean id="userController" class="org.appfuse.web.UserController">
<property name="userManager"><ref bean="userManager"/></property>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
URL Mapping
BeanNameUrlHandlerMapping is the default where URLs are matched to bean names
SimpleUrlHandlerMapping provides central means
of configuring URLs and allows interceptors
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/editUser.html">userFormController</prop>
<prop key="/users.html">userController</prop>
</props>
</property>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Form Controllers
SimpleFormController: best to use for processing
forms
AbstractWizardFormController: use for processing
wizards
AbstractFormController: parent of both Simple/
AbstractWizardFormControllers. Requires before/
after view names to be configured
programmatically

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
HTTP GET Lifecycle

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
POST
Lifecycle

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
SimpleFormController
Initializing form object:
protected Object formBackingObject(HttpServletRequest request)
throws ServletException {
String userId = request.getParameter("id");
if ((userId != null) && !userId.equals("")) {
User user = mgr.getUser(userId);
if (user == null) {
return new User();
}
return user;
} else {
return new User();
}
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
SimpleFormController
Data Binding:
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) {
// convert java.util.Date
SimpleDateFormat dateFormat = new SimpleDateFormat(getText("date.format"));
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, null,
new CustomDateEditor(dateFormat, true));
// convert java.lang.Long
NumberFormat nf = NumberFormat.getNumberInstance();
binder.registerCustomEditor(Long.class, null,
new CustomNumberEditor(Long.class, nf, true));
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
SimpleFormController
Processing a valid command object:
public ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command,
BindException errors)
throws Exception {
if (log.isDebugEnabled()) {
log.debug("entering 'onSubmit' method...");
}
User user = (User) command;
if (request.getParameter("delete") != null) {
mgr.removeUser(user.getId().toString());
request.getSession().setAttribute("message",
getText("user.deleted", user.getFullName()));
} else {
mgr.saveUser(user);
request.getSession().setAttribute("message",
getText("user.saved", user.getFullName()));
}
return new ModelAndView(getSuccessView());
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
SimpleFormControllerTest
public class UserFormControllerTest extends AbstractTransactionalDataSourceSpringContextTests {
private UserFormController c;
public void setUserFormController(UserFormController userFormController) {
this.c = userFormController;
}
protected String[] getConfigLocations() {
return new String[] {"/WEB-INF/action-servlet.xml", "/WEB-INF/applicationContext*.xml"};
}
public void testEdit() throws Exception {
// add a test user to the database
UserManager mgr = (UserManager) applicationContext.getBean("userManager");
User user = new User();
user.setFirstName("Matt");
user.setLastName("Raible");
mgr.saveUser(user);
// verify controller can grab user
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/editUser.html");
request.addParameter("id", user.getId().toString());
ModelAndView mv = c.handleRequest(request, new MockHttpServletResponse());
assertEquals("userForm", mv.getViewName());
Map model = mv.getModel();
assertEquals(user, model.get(c.getCommandName()));
}
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Configuration
<bean id="userFormController" class="org.appfuse.web.UserFormController">
<property name="commandName"><value>user</value></property>
<property name="commandClass"><value>org.appfuse.model.User</value></property>
<property name="validator"><ref bean="beanValidator"/></property>
<property name="formView"><value>userForm</value></property>
<property name="successView"><value>redirect:users.html</value></property>
<property name="userManager"><ref bean="userManager"/></property>
</bean>

TIP: Set commandClass and commandName in
constructor - since they’re unlikely to change

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
View Options
JavaServer Pages: includes support for JSTL (i18n,
etc.)
Tiles: allows you to use Tiles like you would with
Struts - excellent for page composition
Velocity: includes convenience macros to simplify
form development
FreeMarker: macros for form development
XSLT, PDF, Excel: create classes to render view
JasperReports: nice open-source reporting engine

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
ViewResolvers
Bean definition that defines how Spring MVC
should resolve views
Provide de-coupling between Controllers and view
technology
Implementations provides for each of the previous
view options

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
ViewResolver Examples
<!-- View Resolver for JSPs -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- Velocity Configurer and View Resolver -->
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="dateToolAttribute" value="date"/>
<property name="exposeSpringMacroHelpers" value="true"/>
<property name="requestContextAttribute" value="rc"/>
<property name="cache" value="true"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".vm"/>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
ViewResolver Examples
<!-- FreeMarker Configurer and View Resolver -->
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/"/>
<property name="freemarkerSettings">
<props>
<prop key="datetime_format">MM/dd/yyyy</prop>
</props>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="exposeSpringMacroHelpers" value="true"/>
<property name="requestContextAttribute" value="rc"/>
<property name="prefix" value="/">
<property name="suffix" value=".ftl"/>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
JSP 2.0 + JSTL
<spring:bind path="user.*">
<c:if test="${not empty status.errorMessages}">
<div class="error">
<c:forEach var="error" items="${status.errorMessages}">
<c:out value="${error}" escapeXml="false"/><br />
</c:forEach>
</div>
</c:if>
</spring:bind>
...
<form method="post" action="<c:url value='/editUser.html'/>"
onsubmit="return validateUser(this)" name="userForm">
<spring:bind path="user.id">
<input type="hidden" name="id" value="${status.value}"/>
</spring:bind>
<table class="detail">
<tr>
<th><label for="firstName"><fmt:message key="user.firstName"/>:</label></th>
<td>
<spring:bind path="user.firstName">
<input type="text" name="firstName" id="firstName" value="${status.value}"/>
<span class="fieldError">${status.errorMessage}</span>
</spring:bind>
</td>
</tr>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Velocity
#set($springXhtmlCompliant = true)
...
#springBind("user.*")
#if ($status.error)
<div class="error">
#foreach ($error in $status.errorMessages)
${error}<br/>
#end
</div>
#end
...
<form method="post" action="#springUrl('editUser.html')">
#springFormHiddenInput("user.id")
<table>
<tr>
<th><label for="firstName">#springMessage("user.firstName"):</label></th>
<td>
#springFormInput("user.firstName" 'id="firstName"')
#springShowErrors("<br/>" "fieldError")
</td>
</tr>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
FreeMarker
<#import "/spring.ftl" as spring/>
<#assign xhtmlCompliant = true in spring>
...
<@spring.bind "user.*"/>
<#if spring.status.error>
<div class="error">
<#list spring.status.errorMessages as error>
${error}<br/>
</#list>
</div>
</#if>
...
<form method="post" action="<@spring.url '/editUser.html'/>">
<@spring.formHiddenInput "user.id"/>
<table>
<tr>
<th><label for="firstName">
<@spring.message "user.firstName"/></label>:</th>
<td>
<@spring.formInput "user.firstName", 'id="firstName"'/>
<span class="fieldError">${spring.status.errorMessage}</span>
</td>
</tr>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Part II
Spring MVC vs. Struts

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Struts
Version 1.0 released in June 2001
De-facto standard for Java web application
frameworks because it was first
Much better than developing with only JSPs and
Servlets
Widely adopted and used in many applications
Many developers familiar with programming Struts

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Spring MVC
Invented around the same time as Struts, but
version 1.0 released in March 2004
Inversion of Control is built-in, making Controller’s
easy to test
Supports wide range of view options: JSP, Tiles,
Velocity, FreeMarker, XSLT, PDF, Excel,
JasperReports
Lots of documentation and examples

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Actions vs. Controllers
Action has a single execute() method
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
}

Controller has a single handleRequest() method
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Multiple Methods
Both frameworks allow you to have multiple methods in an
Action/Controller - and control which ones are invoked
Struts: subclass DispatchAction, LookupDispatchAction, or
MappingDispatchAction
Specify “parameter” in action-mapping
Spring: subclass MultiActionController
Configure “methodNameResolver” property

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Method Configuration
Struts:
<action path="/user" type="org.appfuse.web.UserAction"
name="userForm" scope="request" parameter="method" validate="false">
<forward name="list" path="/userList.jsp"/>
<forward name="edit" path="/userForm.jsp"/>
</action>

Spring:
<bean id="methodResolver"
class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName" value="method"/>
<property name="defaultMethodName" value="list"/>
</bean>
<bean id="userController" class="org.appfuse.web.UserController">
<property name="methodNameResolver" ref="methodResolver"/>
<property name="userManager" ref="userManager"/>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Configuration
Struts Actions are configured in /WEB-INF/strutsconfig.xml
Spring Controllers are configured in /WEB-INF/
action-servlet.xml (where action is the name of the
Dispatcher servlet in web.xml)
Both allow success/failure views to be configured
in XML, or specified programmatically

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
ActionForms vs. POJOs
Struts: forms must be backed by an ActionForm
(ValidatorForm for validation) - which is a Java
representation of the HTML form
Contains all form properties in String form
Use BeanUtils.copyProperties to convert from
ActionForm to POJO
Register Converters with ConvertUtils

Spring: forms use POJOs as “command objects”
Register PropertyEditors to handle complex types

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
View Resolution
Called forwards in Struts and views in Spring
To redirect in Struts, use redirect=”true” in
<forward> configuration
To redirect in Spring, use redirect:viewName.html
in “successView” property
Programmatic configuration:
Struts: new ActionForward(URL, true) or new
ActionRedirect()
Spring: new RedirectView(viewName)
Both allow parameters to be added to redirected URL
www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Validation
Can use Commons Validator with both frameworks
Struts: programmatic validation in your ValidatorForm’s
validate() method
Spring: programmatic validation in a Validator class
Validators can be chained by specifying a <list> in your
Controller’s “validators” property
public class UserValidator implements Validator {
private Log log = LogFactory.getLog(UserValidator.class);
public boolean supports(Class clazz) {
return clazz.equals(User.class);
}
public void validate(Object obj, Errors errors) {
User user = (User) obj;
ValidationUtils.rejectIfEmptyOrWhitespace(errors,
"lastName", "errors.required", "Value required.");

}

}
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Migrating from
Struts to Spring MVC
web.xml front-dispatcher servlet
i18n bundle configuration
action-mappings to bean definitions
forwards to views
Struts JSP tags to be Spring JSP tags

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
web.xml
Struts:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

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

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Mappings to Definitions
Struts Actions configured as “mappings” in strutsconfig.xml:
<action path="/user" type="org.appfuse.web.UserAction"
name="userForm" scope="request" parameter="method" validate="false">
<forward name="list" path="/userList.jsp"/>
<forward name="edit" path="/userForm.jsp"/>
</action>

Spring Controllers configured as “beans” in actionservlet.xml:
<bean id="userController" class="org.appfuse.web.UserController">
<property name="userManager"><ref bean="userManager"/></property>
</bean>
<bean id="userFormController" class="org.appfuse.web.UserFormController">
<property name="commandName"><value>user</value></property>
<property name="commandClass"><value>org.appfuse.model.User</value></property>
<property name="validator"><ref bean="beanValidator"/></property>
<property name="formView"><value>userForm</value></property>
<property name="successView"><value>redirect:users.html</value></property>
<property name="userManager"><ref bean="userManager"/></property>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Internationalization
Can use JSTL and <fmt:message/> with both
struts-config.xml:
<message-resources parameter="messages"/>

action-servlet.xml:
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages"/>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
JSP Tags - Struts
<html:form action="/user" focus="user.firstName"
onsubmit="return validateUserForm(this)">
<input type="hidden" name="method" value="save"/>
<html:hidden property="user.id"/>
<table class="detail">
<tr>
<th><label for="user.firstName">
<fmt:message key="user.firstName"/>:</label></th>
<td><html:text property="user.firstName" styleId="user.firstName"/></td>
</tr>
<tr>
<th><label for="user.lastName" class="required">
* <fmt:message key="user.lastName"/>:</label></th>
<td>
<html:text property="user.lastName" styleId="user.lastName"/>
<span class="fieldError">
<html:errors property="addressForm.address"/></span>
</td>
</tr>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
JSP Tags - Spring
<form method="post" action="<c:url value="/editUser.html"/>"
onsubmit="return validateUser(this)" name="userForm">
<spring:bind path="user.id">
<input type="hidden" name="id" value="${status.value}"/>
</spring:bind>
<table class="detail">
<tr>
<th><label for="firstName">
<fmt:message key="user.firstName"/>:</label></th>
<td>
<spring:bind path="user.firstName">
<input type="text" name="${status.expression}"
id="firstName" value="${status.value}"/>
<span class="fieldError">${status.errorMessage}</span>
</spring:bind>
</td>
</tr>
<tr>
<th><label for="firstName" class="required">
* <fmt:message key="user.lastName"/>:</label></th>
<td>
<spring:bind path="user.lastName">
<input type="text" name="${status.expression}"
id="lastName" value="${status.value}"/>
<span class="fieldError">${status.errorMessage}</span>
</spring:bind>
</td>
</tr>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Validation Errors
Struts:
<logic:messagesPresent>
<div class="error">
<html:messages id="error">
${error}<br/>
</html:messages>
</div>
</logic:messagesPresent>

Spring:
<spring:bind path="user.*">
<c:if test="${not empty status.errorMessages}">
<div class="error">
<c:forEach var="error" items="${status.errorMessages}">
<c:out value="${error}" escapeXml="false"/><br />
</c:forEach>
</div>
</c:if>
</spring:bind>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Part III
Advanced Spring MVC

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Concept Overview
Page Decoration and Composition
Validation with Commons Validator
Exception Handling
File Upload
Data Binding
Indexed Properties
Developing Wizards

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Page Decoration
Tiles can be used for page composition
Supports JSP and Velocity
SiteMesh is an excellent tool for page decoration
SiteMesh can be used with any Java web framework
since it’s a ServletFilter
Supports Velocity, JSP and FreeMarker (maybe
Tapestry/JSF in next release)

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
How SiteMesh Works

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
SiteMesh: web.xml
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
/WEB-INF/sitemesh.xml
<sitemesh>
<property name="decorators-file" value="/WEB-INF/decorators.xml"/>
<excludes file="${decorators-file}"/>
<page-parsers>
<parser default="true"
class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
<parser content-type="text/html"
class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
<parser content-type="text/html;charset=ISO-8859-1"
class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
</page-parsers>
<decorator-mappers>
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
<param name="config" value="${decorators-file}"/>
</mapper>
</decorator-mappers>
</sitemesh>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
/WEB-INF/decorators.xml
<decorators defaultdir="/decorators">
<excludes>
<pattern>/demos/*</pattern>
<pattern>/resources/*</pattern>
</excludes>
<decorator name="default" page="default.jsp">
<pattern>/*</pattern>
</decorator>
</decorators>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Sample Decorator
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ include file="/taglibs.jsp"%>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title><decorator:title default="Equinox"/></title>
<meta http-equiv="Cache-Control" content="no-store"/>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Expires" content="0"/>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<link href="${ctx}/styles/global.css" type="text/css" rel="stylesheet"/>
<link href="${ctx}/images/favicon.ico" rel="SHORTCUT ICON"/>
<script type="text/javascript" src="${ctx}/scripts/global.js"></script>
<script type="text/javascript" src="${ctx}/scripts/fade.js"></script>
<decorator:head/>
</head>
<body<decorator:getProperty property="body.id" writeEntireProperty="true"/>>
<a name="top"></a>
<div id="content">
<%@ include file="/messages.jsp"%>
<decorator:body/>
</div>

www.springlive.com

</body>
</html>
© 2005, Virtuas, LLC

www.virtuas.com
Before SiteMesh

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
After SiteMesh

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Commons Validator
Spring support created by Daniel Miller in April
2004
Moved from Spring CVS sandbox to Spring
Modules project in April 2005
Validation rules specified in /WEB-INF/
validation.xml
Validators (client and server-side) configured in /
WEB-INF/validator-rules.xml

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Spring Configuration
<bean id="validatorFactory"
class="org.springmodules.commons.validator.DefaultValidatorFactory">
<property name="validationConfigLocations">
<list>
<value>/WEB-INF/validation.xml</value>
<value>/WEB-INF/validator-rules.xml</value>
</list>
</property>
</bean>
<bean id="beanValidator"
class="org.springmodules.commons.validator.DefaultBeanValidator">
<property name="validatorFactory" ref="validatorFactory"/>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
<form-validation>
<formset>
<form name="user">
<field property="lastName" depends="required">
<arg0 key="user.lastName"/>
</field>
</form>
</formset>
</form-validation>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Client-side validation
Form’s onsubmit handler:
<form method="post" action="editUser.html"
onsubmit="return validateUser(this)" name="userForm">

JavaScript tags after form:
<v:javascript formName="user" staticJavascript="false" xhtml="true" cdata="false"/>
<script type="text/javascript" src="<c:url value="/scripts/validator.jsp"/>"></script>

/scripts/validator.jsp
<%@ page language="java" contentType="javascript/x-javascript" %>
<%@ taglib uri="http://www.springmodules.org/tags/commons-validator" prefix="v" %>
<v:javascript dynamicJavascript="false" staticJavascript="true"/>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Exception Handling
action-servlet.xml:
<bean id="exceptionResolver"
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.springframework.dao.DataAccessException">
dataAccessFailure
</prop>
</props>
</property>
</bean>

dataAccessFailure.jsp:
<%@ include file="/taglibs.jsp" %>
<h3>Data Access Failure</h3>
<p>
<c:out value="${requestScope.exception.message}"/>
</p>
<!-<% Exception ex = (Exception) request.getAttribute("exception");
ex.printStackTrace(new java.io.PrintWriter(out)); %>
-->
<a href="<c:url value='/'/>">&#171; Home</a>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
File Upload
<%@ include file="/taglibs.jsp"%>
<h3>File Upload</h3>
<c:if test="${not empty model.filename}">
<p style="font-weight: bold">
Uploaded file (click to view): <a href="${model.url}">${model.filename}</a>
</p>
</c:if>
<p>Select a file to upload:</p>
<form method="post" action="fileUpload.html" enctype="multipart/form-data">
<input type="file" name="file"/><br/>
<input type="submit" value="Upload" class="button"
style="margin-top: 5px"/>
</form>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Command Class
package org.appfuse.web;
public class FileUpload {
private byte[] file;
public void setFile(byte[] file) {
this.file = file;
}
public byte[] getFile() {
return file;
}
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
FileUploadController
public class FileUploadController extends SimpleFormController {
public FileUploadController() {
super();
setCommandClass(FileUpload.class);
}
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws ServletException {
binder.registerCustomEditor(byte[].class,
new ByteArrayMultipartFileEditor());
}
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
Object command, BindException errors)
throws ServletException, IOException {
FileUpload bean = (FileUpload) command;
byte[] bytes = bean.getFile();
// cast to multipart file so we can get additional information
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
CommonsMultipartFile file = (CommonsMultipartFile) multipartRequest.getFile("file");
// process the file
return new ModelAndView(getSuccessView(), "model", model);
}
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
FileUpload Configuration
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<bean id="fileUploadController" class="org.appfuse.web.FileUploadController">
<property name="formView" value="fileUpload"/>
<property name="successView" value="fileUpload"/>
</bean>
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
...
<prop key="/fileUpload.html">fileUploadController</prop>
</props>
</property>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Data Binding
Complex types (i.e. Integer, Double, Date) require
you to register a custom PropertyEditor
Custom PropertyEditors can be registered in
initBinder() method of SimpleFormController
Conversion failures can be managed easily, just add
messages to your i18n bundle:
typeMismatch.java.lang.Integer={0} must be an integer.
typeMismatch.java.lang.Double={0} must be a double.
typeMismatch.java.util.Date={0} must be a date.

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Before typeMismatch Messages

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
After typeMismatch Messages

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Register Custom Editors
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
// convert java.lang.Long
NumberFormat nf = NumberFormat.getNumberInstance();
binder.registerCustomEditor(Long.class, null,
new CustomNumberEditor(Long.class, nf, true));
// convert java.util.Date
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, null,
new CustomDateEditor(dateFormat, true));
// convert java.lang.Integer
binder.registerCustomEditor(Integer.class, null,
new CustomNumberEditor(Integer.class, nf, true));
// convert java.lang.Double
binder.registerCustomEditor(Double.class, null,
new CustomNumberEditor(Double.class, nf, true));
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Indexed Properties
A User can have many phone numbers:
private Set phones;
public Set getPhones() {
return phones;
}
public void setPhones(Set phones) {
this.phones = phones;
}

Hibernate mapping:
<set name="phones" cascade="all">
<key column="user_id"/>
<one-to-many class="org.appfuse.model.Phone"/>
</set>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Indexed Properties, cont.
<table>
<tr>
<th style="text-align: right">Type</th>
<th style="text-align: left">Number</th>
</tr>
<c:forEach var="no" items="${user.phones}" varStatus="s">
<spring:bind path="user.phones[${s.index}].id">
<input type="hidden" name="${status.expression}" value="${status.value}"/>
</spring:bind>
<tr>
<td style="text-align: right">
<spring:bind path="user.phones[${s.index}].type">
<input type="text" name="${status.expression}" value="${status.value}" size="5"/>
<span class="fieldError">${status.errorMessage}</span>
</spring:bind>
</td>
<td>
<spring:bind path="user.phones[${s.index}].number">
<input type="text" name="${status.expression}" value="${status.value}" size="15"/>
<span class="fieldError">${status.errorMessage}</span>
</spring:bind>
</td>
</tr>
</c:forEach>
</table>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
JSP Screenshot

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Add/Delete Properties
Custom Logic required in onBind() for add/delete

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
AbstractWizardFormController
Must implement processFinish() method to process
results of wizard
“pages” property can be specified in XML:
<property name="pages">
<list>
<value>wizard/name</value>
<value>wizard/address</value>
<value>wizard/phone</value>
</list>
</property>

Or in your constructor:
public WizardFormController() {
setPages(new String[] {"wizard/name", "wizard/address",
"wizard/phone"});
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Determining Workflow
Page to call is determined by getTargetPage()
method
Method uses request parameters to determine page
flow

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Key Request Parameters
Parameter

Description

_target#

The # is the page's index in the list of pages. It specifies which page
the controller should show when the current page is submitted.

_finish

If this parameter is present in the request, the processFinish() method
is called and the command object is removed from the session.

_cancel

If this parameter is present in the request, the processCancel()
method is called. The default implementation removes the
command object from the session and throws a ServletException
stating that processCancel() is not implemented.

_page

Indicates the index of the current page. Its recommended you
specify this parameter in a hidden field.

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
UserWizardController
public class UserWizardController extends AbstractWizardFormController {
private UserManager userManager;
public UserWizardController() {
setCommandClass(User.class);
}
public void setUserManager(UserManager userManager) {
this.userManager = userManager;
}
protected ModelAndView processFinish(HttpServletRequest request,
HttpServletResponse response,
Object command,
BindException errors)
throws Exception {
User user = (User) command;
userManager.saveUser(user);
request.getSession()
.setAttribute("message", "User added successfully.");
return new ModelAndView(new RedirectView("users.html"));
}
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Bean Definition
<bean id="userWizardController" class="org.appfuse.web.UserWizardController">
<property name="commandName" value="user"/>
<property name="userManager" ref="userManager"/>
<property name="pages">
<list>
<value>wizard/name</value>
<value>wizard/address</value>
<value>wizard/other</value>
</list>
</property>
</bean>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
name.jsp
<title>Wizard | Step 1</title>
<h3>Name</h3>
<form method="post" action="wizard.html">
<input type="hidden" name="_page" value="0"/>
...
<input type="submit" class="button" name="_target1" value="Next &raquo;"/>
<input type="submit" class="button" name="_cancel" value="Cancel"/>

Need to add processCancel() to handle cancelling
protected ModelAndView processCancel(HttpServletRequest request,
HttpServletResponse response,
Object command, BindException errors)
throws Exception {
return new ModelAndView(new RedirectView("users.html"));
}

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
address.jsp
<title>Wizard | Step 2</title>
<h3>Address Information</h3>
<form method="post" action="wizard.html">
<input type="hidden" name="_page" value="1"/>
...
<input type="submit" class="button" name="_target0" value="&laquo; Prev"/>
<input type="submit" class="button" name="_target2" value="Next &raquo;"/>
<input type="submit" class="button" name="_cancel" value="Cancel"/>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
other.jsp
<title>Wizard | Step 3</title>
<h3>Other Information</h3>
<form method="post" action="wizard.html">
<input type="hidden" name="_page" value="2"/>
...
<input type="submit" class="button" name="_target1" value="&laquo; Prev"/>
<input type="submit" class="button" name="_finish" value="Finish"/>
<input type="submit" class="button" name="_cancel" value="Cancel"/>

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Validating a Wizard
Use “page” attribute for Commons Validator
validation.xml
<field property="lastName" depends="required" page="1">

name.jsp
<input type="hidden" name="page" value="1"/>

Use validatePage() method in WizardController to
validate programmatically

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com
Questions?
mraible@virtuas.com

www.springlive.com

© 2005, Virtuas, LLC

www.virtuas.com

More Related Content

What's hot

#36.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_재직자환급교육,실업자교육,국비지원교육, 자바교육,구...
#36.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_재직자환급교육,실업자교육,국비지원교육, 자바교육,구...#36.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_재직자환급교육,실업자교육,국비지원교육, 자바교육,구...
#36.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_재직자환급교육,실업자교육,국비지원교육, 자바교육,구...탑크리에듀(구로디지털단지역3번출구 2분거리)
 
Vaadin 7 CN
Vaadin 7 CNVaadin 7 CN
Vaadin 7 CNjojule
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsBurt Beckwith
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limitsDroidcon Berlin
 
Automated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xAutomated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xTatsuya Maki
 
What is the difference between struts 1 vs struts 2
What is the difference between struts 1 vs struts 2What is the difference between struts 1 vs struts 2
What is the difference between struts 1 vs struts 2Santosh Singh Paliwal
 
What's new in Android O
What's new in Android OWhat's new in Android O
What's new in Android OKirill Rozov
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Fabio Collini
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Patterngoodfriday
 
Тестирование на Android с Dagger 2
Тестирование на Android с Dagger 2Тестирование на Android с Dagger 2
Тестирование на Android с Dagger 2Kirill Rozov
 
What's Coming in Spring 3.0
What's Coming in Spring 3.0What's Coming in Spring 3.0
What's Coming in Spring 3.0Matt Raible
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaFabio Collini
 
Struts tutorial
Struts tutorialStruts tutorial
Struts tutorialOPENLANE
 
Step By Step Guide For Buidling Simple Struts App
Step By Step Guide For Buidling Simple Struts AppStep By Step Guide For Buidling Simple Struts App
Step By Step Guide For Buidling Simple Struts AppSyed Shahul
 
Photo Insert and Retrieve App
Photo Insert and Retrieve AppPhoto Insert and Retrieve App
Photo Insert and Retrieve AppPeeyush Ranjan
 
Introducing Vuex in your project
Introducing Vuex in your projectIntroducing Vuex in your project
Introducing Vuex in your projectDenny Biasiolli
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKFabio Collini
 

What's hot (20)

Android swedroid
Android swedroidAndroid swedroid
Android swedroid
 
#36.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_재직자환급교육,실업자교육,국비지원교육, 자바교육,구...
#36.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_재직자환급교육,실업자교육,국비지원교육, 자바교육,구...#36.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_재직자환급교육,실업자교육,국비지원교육, 자바교육,구...
#36.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_재직자환급교육,실업자교육,국비지원교육, 자바교육,구...
 
Vaadin 7 CN
Vaadin 7 CNVaadin 7 CN
Vaadin 7 CN
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limits
 
Automated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xAutomated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.x
 
What is the difference between struts 1 vs struts 2
What is the difference between struts 1 vs struts 2What is the difference between struts 1 vs struts 2
What is the difference between struts 1 vs struts 2
 
What's new in Android O
What's new in Android OWhat's new in Android O
What's new in Android O
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Pattern
 
Тестирование на Android с Dagger 2
Тестирование на Android с Dagger 2Тестирование на Android с Dagger 2
Тестирование на Android с Dagger 2
 
What's Coming in Spring 3.0
What's Coming in Spring 3.0What's Coming in Spring 3.0
What's Coming in Spring 3.0
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJava
 
Android TDD
Android TDDAndroid TDD
Android TDD
 
Struts tutorial
Struts tutorialStruts tutorial
Struts tutorial
 
Step By Step Guide For Buidling Simple Struts App
Step By Step Guide For Buidling Simple Struts AppStep By Step Guide For Buidling Simple Struts App
Step By Step Guide For Buidling Simple Struts App
 
Photo Insert and Retrieve App
Photo Insert and Retrieve AppPhoto Insert and Retrieve App
Photo Insert and Retrieve App
 
JS and patterns
JS and patternsJS and patterns
JS and patterns
 
Introducing Vuex in your project
Introducing Vuex in your projectIntroducing Vuex in your project
Introducing Vuex in your project
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UK
 

Viewers also liked

02 java spring-hibernate-experience-questions
02 java spring-hibernate-experience-questions02 java spring-hibernate-experience-questions
02 java spring-hibernate-experience-questionsDhiraj Champawat
 
Spring 3 Annotated Development
Spring 3 Annotated DevelopmentSpring 3 Annotated Development
Spring 3 Annotated Developmentkensipe
 
Spring Web Service, Spring JMS, Eclipse & Maven tutorials
Spring Web Service, Spring JMS, Eclipse & Maven tutorialsSpring Web Service, Spring JMS, Eclipse & Maven tutorials
Spring Web Service, Spring JMS, Eclipse & Maven tutorialsRaghavan Mohan
 
Spring @Transactional Explained
Spring @Transactional ExplainedSpring @Transactional Explained
Spring @Transactional ExplainedSmita Prasad
 
What's new in Spring 3?
What's new in Spring 3?What's new in Spring 3?
What's new in Spring 3?Craig Walls
 
Spring MVC Architecture Tutorial
Spring MVC Architecture TutorialSpring MVC Architecture Tutorial
Spring MVC Architecture TutorialJava Success Point
 
MVC Pattern. Flex implementation of MVC
MVC Pattern. Flex implementation of MVCMVC Pattern. Flex implementation of MVC
MVC Pattern. Flex implementation of MVCAnton Krasnoshchok
 
Spring 4 on Java 8 by Juergen Hoeller
Spring 4 on Java 8 by Juergen HoellerSpring 4 on Java 8 by Juergen Hoeller
Spring 4 on Java 8 by Juergen HoellerZeroTurnaround
 
Introduction to Spring MVC
Introduction to Spring MVCIntroduction to Spring MVC
Introduction to Spring MVCRichard Paul
 
SpringFramework Overview
SpringFramework OverviewSpringFramework Overview
SpringFramework Overviewzerovirus23
 
Spring 3.x - Spring MVC - Advanced topics
Spring 3.x - Spring MVC - Advanced topicsSpring 3.x - Spring MVC - Advanced topics
Spring 3.x - Spring MVC - Advanced topicsGuy Nir
 
Spring Mvc,Java, Spring
Spring Mvc,Java, SpringSpring Mvc,Java, Spring
Spring Mvc,Java, Springifnu bima
 
Managing user's data with Spring Session
Managing user's data with Spring SessionManaging user's data with Spring Session
Managing user's data with Spring SessionDavid Gómez García
 
Spring 3.x - Spring MVC
Spring 3.x - Spring MVCSpring 3.x - Spring MVC
Spring 3.x - Spring MVCGuy Nir
 

Viewers also liked (17)

02 java spring-hibernate-experience-questions
02 java spring-hibernate-experience-questions02 java spring-hibernate-experience-questions
02 java spring-hibernate-experience-questions
 
Spring 3 Annotated Development
Spring 3 Annotated DevelopmentSpring 3 Annotated Development
Spring 3 Annotated Development
 
Spring Web Service, Spring JMS, Eclipse & Maven tutorials
Spring Web Service, Spring JMS, Eclipse & Maven tutorialsSpring Web Service, Spring JMS, Eclipse & Maven tutorials
Spring Web Service, Spring JMS, Eclipse & Maven tutorials
 
Spring @Transactional Explained
Spring @Transactional ExplainedSpring @Transactional Explained
Spring @Transactional Explained
 
What's new in Spring 3?
What's new in Spring 3?What's new in Spring 3?
What's new in Spring 3?
 
Spring MVC Architecture Tutorial
Spring MVC Architecture TutorialSpring MVC Architecture Tutorial
Spring MVC Architecture Tutorial
 
MVC Pattern. Flex implementation of MVC
MVC Pattern. Flex implementation of MVCMVC Pattern. Flex implementation of MVC
MVC Pattern. Flex implementation of MVC
 
Spring annotation
Spring annotationSpring annotation
Spring annotation
 
Spring 4 on Java 8 by Juergen Hoeller
Spring 4 on Java 8 by Juergen HoellerSpring 4 on Java 8 by Juergen Hoeller
Spring 4 on Java 8 by Juergen Hoeller
 
Introduction to Spring MVC
Introduction to Spring MVCIntroduction to Spring MVC
Introduction to Spring MVC
 
SpringFramework Overview
SpringFramework OverviewSpringFramework Overview
SpringFramework Overview
 
Spring 3.x - Spring MVC - Advanced topics
Spring 3.x - Spring MVC - Advanced topicsSpring 3.x - Spring MVC - Advanced topics
Spring 3.x - Spring MVC - Advanced topics
 
Spring Mvc,Java, Spring
Spring Mvc,Java, SpringSpring Mvc,Java, Spring
Spring Mvc,Java, Spring
 
Managing user's data with Spring Session
Managing user's data with Spring SessionManaging user's data with Spring Session
Managing user's data with Spring Session
 
Spring 4 - A&BP CC
Spring 4 - A&BP CCSpring 4 - A&BP CC
Spring 4 - A&BP CC
 
Spring 3.x - Spring MVC
Spring 3.x - Spring MVCSpring 3.x - Spring MVC
Spring 3.x - Spring MVC
 
Spring 4 Web App
Spring 4 Web AppSpring 4 Web App
Spring 4 Web App
 

Similar to Spring mvc my Faviourite Slide

Top 10 Mistakes AngularJS Developers Make
Top 10 Mistakes AngularJS Developers MakeTop 10 Mistakes AngularJS Developers Make
Top 10 Mistakes AngularJS Developers MakeMark Meyer
 
Architecting ActionScript 3 applications using PureMVC
Architecting ActionScript 3 applications using PureMVCArchitecting ActionScript 3 applications using PureMVC
Architecting ActionScript 3 applications using PureMVCmarcocasario
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For ManagersAgileThought
 
Sustaining Test-Driven Development
Sustaining Test-Driven DevelopmentSustaining Test-Driven Development
Sustaining Test-Driven DevelopmentAgileOnTheBeach
 
The Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework EvolutionThe Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework EvolutionFITC
 
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
L2 Web App Development Guest Lecture At University of Surrey 20/11/09L2 Web App Development Guest Lecture At University of Surrey 20/11/09
L2 Web App Development Guest Lecture At University of Surrey 20/11/09Daniel Bryant
 
Testing your application on Google App Engine
Testing your application on Google App EngineTesting your application on Google App Engine
Testing your application on Google App EngineInphina Technologies
 
Testing Your Application On Google App Engine
Testing Your Application On Google App EngineTesting Your Application On Google App Engine
Testing Your Application On Google App EngineIndicThreads
 
WPF and Prism 4.1 Workshop at BASTA Austria
WPF and Prism 4.1 Workshop at BASTA AustriaWPF and Prism 4.1 Workshop at BASTA Austria
WPF and Prism 4.1 Workshop at BASTA AustriaRainer Stropek
 
The WebView Role in Hybrid Applications
The WebView Role in Hybrid ApplicationsThe WebView Role in Hybrid Applications
The WebView Role in Hybrid ApplicationsHaim Michael
 
ASP.NET MVC Internals
ASP.NET MVC InternalsASP.NET MVC Internals
ASP.NET MVC InternalsVitaly Baum
 
20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_twTse-Ching Ho
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with SpringJoshua Long
 
Controllers & actions
Controllers & actionsControllers & actions
Controllers & actionsEyal Vardi
 
Integrating Security Roles into Microsoft Silverlight Applications
Integrating Security Roles into Microsoft Silverlight ApplicationsIntegrating Security Roles into Microsoft Silverlight Applications
Integrating Security Roles into Microsoft Silverlight ApplicationsDan Wahlin
 

Similar to Spring mvc my Faviourite Slide (20)

Top 10 Mistakes AngularJS Developers Make
Top 10 Mistakes AngularJS Developers MakeTop 10 Mistakes AngularJS Developers Make
Top 10 Mistakes AngularJS Developers Make
 
Spring Web MVC
Spring Web MVCSpring Web MVC
Spring Web MVC
 
C#on linux
C#on linuxC#on linux
C#on linux
 
Architecting ActionScript 3 applications using PureMVC
Architecting ActionScript 3 applications using PureMVCArchitecting ActionScript 3 applications using PureMVC
Architecting ActionScript 3 applications using PureMVC
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
 
Sustaining Test-Driven Development
Sustaining Test-Driven DevelopmentSustaining Test-Driven Development
Sustaining Test-Driven Development
 
The Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework EvolutionThe Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework Evolution
 
Asp.net mvc
Asp.net mvcAsp.net mvc
Asp.net mvc
 
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
L2 Web App Development Guest Lecture At University of Surrey 20/11/09L2 Web App Development Guest Lecture At University of Surrey 20/11/09
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
 
Testing your application on Google App Engine
Testing your application on Google App EngineTesting your application on Google App Engine
Testing your application on Google App Engine
 
Testing Your Application On Google App Engine
Testing Your Application On Google App EngineTesting Your Application On Google App Engine
Testing Your Application On Google App Engine
 
WPF and Prism 4.1 Workshop at BASTA Austria
WPF and Prism 4.1 Workshop at BASTA AustriaWPF and Prism 4.1 Workshop at BASTA Austria
WPF and Prism 4.1 Workshop at BASTA Austria
 
The WebView Role in Hybrid Applications
The WebView Role in Hybrid ApplicationsThe WebView Role in Hybrid Applications
The WebView Role in Hybrid Applications
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
ASP.NET MVC Internals
ASP.NET MVC InternalsASP.NET MVC Internals
ASP.NET MVC Internals
 
20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_tw
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with Spring
 
Controllers & actions
Controllers & actionsControllers & actions
Controllers & actions
 
From Swing to JavaFX
From Swing to JavaFXFrom Swing to JavaFX
From Swing to JavaFX
 
Integrating Security Roles into Microsoft Silverlight Applications
Integrating Security Roles into Microsoft Silverlight ApplicationsIntegrating Security Roles into Microsoft Silverlight Applications
Integrating Security Roles into Microsoft Silverlight Applications
 

More from Daniel Adenew

Website Developemnt for edge-develop.com
Website Developemnt for edge-develop.com Website Developemnt for edge-develop.com
Website Developemnt for edge-develop.com Daniel Adenew
 
Edge develop com_innovative
Edge develop com_innovativeEdge develop com_innovative
Edge develop com_innovativeDaniel Adenew
 
Www mercycareethiopia org
Www mercycareethiopia orgWww mercycareethiopia org
Www mercycareethiopia orgDaniel Adenew
 
Www orchidplc com_index_php_option_com_content_view_article (1)
Www orchidplc com_index_php_option_com_content_view_article (1)Www orchidplc com_index_php_option_com_content_view_article (1)
Www orchidplc com_index_php_option_com_content_view_article (1)Daniel Adenew
 
Www mercycareethiopia org_welcome_to_mercy_care_ethiopia_gal
Www mercycareethiopia org_welcome_to_mercy_care_ethiopia_galWww mercycareethiopia org_welcome_to_mercy_care_ethiopia_gal
Www mercycareethiopia org_welcome_to_mercy_care_ethiopia_galDaniel Adenew
 
Edge develop com_previous_clients_html
Edge develop com_previous_clients_htmlEdge develop com_previous_clients_html
Edge develop com_previous_clients_htmlDaniel Adenew
 
Website Developemnt for edge-develop.com
Website Developemnt for edge-develop.com Website Developemnt for edge-develop.com
Website Developemnt for edge-develop.com Daniel Adenew
 
Natural language processing with python and amharic syntax parse tree by dani...
Natural language processing with python and amharic syntax parse tree by dani...Natural language processing with python and amharic syntax parse tree by dani...
Natural language processing with python and amharic syntax parse tree by dani...Daniel Adenew
 
Http tunneling exploit daniel adenew web
Http tunneling exploit daniel adenew webHttp tunneling exploit daniel adenew web
Http tunneling exploit daniel adenew webDaniel Adenew
 
Delivery System Developed By Daniel Adenew
Delivery System Developed By Daniel AdenewDelivery System Developed By Daniel Adenew
Delivery System Developed By Daniel AdenewDaniel Adenew
 
The rise of android malware and efficiency of Anti-Virus
The rise of android malware and efficiency of Anti-VirusThe rise of android malware and efficiency of Anti-Virus
The rise of android malware and efficiency of Anti-VirusDaniel Adenew
 

More from Daniel Adenew (13)

Website Developemnt for edge-develop.com
Website Developemnt for edge-develop.com Website Developemnt for edge-develop.com
Website Developemnt for edge-develop.com
 
Edge develop com_innovative
Edge develop com_innovativeEdge develop com_innovative
Edge develop com_innovative
 
Osdethiopia org
Osdethiopia orgOsdethiopia org
Osdethiopia org
 
Www mercycareethiopia org
Www mercycareethiopia orgWww mercycareethiopia org
Www mercycareethiopia org
 
Www orchidplc com_index_php_option_com_content_view_article (1)
Www orchidplc com_index_php_option_com_content_view_article (1)Www orchidplc com_index_php_option_com_content_view_article (1)
Www orchidplc com_index_php_option_com_content_view_article (1)
 
Www mercycareethiopia org_welcome_to_mercy_care_ethiopia_gal
Www mercycareethiopia org_welcome_to_mercy_care_ethiopia_galWww mercycareethiopia org_welcome_to_mercy_care_ethiopia_gal
Www mercycareethiopia org_welcome_to_mercy_care_ethiopia_gal
 
Edge develop com_previous_clients_html
Edge develop com_previous_clients_htmlEdge develop com_previous_clients_html
Edge develop com_previous_clients_html
 
Website Developemnt for edge-develop.com
Website Developemnt for edge-develop.com Website Developemnt for edge-develop.com
Website Developemnt for edge-develop.com
 
Edge develop com
Edge develop comEdge develop com
Edge develop com
 
Natural language processing with python and amharic syntax parse tree by dani...
Natural language processing with python and amharic syntax parse tree by dani...Natural language processing with python and amharic syntax parse tree by dani...
Natural language processing with python and amharic syntax parse tree by dani...
 
Http tunneling exploit daniel adenew web
Http tunneling exploit daniel adenew webHttp tunneling exploit daniel adenew web
Http tunneling exploit daniel adenew web
 
Delivery System Developed By Daniel Adenew
Delivery System Developed By Daniel AdenewDelivery System Developed By Daniel Adenew
Delivery System Developed By Daniel Adenew
 
The rise of android malware and efficiency of Anti-Virus
The rise of android malware and efficiency of Anti-VirusThe rise of android malware and efficiency of Anti-Virus
The rise of android malware and efficiency of Anti-Virus
 

Recently uploaded

Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 

Recently uploaded (20)

Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 

Spring mvc my Faviourite Slide

  • 2. Introductions Your experience with Spring? Your experience with J2EE? What do you hope to learn today? Open Source experience: Ant, XDoclet, Hibernate? Favorite IDE? Favorite OS? www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 3. Who is Matt Raible? Developing websites since 1994 - Developing J2EE webapps since 1999 Committer on several open source projects: AppFuse, Roller Weblogger, XDoclet, Struts Menu, Display Tag J2EE 5.0 and JSF 1.2 Expert Group Member Author: Spring Live (SourceBeat) and contributor to Pro JSP (Apress) www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 4. Part I Spring MVC Overview www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 5. Controller Interface Has handleRequest() method that returns a ModelAndView Base interface for all controllers: handleRequest() can be called in unit tests ModelAndView: a class that holds both Model and a View AbstractCommandController: use for populating a command object with request parameters MultiActionController: allows for many methods in same class www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 6. ModelAndView Many constructor options make it easy to use View names are logical names that are configured by ViewResolvers Model can be Map or a JavaBean object public ModelAndView(String viewName) { this.viewName = viewName; } public ModelAndView(String viewName, Map model) { this.viewName = viewName; this.model = model; } public ModelAndView(String viewName, String modelName, Object modelObject) { this.viewName = viewName; addObject(modelName, modelObject); } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 7. Controller public class UserController implements Controller { private final Log log = LogFactory.getLog(UserController.class); private UserManager mgr = null; public void setUserManager(UserManager userManager) { this.mgr = userManager; } public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { return new ModelAndView("userList", "users", mgr.getUsers()); } JSP <display:table name="users" class="list" requestURI="" id="userList" export="true"> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 8. ControllerTest public class UserControllerTest extends MockObjectTestCase { private UserController c = new UserController(); private Mock mockManager = null; protected void setUp() throws Exception { mockManager = new Mock(UserManager.class); c.setUserManager((UserManager) mockManager.proxy()); } public void testGetUsers() throws Exception { // set expected behavior on manager mockManager.expects(once()).method("getUsers") .will(returnValue(new ArrayList())); ModelAndView mav = c.handleRequest((HttpServletRequest) null, (HttpServletResponse) null); Map m = mav.getModel(); assertNotNull(m.get("users")); assertEquals(mav.getViewName(), "userList"); // verify expectations mockManager.verify(); } } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 9. Configuration Configured as a bean definition in actionservlet.xml where action is the name of the DispatcherServlet in web.xml <bean id="/users.html" class="org.appfuse.web.UserController"> <property name="userManager"><ref bean="userManager"/></property> </bean> OR <bean id="userController" class="org.appfuse.web.UserController"> <property name="userManager"><ref bean="userManager"/></property> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 10. URL Mapping BeanNameUrlHandlerMapping is the default where URLs are matched to bean names SimpleUrlHandlerMapping provides central means of configuring URLs and allows interceptors <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/editUser.html">userFormController</prop> <prop key="/users.html">userController</prop> </props> </property> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 11. Form Controllers SimpleFormController: best to use for processing forms AbstractWizardFormController: use for processing wizards AbstractFormController: parent of both Simple/ AbstractWizardFormControllers. Requires before/ after view names to be configured programmatically www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 12. HTTP GET Lifecycle www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 14. SimpleFormController Initializing form object: protected Object formBackingObject(HttpServletRequest request) throws ServletException { String userId = request.getParameter("id"); if ((userId != null) && !userId.equals("")) { User user = mgr.getUser(userId); if (user == null) { return new User(); } return user; } else { return new User(); } } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 15. SimpleFormController Data Binding: protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { // convert java.util.Date SimpleDateFormat dateFormat = new SimpleDateFormat(getText("date.format")); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, null, new CustomDateEditor(dateFormat, true)); // convert java.lang.Long NumberFormat nf = NumberFormat.getNumberInstance(); binder.registerCustomEditor(Long.class, null, new CustomNumberEditor(Long.class, nf, true)); } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 16. SimpleFormController Processing a valid command object: public ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { if (log.isDebugEnabled()) { log.debug("entering 'onSubmit' method..."); } User user = (User) command; if (request.getParameter("delete") != null) { mgr.removeUser(user.getId().toString()); request.getSession().setAttribute("message", getText("user.deleted", user.getFullName())); } else { mgr.saveUser(user); request.getSession().setAttribute("message", getText("user.saved", user.getFullName())); } return new ModelAndView(getSuccessView()); } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 17. SimpleFormControllerTest public class UserFormControllerTest extends AbstractTransactionalDataSourceSpringContextTests { private UserFormController c; public void setUserFormController(UserFormController userFormController) { this.c = userFormController; } protected String[] getConfigLocations() { return new String[] {"/WEB-INF/action-servlet.xml", "/WEB-INF/applicationContext*.xml"}; } public void testEdit() throws Exception { // add a test user to the database UserManager mgr = (UserManager) applicationContext.getBean("userManager"); User user = new User(); user.setFirstName("Matt"); user.setLastName("Raible"); mgr.saveUser(user); // verify controller can grab user MockHttpServletRequest request = new MockHttpServletRequest("GET", "/editUser.html"); request.addParameter("id", user.getId().toString()); ModelAndView mv = c.handleRequest(request, new MockHttpServletResponse()); assertEquals("userForm", mv.getViewName()); Map model = mv.getModel(); assertEquals(user, model.get(c.getCommandName())); } } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 18. Configuration <bean id="userFormController" class="org.appfuse.web.UserFormController"> <property name="commandName"><value>user</value></property> <property name="commandClass"><value>org.appfuse.model.User</value></property> <property name="validator"><ref bean="beanValidator"/></property> <property name="formView"><value>userForm</value></property> <property name="successView"><value>redirect:users.html</value></property> <property name="userManager"><ref bean="userManager"/></property> </bean> TIP: Set commandClass and commandName in constructor - since they’re unlikely to change www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 19. View Options JavaServer Pages: includes support for JSTL (i18n, etc.) Tiles: allows you to use Tiles like you would with Struts - excellent for page composition Velocity: includes convenience macros to simplify form development FreeMarker: macros for form development XSLT, PDF, Excel: create classes to render view JasperReports: nice open-source reporting engine www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 20. ViewResolvers Bean definition that defines how Spring MVC should resolve views Provide de-coupling between Controllers and view technology Implementations provides for each of the previous view options www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 21. ViewResolver Examples <!-- View Resolver for JSPs --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/"/> <property name="suffix" value=".jsp"/> </bean> <!-- Velocity Configurer and View Resolver --> <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="resourceLoaderPath" value="/"/> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="dateToolAttribute" value="date"/> <property name="exposeSpringMacroHelpers" value="true"/> <property name="requestContextAttribute" value="rc"/> <property name="cache" value="true"/> <property name="prefix" value="/"/> <property name="suffix" value=".vm"/> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 22. ViewResolver Examples <!-- FreeMarker Configurer and View Resolver --> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/"/> <property name="freemarkerSettings"> <props> <prop key="datetime_format">MM/dd/yyyy</prop> </props> </property> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="exposeSpringMacroHelpers" value="true"/> <property name="requestContextAttribute" value="rc"/> <property name="prefix" value="/"> <property name="suffix" value=".ftl"/> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 23. JSP 2.0 + JSTL <spring:bind path="user.*"> <c:if test="${not empty status.errorMessages}"> <div class="error"> <c:forEach var="error" items="${status.errorMessages}"> <c:out value="${error}" escapeXml="false"/><br /> </c:forEach> </div> </c:if> </spring:bind> ... <form method="post" action="<c:url value='/editUser.html'/>" onsubmit="return validateUser(this)" name="userForm"> <spring:bind path="user.id"> <input type="hidden" name="id" value="${status.value}"/> </spring:bind> <table class="detail"> <tr> <th><label for="firstName"><fmt:message key="user.firstName"/>:</label></th> <td> <spring:bind path="user.firstName"> <input type="text" name="firstName" id="firstName" value="${status.value}"/> <span class="fieldError">${status.errorMessage}</span> </spring:bind> </td> </tr> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 24. Velocity #set($springXhtmlCompliant = true) ... #springBind("user.*") #if ($status.error) <div class="error"> #foreach ($error in $status.errorMessages) ${error}<br/> #end </div> #end ... <form method="post" action="#springUrl('editUser.html')"> #springFormHiddenInput("user.id") <table> <tr> <th><label for="firstName">#springMessage("user.firstName"):</label></th> <td> #springFormInput("user.firstName" 'id="firstName"') #springShowErrors("<br/>" "fieldError") </td> </tr> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 25. FreeMarker <#import "/spring.ftl" as spring/> <#assign xhtmlCompliant = true in spring> ... <@spring.bind "user.*"/> <#if spring.status.error> <div class="error"> <#list spring.status.errorMessages as error> ${error}<br/> </#list> </div> </#if> ... <form method="post" action="<@spring.url '/editUser.html'/>"> <@spring.formHiddenInput "user.id"/> <table> <tr> <th><label for="firstName"> <@spring.message "user.firstName"/></label>:</th> <td> <@spring.formInput "user.firstName", 'id="firstName"'/> <span class="fieldError">${spring.status.errorMessage}</span> </td> </tr> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 26. Part II Spring MVC vs. Struts www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 27. Struts Version 1.0 released in June 2001 De-facto standard for Java web application frameworks because it was first Much better than developing with only JSPs and Servlets Widely adopted and used in many applications Many developers familiar with programming Struts www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 28. Spring MVC Invented around the same time as Struts, but version 1.0 released in March 2004 Inversion of Control is built-in, making Controller’s easy to test Supports wide range of view options: JSP, Tiles, Velocity, FreeMarker, XSLT, PDF, Excel, JasperReports Lots of documentation and examples www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 29. Actions vs. Controllers Action has a single execute() method public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { } Controller has a single handleRequest() method public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 30. Multiple Methods Both frameworks allow you to have multiple methods in an Action/Controller - and control which ones are invoked Struts: subclass DispatchAction, LookupDispatchAction, or MappingDispatchAction Specify “parameter” in action-mapping Spring: subclass MultiActionController Configure “methodNameResolver” property www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 31. Method Configuration Struts: <action path="/user" type="org.appfuse.web.UserAction" name="userForm" scope="request" parameter="method" validate="false"> <forward name="list" path="/userList.jsp"/> <forward name="edit" path="/userForm.jsp"/> </action> Spring: <bean id="methodResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName" value="method"/> <property name="defaultMethodName" value="list"/> </bean> <bean id="userController" class="org.appfuse.web.UserController"> <property name="methodNameResolver" ref="methodResolver"/> <property name="userManager" ref="userManager"/> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 32. Configuration Struts Actions are configured in /WEB-INF/strutsconfig.xml Spring Controllers are configured in /WEB-INF/ action-servlet.xml (where action is the name of the Dispatcher servlet in web.xml) Both allow success/failure views to be configured in XML, or specified programmatically www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 33. ActionForms vs. POJOs Struts: forms must be backed by an ActionForm (ValidatorForm for validation) - which is a Java representation of the HTML form Contains all form properties in String form Use BeanUtils.copyProperties to convert from ActionForm to POJO Register Converters with ConvertUtils Spring: forms use POJOs as “command objects” Register PropertyEditors to handle complex types www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 34. View Resolution Called forwards in Struts and views in Spring To redirect in Struts, use redirect=”true” in <forward> configuration To redirect in Spring, use redirect:viewName.html in “successView” property Programmatic configuration: Struts: new ActionForward(URL, true) or new ActionRedirect() Spring: new RedirectView(viewName) Both allow parameters to be added to redirected URL www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 35. Validation Can use Commons Validator with both frameworks Struts: programmatic validation in your ValidatorForm’s validate() method Spring: programmatic validation in a Validator class Validators can be chained by specifying a <list> in your Controller’s “validators” property public class UserValidator implements Validator { private Log log = LogFactory.getLog(UserValidator.class); public boolean supports(Class clazz) { return clazz.equals(User.class); } public void validate(Object obj, Errors errors) { User user = (User) obj; ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "errors.required", "Value required."); } } } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 36. Migrating from Struts to Spring MVC web.xml front-dispatcher servlet i18n bundle configuration action-mappings to bean definitions forwards to views Struts JSP tags to be Spring JSP tags www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 38. Mappings to Definitions Struts Actions configured as “mappings” in strutsconfig.xml: <action path="/user" type="org.appfuse.web.UserAction" name="userForm" scope="request" parameter="method" validate="false"> <forward name="list" path="/userList.jsp"/> <forward name="edit" path="/userForm.jsp"/> </action> Spring Controllers configured as “beans” in actionservlet.xml: <bean id="userController" class="org.appfuse.web.UserController"> <property name="userManager"><ref bean="userManager"/></property> </bean> <bean id="userFormController" class="org.appfuse.web.UserFormController"> <property name="commandName"><value>user</value></property> <property name="commandClass"><value>org.appfuse.model.User</value></property> <property name="validator"><ref bean="beanValidator"/></property> <property name="formView"><value>userForm</value></property> <property name="successView"><value>redirect:users.html</value></property> <property name="userManager"><ref bean="userManager"/></property> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 39. Internationalization Can use JSTL and <fmt:message/> with both struts-config.xml: <message-resources parameter="messages"/> action-servlet.xml: <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="messages"/> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 40. JSP Tags - Struts <html:form action="/user" focus="user.firstName" onsubmit="return validateUserForm(this)"> <input type="hidden" name="method" value="save"/> <html:hidden property="user.id"/> <table class="detail"> <tr> <th><label for="user.firstName"> <fmt:message key="user.firstName"/>:</label></th> <td><html:text property="user.firstName" styleId="user.firstName"/></td> </tr> <tr> <th><label for="user.lastName" class="required"> * <fmt:message key="user.lastName"/>:</label></th> <td> <html:text property="user.lastName" styleId="user.lastName"/> <span class="fieldError"> <html:errors property="addressForm.address"/></span> </td> </tr> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 41. JSP Tags - Spring <form method="post" action="<c:url value="/editUser.html"/>" onsubmit="return validateUser(this)" name="userForm"> <spring:bind path="user.id"> <input type="hidden" name="id" value="${status.value}"/> </spring:bind> <table class="detail"> <tr> <th><label for="firstName"> <fmt:message key="user.firstName"/>:</label></th> <td> <spring:bind path="user.firstName"> <input type="text" name="${status.expression}" id="firstName" value="${status.value}"/> <span class="fieldError">${status.errorMessage}</span> </spring:bind> </td> </tr> <tr> <th><label for="firstName" class="required"> * <fmt:message key="user.lastName"/>:</label></th> <td> <spring:bind path="user.lastName"> <input type="text" name="${status.expression}" id="lastName" value="${status.value}"/> <span class="fieldError">${status.errorMessage}</span> </spring:bind> </td> </tr> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 42. Validation Errors Struts: <logic:messagesPresent> <div class="error"> <html:messages id="error"> ${error}<br/> </html:messages> </div> </logic:messagesPresent> Spring: <spring:bind path="user.*"> <c:if test="${not empty status.errorMessages}"> <div class="error"> <c:forEach var="error" items="${status.errorMessages}"> <c:out value="${error}" escapeXml="false"/><br /> </c:forEach> </div> </c:if> </spring:bind> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 43. Part III Advanced Spring MVC www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 44. Concept Overview Page Decoration and Composition Validation with Commons Validator Exception Handling File Upload Data Binding Indexed Properties Developing Wizards www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 45. Page Decoration Tiles can be used for page composition Supports JSP and Velocity SiteMesh is an excellent tool for page decoration SiteMesh can be used with any Java web framework since it’s a ServletFilter Supports Velocity, JSP and FreeMarker (maybe Tapestry/JSF in next release) www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 46. How SiteMesh Works www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 48. /WEB-INF/sitemesh.xml <sitemesh> <property name="decorators-file" value="/WEB-INF/decorators.xml"/> <excludes file="${decorators-file}"/> <page-parsers> <parser default="true" class="com.opensymphony.module.sitemesh.parser.FastPageParser"/> <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser"/> <parser content-type="text/html;charset=ISO-8859-1" class="com.opensymphony.module.sitemesh.parser.FastPageParser"/> </page-parsers> <decorator-mappers> <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper"> <param name="config" value="${decorators-file}"/> </mapper> </decorator-mappers> </sitemesh> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 49. /WEB-INF/decorators.xml <decorators defaultdir="/decorators"> <excludes> <pattern>/demos/*</pattern> <pattern>/resources/*</pattern> </excludes> <decorator name="default" page="default.jsp"> <pattern>/*</pattern> </decorator> </decorators> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 50. Sample Decorator <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <%@ include file="/taglibs.jsp"%> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title><decorator:title default="Equinox"/></title> <meta http-equiv="Cache-Control" content="no-store"/> <meta http-equiv="Pragma" content="no-cache"/> <meta http-equiv="Expires" content="0"/> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <link href="${ctx}/styles/global.css" type="text/css" rel="stylesheet"/> <link href="${ctx}/images/favicon.ico" rel="SHORTCUT ICON"/> <script type="text/javascript" src="${ctx}/scripts/global.js"></script> <script type="text/javascript" src="${ctx}/scripts/fade.js"></script> <decorator:head/> </head> <body<decorator:getProperty property="body.id" writeEntireProperty="true"/>> <a name="top"></a> <div id="content"> <%@ include file="/messages.jsp"%> <decorator:body/> </div> www.springlive.com </body> </html> © 2005, Virtuas, LLC www.virtuas.com
  • 51. Before SiteMesh www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 52. After SiteMesh www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 53. Commons Validator Spring support created by Daniel Miller in April 2004 Moved from Spring CVS sandbox to Spring Modules project in April 2005 Validation rules specified in /WEB-INF/ validation.xml Validators (client and server-side) configured in / WEB-INF/validator-rules.xml www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 54. Spring Configuration <bean id="validatorFactory" class="org.springmodules.commons.validator.DefaultValidatorFactory"> <property name="validationConfigLocations"> <list> <value>/WEB-INF/validation.xml</value> <value>/WEB-INF/validator-rules.xml</value> </list> </property> </bean> <bean id="beanValidator" class="org.springmodules.commons.validator.DefaultBeanValidator"> <property name="validatorFactory" ref="validatorFactory"/> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 55. validation.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN" "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd"> <form-validation> <formset> <form name="user"> <field property="lastName" depends="required"> <arg0 key="user.lastName"/> </field> </form> </formset> </form-validation> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 56. Client-side validation Form’s onsubmit handler: <form method="post" action="editUser.html" onsubmit="return validateUser(this)" name="userForm"> JavaScript tags after form: <v:javascript formName="user" staticJavascript="false" xhtml="true" cdata="false"/> <script type="text/javascript" src="<c:url value="/scripts/validator.jsp"/>"></script> /scripts/validator.jsp <%@ page language="java" contentType="javascript/x-javascript" %> <%@ taglib uri="http://www.springmodules.org/tags/commons-validator" prefix="v" %> <v:javascript dynamicJavascript="false" staticJavascript="true"/> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 57. Exception Handling action-servlet.xml: <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.springframework.dao.DataAccessException"> dataAccessFailure </prop> </props> </property> </bean> dataAccessFailure.jsp: <%@ include file="/taglibs.jsp" %> <h3>Data Access Failure</h3> <p> <c:out value="${requestScope.exception.message}"/> </p> <!-<% Exception ex = (Exception) request.getAttribute("exception"); ex.printStackTrace(new java.io.PrintWriter(out)); %> --> <a href="<c:url value='/'/>">&#171; Home</a> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 58. File Upload <%@ include file="/taglibs.jsp"%> <h3>File Upload</h3> <c:if test="${not empty model.filename}"> <p style="font-weight: bold"> Uploaded file (click to view): <a href="${model.url}">${model.filename}</a> </p> </c:if> <p>Select a file to upload:</p> <form method="post" action="fileUpload.html" enctype="multipart/form-data"> <input type="file" name="file"/><br/> <input type="submit" value="Upload" class="button" style="margin-top: 5px"/> </form> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 59. Command Class package org.appfuse.web; public class FileUpload { private byte[] file; public void setFile(byte[] file) { this.file = file; } public byte[] getFile() { return file; } } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 60. FileUploadController public class FileUploadController extends SimpleFormController { public FileUploadController() { super(); setCommandClass(FileUpload.class); } protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws ServletException { binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor()); } protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws ServletException, IOException { FileUpload bean = (FileUpload) command; byte[] bytes = bean.getFile(); // cast to multipart file so we can get additional information MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; CommonsMultipartFile file = (CommonsMultipartFile) multipartRequest.getFile("file"); // process the file return new ModelAndView(getSuccessView(), "model", model); } } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 61. FileUpload Configuration <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> <bean id="fileUploadController" class="org.appfuse.web.FileUploadController"> <property name="formView" value="fileUpload"/> <property name="successView" value="fileUpload"/> </bean> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> ... <prop key="/fileUpload.html">fileUploadController</prop> </props> </property> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 62. Data Binding Complex types (i.e. Integer, Double, Date) require you to register a custom PropertyEditor Custom PropertyEditors can be registered in initBinder() method of SimpleFormController Conversion failures can be managed easily, just add messages to your i18n bundle: typeMismatch.java.lang.Integer={0} must be an integer. typeMismatch.java.lang.Double={0} must be a double. typeMismatch.java.util.Date={0} must be a date. www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 63. Before typeMismatch Messages www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 64. After typeMismatch Messages www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 65. Register Custom Editors protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) { // convert java.lang.Long NumberFormat nf = NumberFormat.getNumberInstance(); binder.registerCustomEditor(Long.class, null, new CustomNumberEditor(Long.class, nf, true)); // convert java.util.Date SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, null, new CustomDateEditor(dateFormat, true)); // convert java.lang.Integer binder.registerCustomEditor(Integer.class, null, new CustomNumberEditor(Integer.class, nf, true)); // convert java.lang.Double binder.registerCustomEditor(Double.class, null, new CustomNumberEditor(Double.class, nf, true)); } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 66. Indexed Properties A User can have many phone numbers: private Set phones; public Set getPhones() { return phones; } public void setPhones(Set phones) { this.phones = phones; } Hibernate mapping: <set name="phones" cascade="all"> <key column="user_id"/> <one-to-many class="org.appfuse.model.Phone"/> </set> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 67. Indexed Properties, cont. <table> <tr> <th style="text-align: right">Type</th> <th style="text-align: left">Number</th> </tr> <c:forEach var="no" items="${user.phones}" varStatus="s"> <spring:bind path="user.phones[${s.index}].id"> <input type="hidden" name="${status.expression}" value="${status.value}"/> </spring:bind> <tr> <td style="text-align: right"> <spring:bind path="user.phones[${s.index}].type"> <input type="text" name="${status.expression}" value="${status.value}" size="5"/> <span class="fieldError">${status.errorMessage}</span> </spring:bind> </td> <td> <spring:bind path="user.phones[${s.index}].number"> <input type="text" name="${status.expression}" value="${status.value}" size="15"/> <span class="fieldError">${status.errorMessage}</span> </spring:bind> </td> </tr> </c:forEach> </table> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 68. JSP Screenshot www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 69. Add/Delete Properties Custom Logic required in onBind() for add/delete www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 70. AbstractWizardFormController Must implement processFinish() method to process results of wizard “pages” property can be specified in XML: <property name="pages"> <list> <value>wizard/name</value> <value>wizard/address</value> <value>wizard/phone</value> </list> </property> Or in your constructor: public WizardFormController() { setPages(new String[] {"wizard/name", "wizard/address", "wizard/phone"}); } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 71. Determining Workflow Page to call is determined by getTargetPage() method Method uses request parameters to determine page flow www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 72. Key Request Parameters Parameter Description _target# The # is the page's index in the list of pages. It specifies which page the controller should show when the current page is submitted. _finish If this parameter is present in the request, the processFinish() method is called and the command object is removed from the session. _cancel If this parameter is present in the request, the processCancel() method is called. The default implementation removes the command object from the session and throws a ServletException stating that processCancel() is not implemented. _page Indicates the index of the current page. Its recommended you specify this parameter in a hidden field. www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 73. UserWizardController public class UserWizardController extends AbstractWizardFormController { private UserManager userManager; public UserWizardController() { setCommandClass(User.class); } public void setUserManager(UserManager userManager) { this.userManager = userManager; } protected ModelAndView processFinish(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { User user = (User) command; userManager.saveUser(user); request.getSession() .setAttribute("message", "User added successfully."); return new ModelAndView(new RedirectView("users.html")); } } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 74. Bean Definition <bean id="userWizardController" class="org.appfuse.web.UserWizardController"> <property name="commandName" value="user"/> <property name="userManager" ref="userManager"/> <property name="pages"> <list> <value>wizard/name</value> <value>wizard/address</value> <value>wizard/other</value> </list> </property> </bean> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 75. name.jsp <title>Wizard | Step 1</title> <h3>Name</h3> <form method="post" action="wizard.html"> <input type="hidden" name="_page" value="0"/> ... <input type="submit" class="button" name="_target1" value="Next &raquo;"/> <input type="submit" class="button" name="_cancel" value="Cancel"/> Need to add processCancel() to handle cancelling protected ModelAndView processCancel(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { return new ModelAndView(new RedirectView("users.html")); } www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 76. address.jsp <title>Wizard | Step 2</title> <h3>Address Information</h3> <form method="post" action="wizard.html"> <input type="hidden" name="_page" value="1"/> ... <input type="submit" class="button" name="_target0" value="&laquo; Prev"/> <input type="submit" class="button" name="_target2" value="Next &raquo;"/> <input type="submit" class="button" name="_cancel" value="Cancel"/> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 77. other.jsp <title>Wizard | Step 3</title> <h3>Other Information</h3> <form method="post" action="wizard.html"> <input type="hidden" name="_page" value="2"/> ... <input type="submit" class="button" name="_target1" value="&laquo; Prev"/> <input type="submit" class="button" name="_finish" value="Finish"/> <input type="submit" class="button" name="_cancel" value="Cancel"/> www.springlive.com © 2005, Virtuas, LLC www.virtuas.com
  • 78. Validating a Wizard Use “page” attribute for Commons Validator validation.xml <field property="lastName" depends="required" page="1"> name.jsp <input type="hidden" name="page" value="1"/> Use validatePage() method in WizardController to validate programmatically www.springlive.com © 2005, Virtuas, LLC www.virtuas.com