Professional Documents
Culture Documents
Contact me at robh@interface21.com
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Diving in at the deep end
Handling forms
Workflow
Validation
Binding
Multiple view technologies
Testing outside the container
Exploring the outer reaches
Interceptors and Filters
Internationalization
File Uploads
Handling Exceptions
MVC in Spring 1.3
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Handling Forms
Spring provides excellent features for
handling form processing
SimpleFormController and
CancellableFormController
• Handle single page form input
AbstractWizardFormController
• Handle multi-page form input
• Consider Spring WebFlow for a more
comprehensive solution
Let's look at SimpleFormController in
more detail
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
SimpleFormController: Key Concepts
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Workflow of SimpleFormController
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Identifying Workflow Branches
Sensible defaults:
GET request – form request
POST request – form submission
Fully customizable
Override the isFormSubmission() method
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Important Concepts
Command Object
Object representing the data being manipulated
by the form
Form data is bound to the command object
Accessible in submission callbacks
Reference Data
Data needed for form rendering
Often select list data
Form View
The view that displays the form
Also used to display errors inline
Success View
The view to show after a successful form
submission
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Anatomy of a Form Request (1)
Call to formBackingObject()
Retrieve the command object
Allows for pre-population of the form
Store in Session if sessionForm property is true
Call to initBinder()
Register custom editors
Binding
If bindOnNewForm is true
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Anatomy of a Form Request (2)
Call to referenceData()
Load reference data needed for displaying the
form
Call to getFormView()
Get the name of the form view
Default implementation uses value of formView
property
Call to showForm()
Completes ModelAndView and returns
Command object stored in session if configured
Renders the actual form
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Anatomy of a Form Submission (1)
Call to formBackingObject()
Retrieve the command object
Default implementation will retrieve from the
Session if sessionForm is true otherwise it will
create a new instance of the configured
commandClass
Call to initBinder()
Register custom editors
Binding
Can prevent binding by overriding
suppressBinding()
Bind errors are stored and exposed in the model
Call to onBind()
Called after bind but before validation
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Anatomy of a Form Submission (2)
Validation done using Validators
Call to onBindAndValidate()
Called after bind and validate
If validation fails then add errors to the
ModelAndView and show the form again
If validation succeeds call onSubmit()
callbacks
May need retrieve the success view
manually with a call to getSuccessView()
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
SimpleFormController Configuration
Parameters (1)
commandClass
The class of the command object
Used by default formBackingObject()
implementation
commandName
The name the command object is exposed as in
the model (default=‘command’)
successView
The name of the view used after successfully
processing a form submission
formView
The name of the view used to render the form
Used by default showForm() implementation
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
SimpleFormController Configuration
Parameters (2)
sessionForm
Indicates whether the command object should be
stored in the session
validateOnBinding
Specify whether the Validator list should be
used to validate the command object after
binding
bindOnNewForm
Indicates whether binding should be invoked
when rendering the form view
validators
Specify a list of Validators to apply to the
command object after binding
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Customizing Data Binding
Uses standard JavaBeans PropertyEditors
The same approach is used for custom binding in
the ApplicationContext
Register your custom editors by overriding the
initBinder() method
Extend the PropertyEditorSupport class to
simplify implementation
Remember that PropertyEditors can do any
logic
Call a service object for domain object binding
Interact with the Spring ApplicationContext to
lookup a manged bean
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Adding Validation Logic
Implement the Validator interface
Decoupled from the web tier
Generic collection of validation errors
Use the Errors interface to log validation
errors
Use ValidationUtils for common validation
checks
Errors are associated with codes for i18n
of error messages
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Binding in the View (1)
Using the <spring:bind/> tag
Has access to
The bound values
Any errors from binding or validation
Provides full flexibility for binding data
and displaying errors
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Binding in the View (2)
<spring:bind path="order.cardDetails.number
order.cardDetails.number">
order.cardDetails.number
<td>
<input type="text" size="60"
name="<c:out
name="<c:out value='${status.expression
value='${status.expression}'/>"
status.expression}'/>"
value="<c:out
value="<c:out value='${status.displayValue
value='${status.displayValue}'
status.displayValue}' />"/>
</td>
<td>
<c:if test="${status.error
test="${status.error}">
status.error}">
<div class="error">
<c:forEach items="${status.errorMessages
items="${status.errorMessages}"
status.errorMessages}" var="error">
var="error">
<c:out value="${error}"/>
</c:forEach
</c:forEach>
c:forEach>
</div>
</c:if
</c:if>
c:if>
</td>
</spring:bind>
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Understanding the BindStatus
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
SimpleFormController in Action
Live Demo
Multiple View Technologies
Two approaches
Manually construct View instances in
Controllers
• Not ideal
• Couples Controllers to View implementations
Configure multiple ViewResolvers
• Ideal approach
• Controllers remain decoupled from View
implementations.
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
View Resolution Strategy
At startup
DispatcherServlet retrieves ViewResolvers
(by type)
Applies ordering to ViewResolver list
• Using the Ordered interface
• Un-ordered ViewResolvers are placed at the end of the
list
Stores the ordered ViewResolver list
At request time
Iterates over the ordered list of ViewResolvers
Asks each ViewResolver to resolve the view
name
Stops as soon as it finds a view
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Important Information
Some ViewResolvers always resolve a
view
Any view that extends
UrlBasedViewResolver
InternalResourceViewResolver always
resolves a view
May be a 404-error page
Always put these resolvers at the end of
the list
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring Multiple ViewResolvers
Explict ordering
<bean id="beanNameViewResolver"
class="...BeanNameViewResolver">
<property name="order" value="0"/>
</bean>
<bean id="jspViewResolver"
class="...InternalResourceViewResolver">
<property name="viewClass" value="...JstlView" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Multiple Views in Action
Live Demo
Testing outside the container
Spring MVC is easy to test outside the container
Support classes in spring-mock.jar
MockHttpServletRequest
MockHttpServletResponse
…
Unit testing
Use EasyMock/JMock
Test exception handling
Test ModelAndView creation
Integration testing
Extend
AbstractTransactionalDataSourceSpringConte
xtTests
Use real service/data tier objects
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Testing Outside the Container
Live Demo
Request Interception
Spring provides two mechanisms for request
interception:
A HandlerInterceptor
• Configured in Spring ApplicationContext
• Configured for a HandlerMapping
• Applies to all handlers mapped by the HandlerMapping
A standard servlet Filter
• Uses standard servlet infrastructure
• Mapped to a particular URL pattern
• Configured in web.xml
Important distinction between the two:
Filters come before the DispatcherServlet
HandlerInterceptors come before the handler
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Request Interception in Action
Dispatcher
Handler
Servlet
Response rendered
Locate HandlerExecutionChain
HandlerMapping
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
The HandlerInterceptor Interface (1)
public interface HandlerInterceptor {
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
The HandlerInterceptor Interface (2)
preHandle()
Called before the handler is invoked by
DispatcherServlet
Can handle the request and end processing of the
HandlerExecutionChain
postHandle()
Called after the handler is invoked but before
view rendering
Can extend the ModelAndView
afterCompletion()
Called after view rendering is completed
Has access to any Exception raised during the
request
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring a HandlerInterceptor
<bean name="handlerMapping"
class="o.sf.w.s.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="maintenanceInterceptor
bean="maintenanceInterceptor"
maintenanceInterceptor" />
<ref bean="localeChangeInterceptor
bean="localeChangeInterceptor"
localeChangeInterceptor" />
</list>
</property>
</bean>
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Filters and Dependency Injection
Standard servlet Filters sit outside the
Spring ApplicationContext
Spring provides DelegatingFilterProxy
allowing for Filters to be first-class
Spring beans
Configure the DelegatingFilterProxy in
the web.xml file
Configure the real Filter in the Spring
ApplicationContext
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring a Filter Proxy(1)
<filter>
<filter-name>requestStatisticsFilter
requestStatisticsFilter</filter-name>
requestStatisticsFilter
<filter-class>
o.sf.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>requestStatisticsFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring a Filter Proxy (2)
<bean id="requestStatisticsFilter
requestStatisticsFilter"
requestStatisticsFilter
class="...RequestStatisticsFilter" />
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Use Cases for Filters and Interceptors
Logging
Extensive support in Spring already
Monitoring
Track response times
Exception Handling
Monitor exceptions raised
Better solution in HandlerExceptionResolvers
Conditional Request Handling
Maintenance mode
Many more
Any logic that can apply across requests
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Filters and Interceptors in Action
Live Demo
Internationalization (1)
Spring provides comprehensive i18n
support
Locale-aware validation framework
Integrated Locale resolution
Locale exposure for view frameworks
Localized message lookup
Four important components
MessageSource
LocaleResolver
LocaleContextHolder
LocalChangeInterceptor
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Internationalization (2)
Four important components
MessageSource
• Provides Locale-aware message lookup
• Used by validation framework
• Can be exposed to view technologies for generating localized
responses
LocaleResolver
• Resolves the Locale for a request
• Provides extensible, configurable resolution behaviour
LocaleContextHolder
• Stores the Locale for the current Thread in a LocaleContext
object
LocalChangeInterceptor
• HandlerInterceptor allowing the user to select a Locale
• Interacts with the LocaleResolver to store the selected
Locale
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
MessageSource Implementations
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring a MessageSource
'Special' bean name
<bean id="messageSource
messageSource"
messageSource
class="…ResourceBundleMessageSource">
<property name="basenames" value="labels
labels"/>
labels
</bean>
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Understanding Locale Resolution
Request comes in
Request Proceeds
Dispatcher
Servlet
Grab
LocaleResolver Expose Locale
(via LocaleResolver)
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
LocaleResolver Implementations (1)
AcceptHeaderLocaleResolver
Reads Locale from the 'accept-language' header
of request
Default implementation
Supports per-user configuration
Cannot be used with LocaleChangeInterceptor
CookieLocaleResolver
Reads the Locale from a cookie
Cookie name is configurable
Falls back to 'accept-language' header
Supports per-user configuration
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
LocaleResolver Implementations (1)
FixedLocaleResolver
Uses single, fixed Locale
Configured in the ApplicationContext
Cannot be used with
LocaleChangeInterceptor
SessionLocaleResolver
Stores the Locale in the user's session
Configurable session attribute
Supports per user-configuration
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring a LocaleResolver
LocaleResolver are accessed by type
Simply declare a bean of type
LocaleResolver:
<bean id="localeResolver"
class="...SessionLocaleResolver" />
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Understanding Locale Switching
LocaleChangeInterceptor
Request Proceeds
Locale
Dispatcher Aware
Servlet Component
Requests Locale
setLocale
Locale
LocaleResolver ContextHolder
Retrieved from LocaleResolver
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring the
LocaleChangeInterceptor
<bean id="localeChangeInterceptor"
class="…LocaleChangeInterceptor">
<property name="paramName
name="paramName"
paramName"
value="lang
value="lang"/>
lang"/>
</bean>
http://www.myapp.com/home?lang=en_GB
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Understanding Message Resolution
Locale
Render response/output
Aware
Component
getLocale()
Locale
ContextHolder
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Using JSTL <fmt:*/> tags (1)
Spring can expose its managed Locale to JSTL
Must explicitly configure JSTL as the view:
<bean id="jspViewResolver"
class="...InternalResourceViewResolver">
<property name="viewClass
name="viewClass"
viewClass" value="...JstlView
value="...JstlView"
JstlView" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Using JSTL <fmt:*/> tags (2)
<fmt:message key="home.title"/>
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Internationalization in Action
Live Demo
Handling File Uploads (1)
Handled by implementations of
MultipartResolver
Looked up automatically by
DispatcherServlet
Use special name: 'multipartResolver'
Two implementations
CommonsMultipartFileResolver
• Uses Jakarta Commons FileUpload
CosMultipartResolver
• Use the com.oreilly.servlet multipart support
package
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Handling File Uploads (1)
Multipart requests are converted to instances of
MultipartHttpServletRequest
Can access directly in Controllers
Iterator getFileNames();
Map getFileMap();
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Data Binding and File Uploads
Bind to a byte[] property
Simply override initBinder():
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
File Uploads in Action
Live Demo
Last Ditch Exception Handling
In general you want to allow fatal
exceptions to propagate up the stack
These exceptions can be handled by a
last ditch handler
Log the error
Notify an administrator
Display a friendly error-page for the user
Use an implementation of the
HandlerExceptionResolver interface
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
HandlerExceptionResolver interface
ModelAndView resolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex);
}
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Understanding Exception Handling
Resolve exception
Handler
ExceptionResolver
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring the
HandlerExceptionResolver
Special bean, resolved by type
Single implementation out of the box –
SimpleMappingExceptionResolver
Map Exception types to view names
Puts the Exception into the model
automatically
Useful out of the box, even better for
extension
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Configuring
SimpleMappingExceptionResolver
<bean id="exceptionHandler"
class="...SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<value>
java.lang.Exception=error
java.lang.Exception=error
</value>
</property>
</bean>
All exceptions are mapped to the 'error' view
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Extending
SimpleMappingExceptionResolver
Rather than build your own
HandlerExceptionResolver extend the
SimpleMappingExceptionResolver
Simple process:
Override the resolveException() method
Call super.resolveException()
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Exception Handling in Action
Live Demo
Summary
Spring MVC has numerous extension points
Form handling workflow
Validation
Binding
View resolution
Exception handling
Filter and HandlerInterceptors
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Q&A