You are on page 1of 65

Advanced Spring MVC

About the speaker


 Principal Consultant at Inteface21
 Core Developer on Spring
 Founder of Spring Modules
 Author of Pro Spring

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

 Well-defined, extensible workflow


 Explicit form request and submission
workflows
 Use template methods to extend the
flow
 Flexible binding system
 Sensible default binders
 Plug-in custom binders
 Binding support for JSP, Velocity and
FreeMarker
 Externalized validation

Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Workflow of SimpleFormController

 Split into two distinct branches


 Form request
• Binding is disabled by default
• Allows for loading for command object and reference
data
• Shows the form view
 Form submission
• Binding is enabled by default
− Shows form on error
• Validation is enabled
− Shows form on error
• Provides callback methods to handle submission logic
• Shows configurable success view after processing

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

 Bind errors are stored and exposed in the model


 Callback method onBindOnNewForm()

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

 Un-typed view of the world


 Necessary to show data binding errors
 Holds the exact data entered by the user
 Wraps the command object
 Binding in the view is to the BindStatus
not the command object

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

Servlet Filter Chain


HandlerInterceptor Chain
Request comes in

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 {

boolean preHandle(HttpServletRequest request,


HttpServletResponse response, Object handler)
throws Exception;

void postHandle(HttpServletRequest request,


HttpServletResponse response, Object handler,
ModelAndView modelAndView)
throws Exception;

void afterCompletion(HttpServletRequest request,


HttpServletResponse response, Object handler,
Exception ex)
throws Exception;

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>

Ordered list of HandlerInterceptors

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)

Corresponds to the bean name

<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" />

Just a plain Spring bean!

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

 Spring provides two implementations of


MessageSource
 ResourceBundleMessageSource
• Uses standard Java ResourceBundles to lookup
messages
 ReloadableResourceBundleMessageSource
• Uses ResourceBundles also
• Allows for ResourceBundle refresh without
stopping the VM

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>

Language specific files in


'<basename>_locale.properties'

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)

Available throughout request


Locale
LocaleResolver ContextHolder

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

Resolve message Message


using Locale Source

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)

 Once configured simply use <fmt:*/>


tags as normal:

<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

public interface MultipartHttpServletRequest


extends HttpServletRequest {

Iterator getFileNames();

MultipartFile getFile(String name);

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():

protected void initBinder(HttpServletRequest request,


ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(byte[].class,
binder.registerCustomEditor(byte[].class,
new ByteArrayMultipartFileEditor());
ByteArrayMultipartFileEditor());
}

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

public interface HandlerExceptionResolver {

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

Render ModelAndView from resolver

Request routed to handler


Dispatcher Handler
Servlet Exception
Occurs!

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()

 Perform custom processing


 Return (potentially modified)
ModelAndView

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

 Make use of the existing form workflow rather


than build controllers from scratch
 Use custom binders to simply form controller
logic
 Use Filters and HandlerInterceptors to add
cross-cutting web logic
Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
More Information
 http://www.springframework.org
 Books:
 Pro Spring (Apress)
 Pro Java Development with Spring (Wiley)
 Expert Spring MVC (Apress, Forthcoming)
• Deepest coverage of Spring MVC
• http://www.apress.com/book/bookDisplay.htm
l?bID=10048
• Expert authors: Seth Ladd, Keith Donald and
more…

Copyright 2004-2005, Interface21 Ltd. - Copying, publishing, or distributing without expressed written permission is prohibited.
Q&A

You might also like