spring web application framework for the presentation...

41
[email protected] Spring Web Framework Revised 7/26/2004 Page 1 of 42 Spring Web Application Framework for the Presentation Layer Revision History Date By Version Description 06/23/2004 0.1 Initial draft. 07/02/2004 0.2 Add several technical points 07/14/2004 0.3 Rearrange some sections 07/26/2004 0.4 Fixed an error pointed out by wes109, close the checkbox/multi-selection part. Create PDF with GO2PDF for free, if you wish to remove this line, click here to buy Virtual PDF Printer

Upload: others

Post on 23-Aug-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 1 of 42

Spring Web ApplicationFramework for thePresentation Layer

Revision History

Date By Version Description

06232004 01 Initial draft07022004 02 Add several technical points07142004 03 Rearrange some sections07262004 04 Fixed an error pointed out by wes109 close the

checkboxmulti-selection part

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 2 of 42

Table of Contents1 PURPOSE 32 ASSUMPTIONS 33 PREPARATION 34 GET STARTED 5

41 RETURN A STATIC HTMLJSP PAGE WITH A HARD CODED DESTINATION 542 RETURN A NAMED VIEW PAGE 843 ERROR PAGES 1044 FORWARD AND REDIRECT 1145 DYNAMIC OUTPUT FIELDS 1246 INPUT AND FORMS 14

5 SPRING CONTROLLERS AND TAGS 1651 SIMPLEFORMCONTROLLER 1652 MORE SETTINGS ON SIMPLEFORMCONTROLLER 2153 BIND MULTIPLE FIELDS 2154 SELECT FROM A LISTARRAYSETMAP 2255 BIND MORE THAN ONE FIELD IN HTML FORMS 2456 BOOLEAN RADIO BUTTONS CHECKBOXES AND MULTIPLE SELECTIONS 2757 ltSPRINGBINDgt MANIPULATION 28

6 FORM AND CONTROLLER COMPOSITIONS 2861 MORE THAN ONE FORM - MULTIPLE COMMAND OBJECTS AND MANUAL BINDING 2862 CHAINED CONTROLLERS 30

7 DISPATCHERSERVLET AND CONTROLLERS 368 THINGS THAT I DECIDE TO LEAVE OUT BUT QUITE USEFUL 39

81 CONTROLLERS 3982 INTERCEPTORS 3983 VALIDATORS 3984 LOCALES 3985 THEMES 3986 MULTIPARTFILE UPLOADING 4087 CACHING FOR STATIC WEB RESOURCES 4088 APPLICATION CONTEXT 4089 OTHERS 40

9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT 4010 OTHER VIEW COMPONENTS 4111 COMPARING WITH OTHER FRAMEWORKS 4112 REFERENCES 41

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 3 of 42

1 PurposeTo jumpstart Spring web application framework Spring is an open source framework for web application developmentIts web site is at httpwwwspringframeworkorg It composes of several components for J2EE development eg webdevelopment component database development component etc We are going to take a look at the web component inthis document

I try to keep this document as concise as possible while as precise as possible This is not a replacement of the java docinstead itrsquos a compliment Read Expert one on one J2EE programming authored by Rod Johnson chapter 12(The entirebook is well worth reading in fact I consider it as a necessary reading on J2EE programming)

This work is based on the work of others especially Spring forums mailing list CJSDN the book mentioned aboveSpring java doc samples source code and etc I just put them together in categories and in the logic order simplifysome of the code to highlight the points

Feel free to use or distribute this document just keep in mind I DO NOT BEAR ANY RESPONSIBILITY FORANYTHING IN THIS DOCUMENT

2 AssumptionsWe are going to use the following platform

1 JDK142 Servlets JSPJSTL3 The web module is spring So if the localhost is used along with port 8080 the prefix for URLs would be

httplocalhost8080springSince there are many application servers for servlet containers and thus many ways to run web applications (ANT IDEetc) we donrsquot want to get into details on how to run them If you donrsquot know how to run a servlet container checkdocuments on these application servers The content of this document should be able to run on any J2EE compliantapplication servers eg Tomcat Resin Weblogic WebSphere etc

3 PreparationSpring framework has 7 jar components We could use 7 smaller jars or one big jar springjar Since I donrsquot know (or Idonrsquot have time to figure out this) the dependencies about components and the size of springjar is less than 1MB I justtake the big one

The minimal dependency of Spring is commons-loggingjar from Apache Jakarta Commons This is the loggingwrapper utility used in Spring You may choose to use log4j log4j-128jar or just use java logging with jdk14 SinceJSTL will be used in this article we also need jstljar and taglibs-standardjar All these libraries are in the Springdistribution with dependencies

Next we need the files springtld (Spring tag definition) and spring-beansdtd (bean definition) You really donrsquot need tolook into these two files since they are just tag definitions (or syntax not semantics) A good XMLHTMLJSP editorwill prompt the tags and attributes in most cases when we edit XMLJSP files using these tags

The directory structure used in this document follows J2EE standard as shown below

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 4 of 42

Having sorted out the libraries and dependencies we turn our eyes on webxml (webxml is part of J2EE standard itrsquosthe starting point for all J2EE applications)

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD Web Application 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgt u

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegt middot lturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigt wlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

para define the servlet name for the DispatcherServletmiddot map it to the URL pattern htm so all the URLs with suffix htm will be handled by the DispatcherServletcedil the Spring tag library definitionFor now donrsquot get into details on DispatcherServlet (we are going to talk about the DispatcherServlet and Spring tagslater on) just know that we define (or hook) them in here and Application servers where we deploy web applicationswill call through here These settings will remain the same throughout this document except at one point we need toaddress error pages

Note that I just pick ldquousersrdquo as the servlet name however itrsquos quite arbitrary So pick something meaningful to yourapplication Once itrsquos chosen it will be used to map to the Spring configuration file by the DispatcherServlet Thedefault filename for the Spring configuration file is ltservlet namegt-servletxml by default in our case itrsquos users-servletxml This is the configuration file where a URL is mapped to an action which in turns handles the logic dataand view The DispatcherServlet calls this file to configure the application This file is one of our major battlegrounds(The other one is of course java classes for controllers etc)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 5 of 42

users-servletxml

webxml

Client DispatcherServlet Controllers Business Logic Layer

viewResolver

urlMapping between URLs andcontroller

31 2

456

We are going to walking through this configuration file to show how to set up controllers models and views Howeversince the view components involve other libraries we wonrsquot be able to discuss it in here but merely just mention someof them We are going to use JSPJSTL in this document (ie the view is fixed)

If you donrsquot want to use the default users-servletxml you may do the following to specify your files

ltservletgtltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgtltinit-paramgtltparam-namegtcontextConfigLocationltparam-namegt

ltparam-valuegtWEB-INFmy1-servletxmlWEB-INFmy2-controllersxmlltparam-valuegtltinit-paramgt

ltservletgt

4 Get startedFor the time being letrsquos ignore the models and start with some simple cases on the controllers

41 Return a static htmljsp page with a hard coded destinationIn this case we have just one page hellojsp under WEB-INFjsp

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltmdash Mapping definitions map urls to action ids --gtltbean id=urlMapping class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggt

ltproperty name=mappingsgtltpropsgt

ltprop key=userhomehtmgtuserHomeActionltpropgtltpropsgt

ltpropertygtltbeangt

lt-- Action definitions --gtltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 6 of 42

Here we define a URL userhomehtm (after web context) to an action userHomeAction (remember in webxml we mapall htm to the servlet named users) which in turns is mapped to the java class userHomeController

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

This class implements the Controller interface that has only one method The DispatcherServlet reads the configurationfile to get the name of this class instantiate it and call this method

The referenced JSP is very simple

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

The result is just showing the page

The second part of the configuration file is to define the JSTL view If you want to use other views this is the place youshould play with In our case this part will remain the same throughout this document since we are not going to useother view components eg Velocity Tapestry or XSLT

Note1 If empty string ldquordquo is returned the web document root is shown if not indexhtml (remember htm is mapped to

our actions so donrsquot use indexhtm) exists If null is returned the output would be empty and no error is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 7 of 42

thrown In fact we could write directly to the response and return null (although itrsquos not a good way to do so)This is the way to tell the framework that we are handling the view by ourselves We will come back to thislater for request forwarding and redirecting

2 Although this is a very simple example it shows the big picture about how the framework works get familiarwith how the DispatcherServlet calls the Controller implementation class

3 The general flow is as followswebxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxmlltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean id=urlMapping

class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggtltproperty name=mappingsgt

ltpropsgtltprop key=userhomehtmgtuserHomeActionltpropgt

ltpropsgtltpropertygt

ltbeangt

ltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

ltbeansgt

The config file users-servletxml handles mappings between URLs and the corresponding controllers and views Keepthis in mind since itrsquos the core of the framework It allows us to work straight on JSP files and controller classes

In users-servletxml in the above notice that there are two mappings within the file This can be further simplified usingBeanNameUrlHandlerMapping class (implicitly)

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

By default BeanNameUrlHandlerMapping class is used if no handler mapping found (ie if we remove theUrlMapping bean) The URL HandlerMapping is either all or none

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 8 of 42

42 Return a named view pageIn UserHomeController class we hard coded the jsp filename This is usually not a desired way to do so Now we aremaking it dynamic First modify the users-servletxml file to add the jsp filename

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegtWEB-INFjsphellojspltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Then we need to retrieve this property in the java class file Spring utilizes the JavaBean style settersgetters toretrievestore properties So all we need to do in the java class is to add a property and its gettersetter TheUserHomeController is modified as follows

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here the filename of the view is externalized When the framework reads the settings for the java class it will use thesetter to set the property viewFilename and the value in the configuration file

Further in the J2EE standard the document root is accessible by users through web So if we want to hide the jsp pagesfrom users for security and other reasons we have to move these jsp files to the WEB-INF(all capital letters) directoryTo organize files in a better way we move all jsp files to WEB-INFjsp So every jsp reference has to pre-append thispath To avoid extra typing letrsquos modify the users-servletxml again

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 2: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 2 of 42

Table of Contents1 PURPOSE 32 ASSUMPTIONS 33 PREPARATION 34 GET STARTED 5

41 RETURN A STATIC HTMLJSP PAGE WITH A HARD CODED DESTINATION 542 RETURN A NAMED VIEW PAGE 843 ERROR PAGES 1044 FORWARD AND REDIRECT 1145 DYNAMIC OUTPUT FIELDS 1246 INPUT AND FORMS 14

5 SPRING CONTROLLERS AND TAGS 1651 SIMPLEFORMCONTROLLER 1652 MORE SETTINGS ON SIMPLEFORMCONTROLLER 2153 BIND MULTIPLE FIELDS 2154 SELECT FROM A LISTARRAYSETMAP 2255 BIND MORE THAN ONE FIELD IN HTML FORMS 2456 BOOLEAN RADIO BUTTONS CHECKBOXES AND MULTIPLE SELECTIONS 2757 ltSPRINGBINDgt MANIPULATION 28

6 FORM AND CONTROLLER COMPOSITIONS 2861 MORE THAN ONE FORM - MULTIPLE COMMAND OBJECTS AND MANUAL BINDING 2862 CHAINED CONTROLLERS 30

7 DISPATCHERSERVLET AND CONTROLLERS 368 THINGS THAT I DECIDE TO LEAVE OUT BUT QUITE USEFUL 39

81 CONTROLLERS 3982 INTERCEPTORS 3983 VALIDATORS 3984 LOCALES 3985 THEMES 3986 MULTIPARTFILE UPLOADING 4087 CACHING FOR STATIC WEB RESOURCES 4088 APPLICATION CONTEXT 4089 OTHERS 40

9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT 4010 OTHER VIEW COMPONENTS 4111 COMPARING WITH OTHER FRAMEWORKS 4112 REFERENCES 41

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 3 of 42

1 PurposeTo jumpstart Spring web application framework Spring is an open source framework for web application developmentIts web site is at httpwwwspringframeworkorg It composes of several components for J2EE development eg webdevelopment component database development component etc We are going to take a look at the web component inthis document

I try to keep this document as concise as possible while as precise as possible This is not a replacement of the java docinstead itrsquos a compliment Read Expert one on one J2EE programming authored by Rod Johnson chapter 12(The entirebook is well worth reading in fact I consider it as a necessary reading on J2EE programming)

This work is based on the work of others especially Spring forums mailing list CJSDN the book mentioned aboveSpring java doc samples source code and etc I just put them together in categories and in the logic order simplifysome of the code to highlight the points

Feel free to use or distribute this document just keep in mind I DO NOT BEAR ANY RESPONSIBILITY FORANYTHING IN THIS DOCUMENT

2 AssumptionsWe are going to use the following platform

1 JDK142 Servlets JSPJSTL3 The web module is spring So if the localhost is used along with port 8080 the prefix for URLs would be

httplocalhost8080springSince there are many application servers for servlet containers and thus many ways to run web applications (ANT IDEetc) we donrsquot want to get into details on how to run them If you donrsquot know how to run a servlet container checkdocuments on these application servers The content of this document should be able to run on any J2EE compliantapplication servers eg Tomcat Resin Weblogic WebSphere etc

3 PreparationSpring framework has 7 jar components We could use 7 smaller jars or one big jar springjar Since I donrsquot know (or Idonrsquot have time to figure out this) the dependencies about components and the size of springjar is less than 1MB I justtake the big one

The minimal dependency of Spring is commons-loggingjar from Apache Jakarta Commons This is the loggingwrapper utility used in Spring You may choose to use log4j log4j-128jar or just use java logging with jdk14 SinceJSTL will be used in this article we also need jstljar and taglibs-standardjar All these libraries are in the Springdistribution with dependencies

Next we need the files springtld (Spring tag definition) and spring-beansdtd (bean definition) You really donrsquot need tolook into these two files since they are just tag definitions (or syntax not semantics) A good XMLHTMLJSP editorwill prompt the tags and attributes in most cases when we edit XMLJSP files using these tags

The directory structure used in this document follows J2EE standard as shown below

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 4 of 42

Having sorted out the libraries and dependencies we turn our eyes on webxml (webxml is part of J2EE standard itrsquosthe starting point for all J2EE applications)

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD Web Application 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgt u

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegt middot lturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigt wlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

para define the servlet name for the DispatcherServletmiddot map it to the URL pattern htm so all the URLs with suffix htm will be handled by the DispatcherServletcedil the Spring tag library definitionFor now donrsquot get into details on DispatcherServlet (we are going to talk about the DispatcherServlet and Spring tagslater on) just know that we define (or hook) them in here and Application servers where we deploy web applicationswill call through here These settings will remain the same throughout this document except at one point we need toaddress error pages

Note that I just pick ldquousersrdquo as the servlet name however itrsquos quite arbitrary So pick something meaningful to yourapplication Once itrsquos chosen it will be used to map to the Spring configuration file by the DispatcherServlet Thedefault filename for the Spring configuration file is ltservlet namegt-servletxml by default in our case itrsquos users-servletxml This is the configuration file where a URL is mapped to an action which in turns handles the logic dataand view The DispatcherServlet calls this file to configure the application This file is one of our major battlegrounds(The other one is of course java classes for controllers etc)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 5 of 42

users-servletxml

webxml

Client DispatcherServlet Controllers Business Logic Layer

viewResolver

urlMapping between URLs andcontroller

31 2

456

We are going to walking through this configuration file to show how to set up controllers models and views Howeversince the view components involve other libraries we wonrsquot be able to discuss it in here but merely just mention someof them We are going to use JSPJSTL in this document (ie the view is fixed)

If you donrsquot want to use the default users-servletxml you may do the following to specify your files

ltservletgtltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgtltinit-paramgtltparam-namegtcontextConfigLocationltparam-namegt

ltparam-valuegtWEB-INFmy1-servletxmlWEB-INFmy2-controllersxmlltparam-valuegtltinit-paramgt

ltservletgt

4 Get startedFor the time being letrsquos ignore the models and start with some simple cases on the controllers

41 Return a static htmljsp page with a hard coded destinationIn this case we have just one page hellojsp under WEB-INFjsp

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltmdash Mapping definitions map urls to action ids --gtltbean id=urlMapping class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggt

ltproperty name=mappingsgtltpropsgt

ltprop key=userhomehtmgtuserHomeActionltpropgtltpropsgt

ltpropertygtltbeangt

lt-- Action definitions --gtltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 6 of 42

Here we define a URL userhomehtm (after web context) to an action userHomeAction (remember in webxml we mapall htm to the servlet named users) which in turns is mapped to the java class userHomeController

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

This class implements the Controller interface that has only one method The DispatcherServlet reads the configurationfile to get the name of this class instantiate it and call this method

The referenced JSP is very simple

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

The result is just showing the page

The second part of the configuration file is to define the JSTL view If you want to use other views this is the place youshould play with In our case this part will remain the same throughout this document since we are not going to useother view components eg Velocity Tapestry or XSLT

Note1 If empty string ldquordquo is returned the web document root is shown if not indexhtml (remember htm is mapped to

our actions so donrsquot use indexhtm) exists If null is returned the output would be empty and no error is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 7 of 42

thrown In fact we could write directly to the response and return null (although itrsquos not a good way to do so)This is the way to tell the framework that we are handling the view by ourselves We will come back to thislater for request forwarding and redirecting

2 Although this is a very simple example it shows the big picture about how the framework works get familiarwith how the DispatcherServlet calls the Controller implementation class

3 The general flow is as followswebxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxmlltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean id=urlMapping

class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggtltproperty name=mappingsgt

ltpropsgtltprop key=userhomehtmgtuserHomeActionltpropgt

ltpropsgtltpropertygt

ltbeangt

ltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

ltbeansgt

The config file users-servletxml handles mappings between URLs and the corresponding controllers and views Keepthis in mind since itrsquos the core of the framework It allows us to work straight on JSP files and controller classes

In users-servletxml in the above notice that there are two mappings within the file This can be further simplified usingBeanNameUrlHandlerMapping class (implicitly)

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

By default BeanNameUrlHandlerMapping class is used if no handler mapping found (ie if we remove theUrlMapping bean) The URL HandlerMapping is either all or none

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 8 of 42

42 Return a named view pageIn UserHomeController class we hard coded the jsp filename This is usually not a desired way to do so Now we aremaking it dynamic First modify the users-servletxml file to add the jsp filename

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegtWEB-INFjsphellojspltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Then we need to retrieve this property in the java class file Spring utilizes the JavaBean style settersgetters toretrievestore properties So all we need to do in the java class is to add a property and its gettersetter TheUserHomeController is modified as follows

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here the filename of the view is externalized When the framework reads the settings for the java class it will use thesetter to set the property viewFilename and the value in the configuration file

Further in the J2EE standard the document root is accessible by users through web So if we want to hide the jsp pagesfrom users for security and other reasons we have to move these jsp files to the WEB-INF(all capital letters) directoryTo organize files in a better way we move all jsp files to WEB-INFjsp So every jsp reference has to pre-append thispath To avoid extra typing letrsquos modify the users-servletxml again

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 3: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 3 of 42

1 PurposeTo jumpstart Spring web application framework Spring is an open source framework for web application developmentIts web site is at httpwwwspringframeworkorg It composes of several components for J2EE development eg webdevelopment component database development component etc We are going to take a look at the web component inthis document

I try to keep this document as concise as possible while as precise as possible This is not a replacement of the java docinstead itrsquos a compliment Read Expert one on one J2EE programming authored by Rod Johnson chapter 12(The entirebook is well worth reading in fact I consider it as a necessary reading on J2EE programming)

This work is based on the work of others especially Spring forums mailing list CJSDN the book mentioned aboveSpring java doc samples source code and etc I just put them together in categories and in the logic order simplifysome of the code to highlight the points

Feel free to use or distribute this document just keep in mind I DO NOT BEAR ANY RESPONSIBILITY FORANYTHING IN THIS DOCUMENT

2 AssumptionsWe are going to use the following platform

1 JDK142 Servlets JSPJSTL3 The web module is spring So if the localhost is used along with port 8080 the prefix for URLs would be

httplocalhost8080springSince there are many application servers for servlet containers and thus many ways to run web applications (ANT IDEetc) we donrsquot want to get into details on how to run them If you donrsquot know how to run a servlet container checkdocuments on these application servers The content of this document should be able to run on any J2EE compliantapplication servers eg Tomcat Resin Weblogic WebSphere etc

3 PreparationSpring framework has 7 jar components We could use 7 smaller jars or one big jar springjar Since I donrsquot know (or Idonrsquot have time to figure out this) the dependencies about components and the size of springjar is less than 1MB I justtake the big one

The minimal dependency of Spring is commons-loggingjar from Apache Jakarta Commons This is the loggingwrapper utility used in Spring You may choose to use log4j log4j-128jar or just use java logging with jdk14 SinceJSTL will be used in this article we also need jstljar and taglibs-standardjar All these libraries are in the Springdistribution with dependencies

Next we need the files springtld (Spring tag definition) and spring-beansdtd (bean definition) You really donrsquot need tolook into these two files since they are just tag definitions (or syntax not semantics) A good XMLHTMLJSP editorwill prompt the tags and attributes in most cases when we edit XMLJSP files using these tags

The directory structure used in this document follows J2EE standard as shown below

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 4 of 42

Having sorted out the libraries and dependencies we turn our eyes on webxml (webxml is part of J2EE standard itrsquosthe starting point for all J2EE applications)

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD Web Application 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgt u

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegt middot lturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigt wlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

para define the servlet name for the DispatcherServletmiddot map it to the URL pattern htm so all the URLs with suffix htm will be handled by the DispatcherServletcedil the Spring tag library definitionFor now donrsquot get into details on DispatcherServlet (we are going to talk about the DispatcherServlet and Spring tagslater on) just know that we define (or hook) them in here and Application servers where we deploy web applicationswill call through here These settings will remain the same throughout this document except at one point we need toaddress error pages

Note that I just pick ldquousersrdquo as the servlet name however itrsquos quite arbitrary So pick something meaningful to yourapplication Once itrsquos chosen it will be used to map to the Spring configuration file by the DispatcherServlet Thedefault filename for the Spring configuration file is ltservlet namegt-servletxml by default in our case itrsquos users-servletxml This is the configuration file where a URL is mapped to an action which in turns handles the logic dataand view The DispatcherServlet calls this file to configure the application This file is one of our major battlegrounds(The other one is of course java classes for controllers etc)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 5 of 42

users-servletxml

webxml

Client DispatcherServlet Controllers Business Logic Layer

viewResolver

urlMapping between URLs andcontroller

31 2

456

We are going to walking through this configuration file to show how to set up controllers models and views Howeversince the view components involve other libraries we wonrsquot be able to discuss it in here but merely just mention someof them We are going to use JSPJSTL in this document (ie the view is fixed)

If you donrsquot want to use the default users-servletxml you may do the following to specify your files

ltservletgtltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgtltinit-paramgtltparam-namegtcontextConfigLocationltparam-namegt

ltparam-valuegtWEB-INFmy1-servletxmlWEB-INFmy2-controllersxmlltparam-valuegtltinit-paramgt

ltservletgt

4 Get startedFor the time being letrsquos ignore the models and start with some simple cases on the controllers

41 Return a static htmljsp page with a hard coded destinationIn this case we have just one page hellojsp under WEB-INFjsp

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltmdash Mapping definitions map urls to action ids --gtltbean id=urlMapping class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggt

ltproperty name=mappingsgtltpropsgt

ltprop key=userhomehtmgtuserHomeActionltpropgtltpropsgt

ltpropertygtltbeangt

lt-- Action definitions --gtltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 6 of 42

Here we define a URL userhomehtm (after web context) to an action userHomeAction (remember in webxml we mapall htm to the servlet named users) which in turns is mapped to the java class userHomeController

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

This class implements the Controller interface that has only one method The DispatcherServlet reads the configurationfile to get the name of this class instantiate it and call this method

The referenced JSP is very simple

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

The result is just showing the page

The second part of the configuration file is to define the JSTL view If you want to use other views this is the place youshould play with In our case this part will remain the same throughout this document since we are not going to useother view components eg Velocity Tapestry or XSLT

Note1 If empty string ldquordquo is returned the web document root is shown if not indexhtml (remember htm is mapped to

our actions so donrsquot use indexhtm) exists If null is returned the output would be empty and no error is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 7 of 42

thrown In fact we could write directly to the response and return null (although itrsquos not a good way to do so)This is the way to tell the framework that we are handling the view by ourselves We will come back to thislater for request forwarding and redirecting

2 Although this is a very simple example it shows the big picture about how the framework works get familiarwith how the DispatcherServlet calls the Controller implementation class

3 The general flow is as followswebxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxmlltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean id=urlMapping

class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggtltproperty name=mappingsgt

ltpropsgtltprop key=userhomehtmgtuserHomeActionltpropgt

ltpropsgtltpropertygt

ltbeangt

ltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

ltbeansgt

The config file users-servletxml handles mappings between URLs and the corresponding controllers and views Keepthis in mind since itrsquos the core of the framework It allows us to work straight on JSP files and controller classes

In users-servletxml in the above notice that there are two mappings within the file This can be further simplified usingBeanNameUrlHandlerMapping class (implicitly)

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

By default BeanNameUrlHandlerMapping class is used if no handler mapping found (ie if we remove theUrlMapping bean) The URL HandlerMapping is either all or none

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 8 of 42

42 Return a named view pageIn UserHomeController class we hard coded the jsp filename This is usually not a desired way to do so Now we aremaking it dynamic First modify the users-servletxml file to add the jsp filename

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegtWEB-INFjsphellojspltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Then we need to retrieve this property in the java class file Spring utilizes the JavaBean style settersgetters toretrievestore properties So all we need to do in the java class is to add a property and its gettersetter TheUserHomeController is modified as follows

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here the filename of the view is externalized When the framework reads the settings for the java class it will use thesetter to set the property viewFilename and the value in the configuration file

Further in the J2EE standard the document root is accessible by users through web So if we want to hide the jsp pagesfrom users for security and other reasons we have to move these jsp files to the WEB-INF(all capital letters) directoryTo organize files in a better way we move all jsp files to WEB-INFjsp So every jsp reference has to pre-append thispath To avoid extra typing letrsquos modify the users-servletxml again

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 4: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 4 of 42

Having sorted out the libraries and dependencies we turn our eyes on webxml (webxml is part of J2EE standard itrsquosthe starting point for all J2EE applications)

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD Web Application 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgt u

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegt middot lturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigt wlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

para define the servlet name for the DispatcherServletmiddot map it to the URL pattern htm so all the URLs with suffix htm will be handled by the DispatcherServletcedil the Spring tag library definitionFor now donrsquot get into details on DispatcherServlet (we are going to talk about the DispatcherServlet and Spring tagslater on) just know that we define (or hook) them in here and Application servers where we deploy web applicationswill call through here These settings will remain the same throughout this document except at one point we need toaddress error pages

Note that I just pick ldquousersrdquo as the servlet name however itrsquos quite arbitrary So pick something meaningful to yourapplication Once itrsquos chosen it will be used to map to the Spring configuration file by the DispatcherServlet Thedefault filename for the Spring configuration file is ltservlet namegt-servletxml by default in our case itrsquos users-servletxml This is the configuration file where a URL is mapped to an action which in turns handles the logic dataand view The DispatcherServlet calls this file to configure the application This file is one of our major battlegrounds(The other one is of course java classes for controllers etc)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 5 of 42

users-servletxml

webxml

Client DispatcherServlet Controllers Business Logic Layer

viewResolver

urlMapping between URLs andcontroller

31 2

456

We are going to walking through this configuration file to show how to set up controllers models and views Howeversince the view components involve other libraries we wonrsquot be able to discuss it in here but merely just mention someof them We are going to use JSPJSTL in this document (ie the view is fixed)

If you donrsquot want to use the default users-servletxml you may do the following to specify your files

ltservletgtltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgtltinit-paramgtltparam-namegtcontextConfigLocationltparam-namegt

ltparam-valuegtWEB-INFmy1-servletxmlWEB-INFmy2-controllersxmlltparam-valuegtltinit-paramgt

ltservletgt

4 Get startedFor the time being letrsquos ignore the models and start with some simple cases on the controllers

41 Return a static htmljsp page with a hard coded destinationIn this case we have just one page hellojsp under WEB-INFjsp

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltmdash Mapping definitions map urls to action ids --gtltbean id=urlMapping class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggt

ltproperty name=mappingsgtltpropsgt

ltprop key=userhomehtmgtuserHomeActionltpropgtltpropsgt

ltpropertygtltbeangt

lt-- Action definitions --gtltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 6 of 42

Here we define a URL userhomehtm (after web context) to an action userHomeAction (remember in webxml we mapall htm to the servlet named users) which in turns is mapped to the java class userHomeController

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

This class implements the Controller interface that has only one method The DispatcherServlet reads the configurationfile to get the name of this class instantiate it and call this method

The referenced JSP is very simple

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

The result is just showing the page

The second part of the configuration file is to define the JSTL view If you want to use other views this is the place youshould play with In our case this part will remain the same throughout this document since we are not going to useother view components eg Velocity Tapestry or XSLT

Note1 If empty string ldquordquo is returned the web document root is shown if not indexhtml (remember htm is mapped to

our actions so donrsquot use indexhtm) exists If null is returned the output would be empty and no error is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 7 of 42

thrown In fact we could write directly to the response and return null (although itrsquos not a good way to do so)This is the way to tell the framework that we are handling the view by ourselves We will come back to thislater for request forwarding and redirecting

2 Although this is a very simple example it shows the big picture about how the framework works get familiarwith how the DispatcherServlet calls the Controller implementation class

3 The general flow is as followswebxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxmlltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean id=urlMapping

class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggtltproperty name=mappingsgt

ltpropsgtltprop key=userhomehtmgtuserHomeActionltpropgt

ltpropsgtltpropertygt

ltbeangt

ltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

ltbeansgt

The config file users-servletxml handles mappings between URLs and the corresponding controllers and views Keepthis in mind since itrsquos the core of the framework It allows us to work straight on JSP files and controller classes

In users-servletxml in the above notice that there are two mappings within the file This can be further simplified usingBeanNameUrlHandlerMapping class (implicitly)

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

By default BeanNameUrlHandlerMapping class is used if no handler mapping found (ie if we remove theUrlMapping bean) The URL HandlerMapping is either all or none

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 8 of 42

42 Return a named view pageIn UserHomeController class we hard coded the jsp filename This is usually not a desired way to do so Now we aremaking it dynamic First modify the users-servletxml file to add the jsp filename

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegtWEB-INFjsphellojspltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Then we need to retrieve this property in the java class file Spring utilizes the JavaBean style settersgetters toretrievestore properties So all we need to do in the java class is to add a property and its gettersetter TheUserHomeController is modified as follows

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here the filename of the view is externalized When the framework reads the settings for the java class it will use thesetter to set the property viewFilename and the value in the configuration file

Further in the J2EE standard the document root is accessible by users through web So if we want to hide the jsp pagesfrom users for security and other reasons we have to move these jsp files to the WEB-INF(all capital letters) directoryTo organize files in a better way we move all jsp files to WEB-INFjsp So every jsp reference has to pre-append thispath To avoid extra typing letrsquos modify the users-servletxml again

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 5: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 5 of 42

users-servletxml

webxml

Client DispatcherServlet Controllers Business Logic Layer

viewResolver

urlMapping between URLs andcontroller

31 2

456

We are going to walking through this configuration file to show how to set up controllers models and views Howeversince the view components involve other libraries we wonrsquot be able to discuss it in here but merely just mention someof them We are going to use JSPJSTL in this document (ie the view is fixed)

If you donrsquot want to use the default users-servletxml you may do the following to specify your files

ltservletgtltservlet-namegtusersltservlet-namegtltservlet-classgtorgspringframeworkwebservletDispatcherServletltservlet-classgtltinit-paramgtltparam-namegtcontextConfigLocationltparam-namegt

ltparam-valuegtWEB-INFmy1-servletxmlWEB-INFmy2-controllersxmlltparam-valuegtltinit-paramgt

ltservletgt

4 Get startedFor the time being letrsquos ignore the models and start with some simple cases on the controllers

41 Return a static htmljsp page with a hard coded destinationIn this case we have just one page hellojsp under WEB-INFjsp

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltmdash Mapping definitions map urls to action ids --gtltbean id=urlMapping class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggt

ltproperty name=mappingsgtltpropsgt

ltprop key=userhomehtmgtuserHomeActionltpropgtltpropsgt

ltpropertygtltbeangt

lt-- Action definitions --gtltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 6 of 42

Here we define a URL userhomehtm (after web context) to an action userHomeAction (remember in webxml we mapall htm to the servlet named users) which in turns is mapped to the java class userHomeController

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

This class implements the Controller interface that has only one method The DispatcherServlet reads the configurationfile to get the name of this class instantiate it and call this method

The referenced JSP is very simple

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

The result is just showing the page

The second part of the configuration file is to define the JSTL view If you want to use other views this is the place youshould play with In our case this part will remain the same throughout this document since we are not going to useother view components eg Velocity Tapestry or XSLT

Note1 If empty string ldquordquo is returned the web document root is shown if not indexhtml (remember htm is mapped to

our actions so donrsquot use indexhtm) exists If null is returned the output would be empty and no error is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 7 of 42

thrown In fact we could write directly to the response and return null (although itrsquos not a good way to do so)This is the way to tell the framework that we are handling the view by ourselves We will come back to thislater for request forwarding and redirecting

2 Although this is a very simple example it shows the big picture about how the framework works get familiarwith how the DispatcherServlet calls the Controller implementation class

3 The general flow is as followswebxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxmlltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean id=urlMapping

class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggtltproperty name=mappingsgt

ltpropsgtltprop key=userhomehtmgtuserHomeActionltpropgt

ltpropsgtltpropertygt

ltbeangt

ltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

ltbeansgt

The config file users-servletxml handles mappings between URLs and the corresponding controllers and views Keepthis in mind since itrsquos the core of the framework It allows us to work straight on JSP files and controller classes

In users-servletxml in the above notice that there are two mappings within the file This can be further simplified usingBeanNameUrlHandlerMapping class (implicitly)

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

By default BeanNameUrlHandlerMapping class is used if no handler mapping found (ie if we remove theUrlMapping bean) The URL HandlerMapping is either all or none

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 8 of 42

42 Return a named view pageIn UserHomeController class we hard coded the jsp filename This is usually not a desired way to do so Now we aremaking it dynamic First modify the users-servletxml file to add the jsp filename

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegtWEB-INFjsphellojspltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Then we need to retrieve this property in the java class file Spring utilizes the JavaBean style settersgetters toretrievestore properties So all we need to do in the java class is to add a property and its gettersetter TheUserHomeController is modified as follows

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here the filename of the view is externalized When the framework reads the settings for the java class it will use thesetter to set the property viewFilename and the value in the configuration file

Further in the J2EE standard the document root is accessible by users through web So if we want to hide the jsp pagesfrom users for security and other reasons we have to move these jsp files to the WEB-INF(all capital letters) directoryTo organize files in a better way we move all jsp files to WEB-INFjsp So every jsp reference has to pre-append thispath To avoid extra typing letrsquos modify the users-servletxml again

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 6: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 6 of 42

Here we define a URL userhomehtm (after web context) to an action userHomeAction (remember in webxml we mapall htm to the servlet named users) which in turns is mapped to the java class userHomeController

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

This class implements the Controller interface that has only one method The DispatcherServlet reads the configurationfile to get the name of this class instantiate it and call this method

The referenced JSP is very simple

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

The result is just showing the page

The second part of the configuration file is to define the JSTL view If you want to use other views this is the place youshould play with In our case this part will remain the same throughout this document since we are not going to useother view components eg Velocity Tapestry or XSLT

Note1 If empty string ldquordquo is returned the web document root is shown if not indexhtml (remember htm is mapped to

our actions so donrsquot use indexhtm) exists If null is returned the output would be empty and no error is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 7 of 42

thrown In fact we could write directly to the response and return null (although itrsquos not a good way to do so)This is the way to tell the framework that we are handling the view by ourselves We will come back to thislater for request forwarding and redirecting

2 Although this is a very simple example it shows the big picture about how the framework works get familiarwith how the DispatcherServlet calls the Controller implementation class

3 The general flow is as followswebxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxmlltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean id=urlMapping

class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggtltproperty name=mappingsgt

ltpropsgtltprop key=userhomehtmgtuserHomeActionltpropgt

ltpropsgtltpropertygt

ltbeangt

ltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

ltbeansgt

The config file users-servletxml handles mappings between URLs and the corresponding controllers and views Keepthis in mind since itrsquos the core of the framework It allows us to work straight on JSP files and controller classes

In users-servletxml in the above notice that there are two mappings within the file This can be further simplified usingBeanNameUrlHandlerMapping class (implicitly)

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

By default BeanNameUrlHandlerMapping class is used if no handler mapping found (ie if we remove theUrlMapping bean) The URL HandlerMapping is either all or none

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 8 of 42

42 Return a named view pageIn UserHomeController class we hard coded the jsp filename This is usually not a desired way to do so Now we aremaking it dynamic First modify the users-servletxml file to add the jsp filename

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegtWEB-INFjsphellojspltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Then we need to retrieve this property in the java class file Spring utilizes the JavaBean style settersgetters toretrievestore properties So all we need to do in the java class is to add a property and its gettersetter TheUserHomeController is modified as follows

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here the filename of the view is externalized When the framework reads the settings for the java class it will use thesetter to set the property viewFilename and the value in the configuration file

Further in the J2EE standard the document root is accessible by users through web So if we want to hide the jsp pagesfrom users for security and other reasons we have to move these jsp files to the WEB-INF(all capital letters) directoryTo organize files in a better way we move all jsp files to WEB-INFjsp So every jsp reference has to pre-append thispath To avoid extra typing letrsquos modify the users-servletxml again

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 7: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 7 of 42

thrown In fact we could write directly to the response and return null (although itrsquos not a good way to do so)This is the way to tell the framework that we are handling the view by ourselves We will come back to thislater for request forwarding and redirecting

2 Although this is a very simple example it shows the big picture about how the framework works get familiarwith how the DispatcherServlet calls the Controller implementation class

3 The general flow is as followswebxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(WEB-INFjsphellojsp)

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxmlltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean id=urlMapping

class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMappinggtltproperty name=mappingsgt

ltpropsgtltprop key=userhomehtmgtuserHomeActionltpropgt

ltpropsgtltpropertygt

ltbeangt

ltbean id=userHomeAction class=orgspringwebtestUserHomeControllergt

ltbeansgt

The config file users-servletxml handles mappings between URLs and the corresponding controllers and views Keepthis in mind since itrsquos the core of the framework It allows us to work straight on JSP files and controller classes

In users-servletxml in the above notice that there are two mappings within the file This can be further simplified usingBeanNameUrlHandlerMapping class (implicitly)

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

By default BeanNameUrlHandlerMapping class is used if no handler mapping found (ie if we remove theUrlMapping bean) The URL HandlerMapping is either all or none

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 8 of 42

42 Return a named view pageIn UserHomeController class we hard coded the jsp filename This is usually not a desired way to do so Now we aremaking it dynamic First modify the users-servletxml file to add the jsp filename

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegtWEB-INFjsphellojspltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Then we need to retrieve this property in the java class file Spring utilizes the JavaBean style settersgetters toretrievestore properties So all we need to do in the java class is to add a property and its gettersetter TheUserHomeController is modified as follows

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here the filename of the view is externalized When the framework reads the settings for the java class it will use thesetter to set the property viewFilename and the value in the configuration file

Further in the J2EE standard the document root is accessible by users through web So if we want to hide the jsp pagesfrom users for security and other reasons we have to move these jsp files to the WEB-INF(all capital letters) directoryTo organize files in a better way we move all jsp files to WEB-INFjsp So every jsp reference has to pre-append thispath To avoid extra typing letrsquos modify the users-servletxml again

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 8: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 8 of 42

42 Return a named view pageIn UserHomeController class we hard coded the jsp filename This is usually not a desired way to do so Now we aremaking it dynamic First modify the users-servletxml file to add the jsp filename

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN

httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegtWEB-INFjsphellojspltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygt

ltbeangtltbeansgt

Then we need to retrieve this property in the java class file Spring utilizes the JavaBean style settersgetters toretrievestore properties So all we need to do in the java class is to add a property and its gettersetter TheUserHomeController is modified as follows

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here the filename of the view is externalized When the framework reads the settings for the java class it will use thesetter to set the property viewFilename and the value in the configuration file

Further in the J2EE standard the document root is accessible by users through web So if we want to hide the jsp pagesfrom users for security and other reasons we have to move these jsp files to the WEB-INF(all capital letters) directoryTo organize files in a better way we move all jsp files to WEB-INFjsp So every jsp reference has to pre-append thispath To avoid extra typing letrsquos modify the users-servletxml again

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 9: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 9 of 42

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangtltbeansgt

These two lines will remove the need to add path WEB-INFjsp and jsp for all references So the value hello isautomatically mapped to WEB-INFjsphellojsp Another benefit is that this mapping decouples views from resources

This example shows not only how to externalize settings but also the convenience to change configurations especiallyduring refactoring Imaging when we begin with a prototype hardcode all settings and then later on we need to refactorthem out

Now our configuration is somewhat like this

webxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE web-app PUBLIC -Sun Microsystems IncDTD WebApplication 23ENhttpjavasuncomdtdweb-app_2_3dtdgt

ltweb-appgtltservletgt

ltservlet-namegtusersltservlet-namegtltservlet-classgt

orgspringframeworkwebservletDispatcherServletltservlet-classgt

ltservletgt

ltservlet-mappinggtltservlet-namegtusersltservlet-namegtlturl-patterngthtmlturl-patterngt

ltservlet-mappinggt

lttaglibgtlttaglib-urigtspringlttaglib-urigtlttaglib-locationgtWEB-INFspringtldlttaglib-locationgt

lttaglibgtltweb-appgt

Controller implementation class

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest requestHttpServletResponse response) throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

hellojsp

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello usersltPgt

ltBODYgtltHTMLgt

users-servletxml

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

ltbeansgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 10: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 10 of 42

Itrsquos much better and cleaner now This will serve as the base for us to expand and add more code

43 Error pagesErrorException handling (and logging) is one of the important indicators to judge the maturity of a framework Letrsquosjump into this right away to have a quick lookIf for some reason we get an exception in the Controller implementation we would get an empty page if we donrsquot doanything particular This is the default behavior and is desirable for security and other reasons However if we want toshow users some related info(Itrsquos a courtesy to show our mercy or itrsquos time to show our power) we could add someconfiguration to the users-servletxml Spring is flexible to catch any kinds of exceptions and show to the users

ltxml version=10 encoding=UTF-8gtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- Action definitions --gtltbean name=userhomehtm class=orgspringwebtestUserHomeControllergt

ltproperty name=viewFilenamegtltvaluegthelloltvaluegtltpropertygtltbeangt

lt-- This is to define jstl view --gtltbean id=viewResolver

class=orgspringframeworkwebservletviewInternalResourceViewResolvergtltproperty name=viewClassgt

ltvaluegtorgspringframeworkwebservletviewJstlViewltvaluegtltpropertygtltproperty name=prefixgtltvaluegtWEB-INFjspltvaluegtltpropertygtltproperty name=suffixgtltvaluegtjspltvaluegtltpropertygt

ltbeangt

ltbean id=exceptionResolverclass=orgspringframeworkwebservlethandlerSimpleMappingExceptionResolvergt

ltproperty name=exceptionMappingsgtltpropsgt

ltprop key=javasqlSQLExceptiongtcaughtexceptionltpropgtltprop key=javalangRuntimeExceptiongtcaughtexceptionltpropgt

ltpropsgtltpropertygt

ltbeangtltbeansgt

This will use the named jsp files to render exceptions named in the key fields ie the SQLException andRuntimeException will be displayed in WEB-INFjspcaughtexceptionjsp The jsp file could be like this

lthtmlgtltheadgtlttitlegtSystem failurelttitlegtltheadgtltbodygt

lt Exception ex = (Exception)requestgetAttribute(ldquoExceptionrdquo) gtltH2gtSystem failure cause lt exgetMessage() gtltH2gtltPgtlt exprintStackTrace(new javaioPrintWriter(out) gt

ltbodygtlthtmlgt

In this scenario javalangException and others will be uncaught In order to display any errors from those exceptionswe could add entries in webxml and supply the uncaughtexceptionjsp

lterror-pagegtltexception-typegtjavalangExceptionltexception-typegtltlocationgtWEB-INFjspuncaughtexceptionjspltlocationgt

lterror-pagegt

This works on WebSphere and WebLogic servers but doesnrsquot work on Tomcat which uses the lterror-codegt tag Irsquollleave this part out since the matter is really application server related and has nothing to do with the framework

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 11: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 11 of 42

44 Forward and redirectItrsquos straight forward to redirect to a different URL Here is the controller code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletviewRedirectView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(new RedirectView(thisgetViewFilename()))

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Here is the change to the users-servletxmllt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtspringuserhomehtmltvaluegtltpropertygtltbeangt

Here we will redirect to the userhomehtm Keep in mind the URL we redirect is from document root not from webcontext root so we have to append spring in the front

Another way to redirect to a URL is using HttpServletResponse object Here is the code

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

responsesendRedirect(thisgetViewFilename())return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

Again the URL is from the document root Here we have to return null to signal that we handle the view

The forwarding is similar Here is the codepackage orgspringwebtest

import orgspringframeworkwebservletmvcController

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 12: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 12 of 42

import orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class URLRedirectController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

requestgetRequestDispatcher(thisgetViewFilename())forward(request response)return null

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The forwarded URL is relative to the web context

lt-- redirect action --gtltbean name=redirecthtm class=orgspringwebtestURLRedirectControllergt

ltproperty name=viewFilenamegtltvaluegtuserhomehtmltvaluegtltpropertygtltbeangt

Another useful class for forwardingincluding is orgspringframeworkwebservletviewInternalResourceViewCheck the java doc on this class

Comments1 The redirect URL will be shown in browser while the forward URL wonrsquot2 Redirect could go out of the current web context while forward canrsquot3 Chain actions Since the web layer is very small normally there is no need to chain the controllers together

because the only functionality is to send out the view However in some cases when we want to avoidduplicated code we want to chain certain controllers together For example certain global pulldown menushown in every page or certain breadcrumbs Right now this is not supported and itrsquos hard to change the codeto support this because of the restriction on errorsgetModel() (see below) Another way to do this is throughinterceptors where we can just pass back the models not the views

4 In terms of workflow we might need to chain actions there is a wizard form controller5 include should work in the same way

Up to now we concentrate only on the Controller component Before we dive further letrsquos switch to the modelcomponent for a while As we all know web applications usually have inputoutput

45 Dynamic output fieldsIrsquove seen some inflexible JSP frameworks They map an URL to a setting for the controller Before the controller sendsout the corresponding JSP view it creates the necessary bean for the JSP It retrieves the name of the bean from thesetting initialize it call the interface method to do other tasks and return the bean The logic seems perfect but theresult is that you can specify only one bean per JSP and thus force us to make a big jumbo bean for various outputsHowever in Spring the controller can return a Map object which could hold more than one object So Spring and otherframeworks do a better job so we could return as many objects as we wantNow letrsquos modify the above hello example to output two fields

ltHTMLgtltHEADgtltTITLEgtAdminltTITLEgtltHEADgtltBODYgt

ltH1gtSimple hard coded destination pageltH1gtltPgtHello ltcout value=rdquo$(user)rdquogt time is ltcout value=rdquo$(now)rdquogtltPgt

ltBODYgtltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 13: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 13 of 42

Here we add two fields user and now which are passed in from the controller

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class UserHomeController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Map data = new HashMap()dataput(now new javautilDate()toString())dataput(user Spring user)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

The controller passes a Map object back to the view The map contains arbitrary numbers of objects

Now letrsquos take a look at how to output some dynamic data and dynamic structure such as dynamic fields lists tablesetc The next example is that infamous ldquoyoursquove got mailrdquo example Here is the JSP file

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtDynamic fieldltTITLEgtltHEADgtltBODYgt

ltH1gtDo you see this message ltH1gtltPgt[

ltcif test=$newmail gt 0gtltcout value=$messagegt

ltcifgt]ltpgt

ltBODYgtltHTMLgt

When newmail gt 0 it will print out the message Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

public class DynamicFieldController implements Controller

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 14: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 14 of 42

Map data = new HashMap()dataput(newmail new Integer(-5))dataput(message Youve got mail)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

And we add a URL mapping in users-servletxml too

lt-- dynamic field action --gtltbean name=dynfieldhtm class=orgspringwebtestDynamicFieldControllergt

ltproperty name=viewFilenamegtltvaluegtdynamicfieldltvaluegtltpropertygtltbeangt

Try to change the value for newmail in the controller to see if you can get the message

46 Input and formsNow itrsquos time to talk about the problematic input issues The reason why input is troublesome is the mismatch betweenhtml form input and java objects similar to the misalignment between SQL and java objects When a request isreceived on the server side we get input by hardcoded keys The retrieval of values using keys is as evil as writingHTML out in servlets and thus should be encapsulated

Example 1 get values from keysFirst letrsquos create two JSP pages one is input1jsp for input form another is result1jsp for output Here is input1jsp

ltHTMLgtltHEADgtltTITLEgtInput 1 - Form based inputltTITLEgtltHEADgtltBODYgtltFORM name=rdquouserFormrdquo action=rdquospringinputposthtmrdquo method=rdquoPOSTrdquogt

Username ltBRgtltINPUT type=rdquotextrdquo name=rdquousernamerdquo size=rdquo32rdquogtltBRgtltINPUT type=rdquosubmitrdquo value=rdquo Try me ldquogt

ltFORMgtltBODYgtltHTMLgt

It has only one input field named username Here is result1jsp it just printout the input

lta taglib prefix=rdquocrdquo uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 1 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=rdquo$usernamerdquogtltPgt

ltBODYgtltHTMLgt

Next we need to get two controllers done Here is Input1ShowControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndView

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

public class Input1ShowController implements Controller

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 15: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 15 of 42

private String viewFilename

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

return new ModelAndView(thisgetViewFilename())

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It just returns the input form And here is Input1PostControllerjava

package orgspringwebtest

import orgspringframeworkwebservletmvcControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindRequestUtils

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautilMapimport javautilHashMap

import orgapachecommonslogging

public class Input1PostController implements Controller

private String viewFilenameprotected final Log logger = LogFactorygetLog(getClass())

public ModelAndView handleRequest(HttpServletRequest request HttpServletResponse response)throws Exception

String username = RequestUtilsgetRequiredStringParameter(request username)loggerdebug(The username= + username)

Map data = new HashMap()dataput(username username)return new ModelAndView(thisgetViewFilename() data)

public void setViewFilename(String name) thisviewFilename = name public String getViewFilename() return thisviewFilename

It gets the input from the request We are using a utility class from Spring Of course you can get it directly from therequest In either way the problem is the hardcoded field names username in this case Wersquoll come back to this in thenext caseAnd we also add the debug statementFinally we need to hook these files together in users-servletxml as shown in the following

ltxml version=rdquo10rdquo encoding=rdquoUTF-8rdquogtltDOCTYPE beans PUBLIC -SPRINGDTD BEANEN httpwwwspringframeworkorgdtdspring-beansdtdgt

ltbeansgtlt-- input1 show action --gtltbean name=input1showhtm class=orgspringwebtestInput1ShowControllergt

ltproperty name=viewFilenamegtltvaluegtinput1ltvaluegtltpropertygtltbeangt

lt-- input1 post action --gtltbean name=input1posthtm class=orgspringwebtestInput1PostControllergt

ltproperty name=viewFilenamegtltvaluegtresult1ltvaluegtltpropertygtltbeangt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 16: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 16 of 42

ltbeansgt

Next we are going to show another way to work on this show-post scenario Also from now on for simplicity we omitthe last two bean settings viewResolver and exceptionResolver replace them by hellip in the file

5 Spring Controllers and TagsSo far in the previous examples we always implemented the Controller interface Besides the interface Springprovides some implementations for the Controller as well to save some effort for users Here is the hirachy of Springclasses

AbstractController

BurlapServiceExporter

Controller

ParameterizableViewController

HessianServiceExporter

BaseCommandController

MultiActionController

AbstractFormControllerAbstractCommandController

AbstractWizardFormController SimpleFormController

UrlFilenameViewController

WebContentGenerator

ApplicationObjectSupport

ApplicationContextAware

WebApplicationObjectSupport

Validator ServletRequestDataBinder

DataBinder BindException

We are not going to go through all of them However it would be better if you could go through the source code ofeach class to get familiar with them and understand the purposesfunctionalities I also include some related classessome of which will be used later

Letrsquos start with SimpleFormController

51 SimpleFormControllerLetrsquos consider the example in Section $46 and re-implement it using SimpleFormController to see how convenient it isto use Spring classesHere is the change to the input1jsp saved in input2jsp

ltHTMLgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 17: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 17 of 42

ltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=springinput1posthtm method=POSTgt

Usernameltspringbind path=commandgt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

The big change is the tag ltspringbindgt The command is the default name for the input class which we will declare asString later This tag will bind the input field to the String Here is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input1SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

String formBean = (String)command

Map model = errorsgetModel()modelput(username formBean) return null in order to get to the success view defined in xmlreturn new ModelAndView(thisgetSuccessView() model)

The method onSubmit() is called when the input is submitted The important change is the String casting This is a nicefeature in Spring ndash we just start working on objects no more data filling in Since we using the spring tagltspringbindgt we have to include the error model Errors in the command object Also keep in mind theerrorsgetModel() can be called only once If you call twice the data that you put in before the second call will be lostHere are several other ways to do this (from forums)

protected ModelAndView onSubmit(Object command BindException errors)

Map myModel = new HashMap()myModelputAll(errorsgetModel())return new ModelAndView(getSuccessView() myModel)

or call the onSubmit(hellip) method in the supper class which will do this for you or override the methoddoSubmitAction(Object command)

If you donrsquot do the above you would get that infamous exception

javaxservletjspJspTagExceptionCould not find Errors instance for bean xxxxxx in request add the Errors model to yourModelAndView via errorsgetModel()

which confuses some of the beginners

Here is the change in users-serlvetxml

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 18: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 18 of 42

ltbean name=input1simpleformhtm class=orgspringwebtestInput1SimpleFormControllergtltproperty name=commandClassgtltvaluegtjavalangStringltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput2ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult1ltvaluegtltpropertygt

ltbeangt

Here we declare the commandClass to be String so that we could cast the command object to String in the controllerclass The formView and successView are just properties in SimpleFormController We use just one controller for twoactions get the page and submit the input So we specify the formView to get the page and specify the successView tosend the input The extra property commandClass is to tell the framework the data class of the input This is really a badname at first sight A better name should be formBeanClass however from the framework point of view this is areasonable name

So in here we donrsquot need the Input1ShowController class anymore (It does nothing more than showing the page) Thespringbind tag encapsulates the HTML input to a java Object so we donrsquot need to retrieve values by hardcoded keysand thus decouple the dependencies on the keys (In addition it has more functionalities that we will unfold later)

The underlying logic is as follows

The default name for the binding is command or the name specified in the commandName fieldThe command object is initialized in the GET method of the form servlet (check AbstractFormController) To beprecise itrsquos in formBackingObject() method called by GET method

The input object should not be the business object directly as suggested by others The business layer should have aninterface to cast out the implementation of the input

The spring tag ltspringbindgt will bind the input fields and does more Here is a little bit more complicated exampleWe are going to create a java bean with two fields username and age

package orgspringwebtest

public class Input3Bean

String usernameint age

public void setUsername(String name) username = name public String getUsername() return username

public void setAge(int age) thisage = age public int getAge() return age

Note If we donrsquot initialized username and age here it means they are required Here is the JSP file with these twofields

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=username size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=age size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 19: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 19 of 42

ltFORMgtltbodygtltHTMLgt

And the result page is here

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$usernamegt and ltcout value=$agegtltpgt

ltBODYgtltHTMLgt

Since we are going to use the newly-created java bean Input3Bean as the input the command is referencing this beanand thus has two fields Besides the binding we add a message output from the status If we type in non-numeric lettersin the second field age we should see a binding error message from this field

The next step is the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input3SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input3Bean formBean = (Input3Bean)command

Map model = errorsgetModel()modelput(username formBeangetUsername())modelput(age new Integer(formBeangetAge()))

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())return refData

The second method sends back the same action in the form when we show the input page Because we are using thesame URL for the action we just return where we are coming from If you want to bind the error object in thereferenceData() you could do the following

BindException anotherCommand = new BindException(new MyCommand() myCommand)dataputAll(anotherCommandgetModel())

See section 61 for more info

The last piece is the change in the users-servletxml

ltbean name=input3simpleformhtm class=orgspringwebtestInput3SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput3Beanltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 20: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 20 of 42

ltproperty name=formViewgtltvaluegtinput3ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult3ltvaluegtltpropertygt

ltbeangt

Letrsquos take a look at the input JSP page input3jsp Here we bind the input field username to the java bean fieldusername Here the input field name of the HTML page may not be the same as the field in java bean because thebinding will do the mapping automatically Another way to do this is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32gtltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgt

ltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We utilize the statusexpression field this set the HTML input field name to the java bean name automatically Noticingthat when we type in non-numeric letters into the second field age we get an error and whatever we typed in is gonetoo In order to preserve the data from previous input letrsquos modify the above code again

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 3 - Form based inputlttitlegtltheadgtltbodygtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

Usernameltspringbind path=commandusernamegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtAgeltspringbind path=commandagegt

ltINPUT type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgt

ltfont color=redgtltcout value=$statuserrorMessagegtltfontgtltbrgtltspringbindgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

We add the value attributes for the input fields Furthermore we can use statusvalue to pass any prepopulated data tothe form For example add the following method to the controller class

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input3Bean formBean = new Input3Bean()formBeansetAge(5)formBeansetUsername(your name)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 21: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 21 of 42

return formBean

Then the value ldquoyour namerdquo and ldquo5rdquo should show up in the form So form updates could utilize this feature

52 More settings on SimpleFormControllerBesides commandClass formView and successView here are some more properties we could setl commandName You can give a name reference to the command class and then reference this name in the jsp file

This gives a meaning to the command object in JSP files but also creates a reference dependency So itrsquos up to youwhether you want to use it or not commandName and commandClass are from BaseCommandController class

l validator from BaseCommandController class tool validateOnBinding from BaseCommandController class tool bindOnNewForm from AbstractFormController classl sessionForm from AbstractFormController class itrsquos said that if this is true the command object will be created

on a GET method and stored in the session Once the POST is completed the object will be removed We have tobe careful in here because a browser and all child browsers(File|New) share the same session Another effect ofthis setting is that it does not allow users to click back buttons because the object is removed after the post

l synchronizeOnSession from AbstractController classPlease refere to the documents on the classes or source code if you have doubt on how to use them

53 Bind multiple fieldsIn section 51 we talked about the field binding ie bind each individual field In this section we talk about theform binding Letrsquos change the input3jsp to input4jsp as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 4 - Form based inputlttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtlt-- or use the followingltcforEach items=$statuserrorMessages var=errorgt

Error code ltcout value=$errorgtltbrgtltcforEachgt--gt

ltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandgtUsername

ltINPUT type=text name=username size=32 value=ltcout value=$commandusernamegtgtAge

ltINPUT type=text name=age size=32 value=ltcout value=$commandagegtgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we use just one pair of ltspringbindgt to bind all the fields in the form Of course in here we have to specify allthe field names Another side effect is that the wrong input will be shown in the error message and not updated in theinput field(which contains only the original value) The possible errors are outside the form too not along the fieldsides because they are for all the fieldsThis approach and the approach in section 51 each has their own merits and shortcomings Itrsquos up to you whichapproach you want to take Personally I think Springrsquos way is better because we donrsquot need to hard code field namesthe error messages are specific to fields and the values are up to date

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 22: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 22 of 42

54 Select from a listarraysetmapMapListSetarrays caseIf you want to populate a pulldown menu check the docs for ltspringbindgt ltspringtransformgtHere is a simple usage create a pulldown menu for month selection convert numerical months to abbreviations Letrsquosstart with the input bean

package orgspringwebtest

public class Input5Bean

private String month

public String getMonth() return month public void setMonth(String month) thismonth = month

There is only one field month with values from 0-11 for 12 months The JSP file input5jsp is as follows

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 5 - Listslttitlegtltheadgtltbodygtltspringbind path=commandgt

ltFONT color=redgtltBgtltcout value=$statuserrorMessagegtltBgtltBRgtltFONTgtltspringbindgtltFORM name=userForm action=ltcout value=$actionUrlgt method=POSTgt

ltspringbind path=commandmonthgtBirth Month

ltselect name=monthgtltcforEach var=month items=$monthsgt

ltspringtransform value=$month var=monthNamegtltcif test=$statusvalue == monthNamegt

ltoption value=ltcout value=$monthNamegt selectedgtltcifgtltcif test=$statusvalue = monthNamegt

ltoption value=ltcout value=$monthNamegtgtltcifgt

ltcout value=$monthNamegtltoptiongt

ltcforEachgtltselectgt

ltspringbindgtltINPUT type = submit value= Try gtltspringbindgt

ltFORMgtltbodygtltHTMLgt

Here we have the mapping to map month to monthName using ltspringtransformgt tag This tag uses a PropertyEditorto convert a number to a month abbreviation (A side note is that ltcifgt block canrsquot be inside the option tag in mysetting so I take a long shot here just donrsquot have time to figure out that but this is not the point here)

package orgspringwebtest

import javabeansPropertyEditorSupport

public class MonthConvertPropertyEditor extends PropertyEditorSupport

public MonthConvertPropertyEditor()

public String getAsText()

if (thisgetValue() == null || (thisgetValue() instanceof String)) return

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 23: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 23 of 42

String text = ((String)thisgetValue())if (textequals(0)) return Janelse if (textequals(1)) return Febelse if (textequals(2)) return Marelse if (textequals(3)) return Aprelse if (textequals(4)) return Mayelse if (textequals(5)) return Junelse if (textequals(6)) return Julelse if (textequals(7)) return Augelse if (textequals(8)) return Septelse if (textequals(9)) return Octelse if (textequals(10)) return Novelse if (textequals(11)) return Decelse return text

public void setAsText(String text)

if (textequals(Jan)) setValue(0)else if (textequals(Feb)) setValue(1)else if (textequals(Mar)) setValue(2)else if (textequals(Apr)) setValue(3)else if (textequals(May)) setValue(4)else if (textequals(Jun)) setValue(5)else if (textequals(Jul)) setValue(6)else if (textequals(Aug)) setValue(7)else if (textequals(Sept)) setValue(8)else if (textequals(Oct)) setValue(9)else if (textequals(Nov)) setValue(10)else if (textequals(Dec)) setValue(11)else setValue()

We register this PropertyEditor in the controller class

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebbindServletRequestDataBinderimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input5SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input5Bean formBean = (Input5Bean)command

Map model = errorsgetModel()modelput(month formBeangetMonth())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()refDataput(actionUrl requestgetRequestURI())

List list = new ArrayList()for (int i=0 ilt12 i++)

listadd(i + )refDataput(months list)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 24: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 24 of 42

return refData

protected void initBinder(HttpServletRequest request ServletRequestDataBinder binder)

superinitBinder(request binder)binderregisterCustomEditor(Stringclass month new MonthConvertPropertyEditor())

protected Object formBackingObject(HttpServletRequest request) throws Exception

Input5Bean formBean = new Input5Bean()formBeansetMonth(5)

return formBean

Here we register the PropertyEditor only for the input field month so it wonrsquot interfere with other fields If a globalPropertyEditor is desired we can set it up in the users-servletxml for example add the following to the file

ltbean id=customEditorConfigurer class=orgspringframeworkbeansfactoryconfigCustomEditorConfigurergtltproperty name=customEditorsgt

ltmapgtltentry key=javalangStringgt

ltbean class=orgspringwebtestMonthConvertPropertyEditorgtltentrygt

ltmapgtltpropertygt

ltbeangt

This will cause to use the specified PropertyEditor on all Strings The benefit of using a PropertyEditor is that weseparate the mapping from the view and controller

Similarly we could add custom PropertyEditors for say BigDecimal or converting null to 0 etc If you are notfamiliar with the PropertyEditor class read core java book

The rest of configuration is omitted since you should be able to figure it out by now

55 Bind more than one field in HTML formsIn the last example in essence we export a ListMapetc to the page Now we take a look on how to input aListMapetc from HTML forms to the controllersExample 1 How to bind two separate two fields to one java bean field eg bind DDMMYY and HHmm to a singleDate object or bind last name and first name to a single common name object

a use the same field name for both fields then you get comma-seperated values for bothb Override BaseCommandControllerrsquos onBind() or onBindAndValidate() read in both pass out one and set the

value to the command objectHere is the simple code for this approach The input jsp(input6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygtltFORM name=userForm action=springinput6simpleformhtm method=POSTgt

ltspringbind path=commandgtFirst name ltINPUT type=text name=commonname size=32gtltBRgtLast name ltINPUT type=text name=commonname size=32gtltBRgt

ltspringbindgtltINPUT type = submit value= Try gt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 25: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 25 of 42

ltFORMgtltbodygtltHTMLgt

The output JSP (result6jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 6 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtltcout value=$commonnamegtltpgt

ltBODYgtltHTMLgt

The bean class is

package orgspringwebtest

public class Input6Bean

private String commonname

public String getCommonname() return commonname public void setCommonname(String common) commonname = common

The controller class is

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import javautil

public class Input6SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Input6Bean formBean = (Input6Bean)command

Map model = errorsgetModel()modelput(commonname formBeangetCommonname())

return new ModelAndView(thisgetSuccessView() model)

protected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input6Bean formBean = (Input6Bean)commandformBeansetCommonname(formBeangetCommonname()replace( ))

In onBindAndValidate() we replace the comma by a space in order to have a common name(reformat the input) Thecomma is introduced by HTML And finally here is configuration is users-xml

ltbean name=input6simpleformhtm class=orgspringwebtestInput6SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput6Beanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput6ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult6ltvaluegtltpropertygt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 26: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 26 of 42

ltbeangt

Although this is working and interesting I personally donrsquot recommend this approach because this breaks other thingseg error handling updated values Instead we should just create each field in a java bean and ldquodenormalizerdquo itsomewhere else one could add extra field to hold the composite value and use the lifecycle method(init) to populate thisfield

Example 2 How to bind a list of objects Spring is capable of handling ListMapArray

package orgspringwebtest

import javautil

public class Input7Bean

sub of CollectionMapIteratorEnumerationcomma-seperated Stringsprivate List phoneList

public Input7Bean ()

phoneList = new ArrayList()phoneListadd(new String())phoneListadd(new String())phoneListadd(new String())

public List getPhoneList() return phoneList public void setPhoneList(List monthsList) thisphoneList = monthsList

Here we populate 3 String fields for the input in the list We are just using SimpleFormController class Letrsquos look at theinput JSP input7jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 6 - Combine two fields into onelttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput7simpleformhtm method=POSTgt

ltcforEach var=phone items=$commandphoneList varStatus=loopStatusgtltspringbind path=phonegt

ltinput type=text name=ltcout value=$statusexpressiongt size=32value=ltcout value=$statusvaluegtgtltBRgt

ltspringbindgtltcforEachgtltINPUT type = submit value= Try gt

ltFORMgtltbodygtltHTMLgt

Here naturally we would think the phone loop variable is binded to the tag path But this is not working a ldquocan not findErrors collectionrdquo will be prompted out We have to explicitly build the bind path from command

ltspringbind path=commandphoneList[$loopStatusindex]gt

This is because the Spring binding tag doesnrsquot know the loop variable var and thus we have to build the path from thecommand object which is recognized by Spring

The ltcforEachgt tag would work with CollectionIteratorEnumerationMap the ltspringbindgt path should work withthem too the only doubt class is Set If itrsquos not working use toArray() I donrsquot have time to check on this yet

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 27: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 27 of 42

56 Boolean radio buttons checkboxes and multiple selectionsRadio buttons fine simple examplesCheckboxes troublemaker The root cause of this is in HTML if a checkbox is not checked then this field will not besent to the server and thus the server doesnrsquot even know this field exists and consequently will not updatereset thevalue If we blindly reset all the fields that do not have an input then the wizard form which has a form object thatspans several pages would not workThere are several remedies on this

1 If all you want is just truefalse use a pulldown menu with truefalse2 You may use javascript to assign some value to a hidden value to be passed back3 You can manually track down these values since you have the knowledge of what fields are there Here is the

code example for this way itrsquos kind of ugly because it creates dependenciespackage orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequest

public class Input8SimpleFormController extends SimpleFormControllerprotected void onBindAndValidate(HttpServletRequest request Object commandBindException errors) throws Exception

Input8Bean formBean = (Input8Bean)command

if (requestgetParameter(checkStatus) == null)

formBeansetCheckStatus(false)

Now you see we have to hardcode the key checkStatus in the code The JSP page (input8jsp) is

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 8 - checkboxlttitlegtltheadgtltbodygt

lth2gtInputlth2gtltFORM name=userForm action=springinput8simpleformhtm method=POSTgt

Checkbox testltspringbind path=commandcheckStatusgt

ltcif test=$statusvaluegtltinput type=checkbox name=ltcout value=$statusexpressiongt

value=true checkedgtltcifgtltcif test=$statusvaluegt

ltinput type=checkbox name=ltcout value=$statusexpressiongtvalue=truegt

ltcifgtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgtltbodygtltHTMLgt

The bean class the result page and the configuration is simple and similar to the above examples so I justleave them out

4 Another way is as followsHere is what we can do in HTML and servlet If we have two fields

ltinput type=checkbox name=test1 value=true checkedgtltinput type=hidden name=test1 value=falsegt

Here is the code to retrieve the value in the servletrequestgetParameter(test1)

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 28: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 28 of 42

If the checkbox is set then the first one will be retrieved by the java code(although the second one is passedbut itrsquos ignored by the java code unless you use requestgetParameterValues(ldquotest1rdquo)) If the checkbox isnot set then the second one is retrieved because the first one is not passed to the server So in any case wecould get the correct value (truefalse)However Spring doesnrsquot use getParameter() to retrieve values but uses getParameterValues() So in this caseit returns the string ldquotruefalserdquo If we add new PropertyEditor to take only the first one it should work

5 Spring is going to add a new convention for this field names with prefix _ will trigger the checkingreset

Multiple selections the same problem as in checkboxesltspringbind path=commandlunchgt

ltselect multiple name=ltcout value=$statusexpressiongtgt size=3gtltoption value=PizzagtPizzaltoptiongtltoption value=NoodlegtNoodleltoptiongtltoption value=RicegtRiceltoptiongtltoption value=SaladgtSaladltoptiongtltoption value=SubwaygtSubwayltoptiongtltoption value=SandwichgtSandwichltoptiongtltoption value=Big MacgtBig Macltoptiongtltoption value=WhoppergtWhopperltoptiongt

ltselectgtltinput type=hidden name=ltcout value=$statusexpressiongtgt

ltspringbindgtThis renders a 3-line select box where you can select multiple values If none are selected the parameter is not present ifthe hidden field is not there else only the hidden field(an empty string in this case) is passed back Again we need acustomized PropertyEditor to rip off the the hidden value at the end of the list Like in the case of checkboxes Spring isgoing to fix this in the next release

Another interesting suggestion add an attribute in the bind to indicate whether this field should be reset I personallythink this is a good idea too but after checking the source code for the binding tag I realize itrsquos not easy if notimpossible to do so

57 ltspringbindgt manipulationHere is a discussion on the Spring taghttpopensourceatlassiancomconfluencespringdisplayDISCWorking+with+Spring+MVCItrsquos an interesting idea though But I donrsquot like it since itrsquos alter the html structure so that you canrsquot see these kinds ofpages in a browser Furthermore I am not sure whether the UI tools dreamweaver or like can support this(maybemaybe not)

6 Form and controller compositionsNow itrsquos time take a look at multiple formscommand objects

61 More than one Form - Multiple command objects and manual bindingNotice that we can specify only one command object in the SimpleFormController class we should be keen enough towonder what if there are more than one form on a page say a table selection form and a general search form

There are several remedies to overrun this limitation

The first one is obvious use ltspringbindgt only in one form not the rest forms After all you donrsquot want to checkerrors on a search page anyway

The second way is to make larger objects through composition(yah as always) It works well until we hit the validationSince we normally fill the data into only one form and ignore the rest we have to check only the active form not all theforms in the validation This results if-else checks in the validation kind of unusual Furthermore the error messagesfor the inactive forms pollute the entire page

The third way is to create a hbm-like config file to do the mapping map each form to a bean just like mapping a table(row) to a bean

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 29: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 29 of 42

The forth way to manully bind the form objects Here is a simple example The input JSP file (input10jsp) is

lt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 1 - Form based inputlttitlegtltheadgtltbodygtForm 1ltBRgtltFORM name=form1 action=springinput10asimpleformhtm method=POSTgt

Usernameltspringbind path=command1usernamegt

ltINPUT type=text name=username size=32gtltBRgtltspringbindgtltINPUT type = submit value= Submit gt

ltFORMgt

Form 2ltBRgtltFORM name=form2 action=springinput10bsimpleformhtm method=POSTgt

Usernameltspringbind path=command2favoritegt

ltINPUT type=text name=favorite size=32gtltBRgtltspringbindgtltINPUT type = submit value= Find gt

ltFORMgtltbodygtltHTMLgt

There are two forms here with different form objects command1 and command2 In the controller class we manuallypopulate them

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javaxservlethttpHttpServletRequestimport javautil

public class Input10SimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Systemoutprintln(com= + commandgetClass()getName())Input10aBean formBean = (Input10aBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(username formBeangetUsername())

return new ModelAndView(thisgetSuccessView() model)

protected Map referenceData(HttpServletRequest request) throws Exception

Map refData = new HashMap()

BindException errorsa = new BindException(new Input10aBean() command1)BindException errorsb = new BindException(new Input10bBean() command2)

refDataputAll(errorsagetModel())refDataputAll(errorsbgetModel())

return refData

In referenceData() we just wrap each object with a BindException object and return them with a Map This is to showthe page To submit the forms one of the posts goes to the onSubmit() in this class another one goes to the followingclass

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 30: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 30 of 42

package orgspringwebtest

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindExceptionimport javautil

public class Input10bSimpleFormController extends SimpleFormController

public ModelAndView onSubmit(Object command) throws Exception

Input10bBean formBean = (Input10bBean)command

BindException errors = new BindException(command command)Map model = errorsgetModel()modelput(favorite formBeangetFavorite())

return new ModelAndView(thisgetSuccessView() model)

Now we have two separate controllers with their own validation paths The two result pages are simple

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10a resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtusername ltcout value=$usernamegtltpgt

ltBODYgtltHTMLgt

and

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 10b resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgtfavorite ltcout value=$favoritegtltpgt

ltBODYgtltHTMLgt

The last piece is the config file

ltbean name=input10asimpleformhtm class=orgspringwebtestInput10SimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10aBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10altvaluegtltpropertygt

ltbeangt

ltbean name=input10bsimpleformhtm class=orgspringwebtestInput10bSimpleFormControllergtltproperty name=commandClassgtltvaluegtorgspringwebtestInput10bBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput10ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult10bltvaluegtltpropertygt

ltbeangt

The commandClass field has to be the class you want to cast in the onSubmit() method

Of course we could externalize the list of form beans just as we do with the command bean Also each action has itsown validation doesnrsquot interfere with other form beans

62 Chained controllersHere is a chained controller class from the Spring forum

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 31: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 31 of 42

package orgspringwebtest Controller that does a similar thing but is much more flexible It will allow you chain any number of Controllers to handle a single request

The rules that must be followed by the chained controllers are 1) They must put unique objects into the Model If 2 controllers try to put something into the Model under the same key an exception is thrown(unless both are the same object) 2) They must all have the same default view default being the formView for forms 3) If one of the controllers requests a view that is not the default then that is the view that will get used however if more that one of the controllers returns a non default view its an exception not default being the successView for forms And here is a bit of config that uses it NOTE that givingappeal_search is the default view ltbean name=givingappeal_searchform class=ourcommunitywebutilspringChainedControllergt ltproperty name=controllerChaingt ltlistgt ltref bean=appealSearchController gt ltref bean=appealEmailController gt ltlistgt ltpropertygt ltproperty name=defaultViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealSearchController class=ourcommunitywebgivingAppealSearchControllergt ltproperty name=commandNamegtltvaluegtappealSearchFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebgivingAppealSearchFormltvaluegt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltbeangt ltbean id=appealEmailController class=ourcommunitywebutilemailEmailController gt ltproperty name=commandNamegtltvaluegtappealEmailFormltvaluegtltpropertygt ltproperty name=commandClassgt ltvaluegtourcommunitywebutilemailEmailFormltvaluegtltpropertygt ltproperty name=validatorgt ltbean class=ourcommunitywebutilemailEmailFormValidator gt ltpropertygt ltproperty name=successViewgtltvaluegtgivingappeal_email_sentltvaluegtltpropertygt ltproperty name=formViewgtltvaluegtgivingappeal_searchltvaluegtltpropertygt ltproperty name=toAddressgtltvaluegtdonations ltatgt ourcommunitycomaultvaluegtltpropertygt ltproperty name=subjectgtltvaluegtAppeal Suggestionltvaluegtltpropertygt ltbeangt

import javautilHashMapimport javautilIteratorimport javautilMap

import javaxservletServletExceptionimport javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

import orgspringframeworkwebservletModelAndViewimport orgspringframeworkwebservletmvcAbstractControllerimport orgspringframeworkwebservletmvcController

public class ChainedController extends AbstractController

private Controller[] controllerChainprivate String defaultView

protected ModelAndView handleRequestInternal(HttpServletRequest requestHttpServletResponse response) throws Exception

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 32: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 32 of 42

boolean hasAlternativeViewName = falseString viewName = getDefaultView()Map chainedModel = new HashMap()

for (int i = 0 i lt controllerChainlength i++)

ModelAndView modelAndView = controllerChain[i]handleRequest(request response)

if (modelAndViewgetViewName() == null)

throw new ServletException(Controller did not return a view name)

if (getDefaultView()equals(modelAndViewgetViewName()))

if (hasAlternativeViewName)

throw new ServletException(More than 1 controller specified an alternativeview)

hasAlternativeViewName = trueviewName = modelAndViewgetViewName()

for (Iterator it=modelAndViewgetModel()entrySet()iterator() ithasNext() )

MapEntry e = (MapEntry)itnext()Object oldVal = chainedModelput(egetKey() egetValue())if (oldVal = null ampamp (oldValequals(egetValue())))

throw new ServletException(Different objects placed into the model under thesame key[ + egetKey() + ])

return new ModelAndView(viewName chainedModel)

public void setControllerChain(Controller[] controllerChain)

thiscontrollerChain = controllerChain

public void setDefaultView(String defaultView)

thisdefaultView = defaultView

public String getDefaultView()

return defaultView

The major problem in here is the restriction on the controllers The root cause is this code ties model and view togetherThe solution is to introduce another layer of abstraction to separate models from views to isolate the actions to retrievemodel data I call this interface Action In this interface we should pass in command object (input) and the Map fromerrors (output) Then we can chain actions together Composite design pattern should be helpful

Here is the controller class

package orgspringwebtestactions

import orgspringframeworkwebservletmvcSimpleFormControllerimport orgspringframeworkwebservletModelAndViewimport orgspringframeworkvalidationBindException

import javaxservlethttpHttpServletRequestimport javaxservlethttpHttpServletResponse

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 33: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 33 of 42

import javautil This is to seperate the action and model

public class ChainedActionController extends SimpleFormController

private Action action

public ModelAndView onSubmit(HttpServletRequest request HttpServletResponse responseObject command BindException errors) throws Exception

Map model = errorsgetModel()actionexecute(command model)return new ModelAndView(thisgetSuccessView() model)

public Action getAction() return action public void setAction(Action act) action = act

Notice that the controller delegates actions The Action interface has just one method

package orgspringwebtestactions

import javautilMap

public interface Action

public void execute(Object cmd Map model)

The input is the command object from the controller and the output is the model Each action could add or modify themodel (yes there is a chance they could interfere with each other so document them) The implementation of theinterface has two classes because we are using composite pattern

package orgspringwebtestactions

import javautil we should add a hook to the parent so we could use parents command object

public class ActionSupport implements Action

protected String actionObject

public void setActionObject(String objectName) actionObject = objectName public String getActionObject() return actionObject

public void execute(Object cmd Map model)

and

package orgspringwebtestactions

import orgspringframeworkbeansBeanWrapperimport orgspringframeworkbeansBeanWrapperImplimport javautil

public class ActionComposite extends ActionSupport

This is the hook to the childrenprotected List actions = null

public void setActions(List list)

actions = listpublic List getActions() return actions

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 34: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 34 of 42

public void execute(Object cmd Map model)

if (actions = null)

for (Iterator it=actionsiterator()ithasNext())

ActionSupport action = ((ActionSupport)itnext())actionexecute(getSubFieldObject(cmd actiongetActionObject()) model)

private static Object getSubFieldObject(Object targetObj String pathString)

if (pathString == null) return targetObj

if (pathStringtrim()equalsIgnoreCase(command)) return targetObj

String myPath = pathStringif (pathStringstartsWith(command))

myPath = myPathsubstring(myPathindexOf()+1 myPathlength())BeanWrapper bw = new BeanWrapperImpl(targetObj)return bwgetPropertyValue(myPath)

The first class is the ldquoleafrdquo class and the second is the composite Normally a new action should be a subclass ofActionSupport Letrsquos take a look at how to create new actions and tie them together

First create two actions

package orgspringwebtestactions

import javautilMap

public class Action1Simple extends ActionSupport

public void execute(Object cmd Map model)

ChainedBean formBean = (ChainedBean)cmdmodelput(birth formBeangetBirth())modelput(age formBeangetYourBean()getAge())modelput(name formBeangetYourBean()getMyBean()getName())

and

package orgspringwebtestactions

import javautilMap

public class Action2Simple extends ActionSupport

public void execute(Object cmd Map model)

Chained1Bean formBean = (Chained1Bean)cmdformBeansetAge(not sure)modelput(age formBeangetAge())

The second action overwrites the first one on the field age the first one gets input from the form The config in theusers-servletxml is as follows

ltbean name=input112chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 35: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 35 of 42

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsActionCompositegtltproperty name=actionsgt

ltlistgtltbean class=orgspringwebtestactionsAction1Simplegtltbean class=orgspringwebtestactionsAction2Simplegt

ltproperty name=actionObjectgtltvaluegtcommandyourBeanltvaluegtltpropertygtltbeangt

ltlistgtltpropertygt

ltbeangtltpropertygt

ltbeangt

Itrsquos a little bit verbose If you want just one action check this one

ltbean name=input111chainedactionshtmclass=orgspringwebtestactionsMyTest1ChainedActionControllergt

ltproperty name=commandClassgtltvaluegtorgspringwebtestactionsChainedBeanltvaluegtltpropertygtltproperty name=formViewgtltvaluegtinput11ltvaluegtltpropertygtltproperty name=successViewgtltvaluegtresult11ltvaluegtltpropertygtltproperty name=actiongt

ltbean class=orgspringwebtestactionsAction1Simplegtltpropertygt

ltbeangt

Note the default object passed into actions is the command object If a field of the command object is desired we couldspecify as commandyourField just in the same way we do in the ltspringbindgt The top object is always ldquocommandrdquo

The JSP pages are trivial here is input11jsp

lt taglib prefix=c uri=httpjavasuncomjstlcore gtlt taglib prefix=fmt uri=httpjavasuncomjstlfmt gtlt taglib prefix=spring uri=spring gt

ltHTMLgtltheadgtlttitlegtInput 11 - Chained actionslttitlegtltheadgtltbodygtHelloltbrgtltFORM name=userForm action=springinput111chainedactionshtm method=POSTgt

Birthltspringbind path=commandbirthgt

ltINPUT type=text name=birth size=32 value=gtltspringbindgt

Ageltspringbind path=commandyourBeanagegt

ltINPUT type=text name=yourBeanage size=32 value=gtltspringbindgt

ltINPUT type = submit value= Try gtltFORMgt

ltbodygtltHTMLgt

and the result11jsp is

lt taglib prefix=c uri=httpjavasuncomjstlcore gt

ltHTMLgtltHEADgtltTITLEgtInput 3 resultltTITLEgtltHEADgtltBODYgt

ltH1gtThe input isltH1gtltPgt[ltcout value=$namegt]ltpgtltPgt[ltcout value=$agegt]ltpgtltPgt[ltcout value=$birthgt]ltpgt

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 36: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 36 of 42

ltBODYgtltHTMLgt

Here we donrsquot have any restrictions that the previous post has Of course there is a chance that they would overrideeach other but this should be responsibility of the person who does the configuration and integration not each actiondeveloper

Another thread on this is at here httpwwwcompetitiescomspringworkflow Not sure whether itrsquos the same as above

7 DispatcherServlet and ControllersHaving said so much now itrsquos time to take a look at the central piece of the web framework DispatcherServlet In orderto make good use of the framework it would be better to understand how it works in general

The structure of the DispatcherServlet is as follows

HttpServlet

HttpServletBean

FrameworkServlet

DispatcherServlet

ServletConfigPropertyValues

MutablePropertyValues PropertyValues

WebApplicationContext

ViewResolver

View

Controller

ApplicationContext

HandlerMapping

HandlerAdapter

SimpleControllerHandlerAdapter ThrowawayControllerHandlerAdapter CommonsPathMapHandlerMapping

BeanNameUrlHandlerMapping SimpleUrlHandlerMapping

AbstractHandlerMapping

AbstractPathMapHandlerMapping

1 Control Map requests to handlers

2 ModelCall handler to handle

3 View render the view

The functionalities areHttpServlet This is the top class in the hirachy belongs to javaxservletHttpServletBean to add bean related functionalitiesFrameworkServlet to add context related functionalitiesDispatcherServlet main servlet

The init sequence is as follows

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 37: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 37 of 42

F r a m e w o r k S e r v le t H t tp S e r v le tB e a n

in i t ( )

D is p a tc h e rS e rv le t

in itS e r v le tB e a n ()

in i tW e b A p p l ic a t io n C o n te x t ( )

c re a te W e b A p p lic a t io n C o n te x t ()

in i tF r a m e w o r k S e rv le t( )

in itM u lt ip a r tR e s o lv e r ()

in itL o c a le R e s o lv e r ( )

in itT h e m e R e s o lv e r( )

in itH a n d le rM a p p in g s ( )

in itH a n d le rA d a p te r s ( )

in itH a n d le rE x c e p t io n R e s o lv e rs ()

in itV ie w R e s o lv e r( )

The pattern of these init methods prompt services ndash if we could config them as services rather than hardcoded there itwould be more flexible (my guts guess)

The calling sequence is as follows but I do ignore the interceptors to highlight the structure

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 38: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 38 of 42

FrameworkServlet HandlerExecutionChainDispatcherServlet

doService()

serviceWrapper()

getHandler()

getHandlerAdapter()

render()

handle()

getHandle()

HandlerMapping

getHandle()

HandlerAdapter Controller ViewResolver ViewModelAndView

resolveViewName()

handleRequest()

getViewgetViewName()

getView()

getView()

doGet()

doPost()

Here are the view related classes Since we are not going to dive into views they are here only for references

ViewAbstractView

AbstractExcelViewAbstractPdfViewAbstractUrlBasedViewAbstractXsltView

FreeMarkerView InternalResourceView RedirectView VelocityView

JstlView TilesView

TilesJstlView

The view configurations can not be inherited as of 102 because composition is the only mechnism here Check laterversion if you need this(in tiles)

The ViewResolver tree is

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 39: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 39 of 42

ViewResolver

AbstractCachingViewResolverBeanNameViewResolver

ResourceBundleViewResolver UrlBasedViewResolver XmlViewResolver

InternalResourceViewResolver VelocityViewResolver

The view resolver calls corresponding view classes (or subclasses)

8 Things that I decide to leave out but quite usefulUtilize other resources I have no intent to cover everything So read java docs books samples and source code

81 ControllersHere are more controllers

MultiAction controller I am not a big fan to mix different actionsWizardForm controller simple wizard form Another one is workflowhttpwwwcompetitiescomspringworkflowintroductionhtml andhttpwwwopensymphonycomosworkflow

Controllers can be tested outside web containers

82 InterceptorsInterceptors are for actions not views

83 ValidatorsStraight forward no trick here until we get to multi forms

Should validate in the business layer

84 LocalesContentType It seems the contentType in jsp canrsquot be set from outside If this is the case could we trigger from therequest side with the right locale(after we get input before we send out the output) I think this should be the rightapproach

I just saw another solution on the application server level (more precisely on Tomcat) to force the server to send outbig5 To me this is shaky We shouldnrsquot do it in this way at all from my experience

85 ThemesDynamically assign themes Is this necessary Since we could just change the reference link to a new CSS file

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 40: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 40 of 42

86 Multipartfile uploadingText and binaries

87 Caching for static web resourcesIf we can turn it onoff itrsquos easier for us to test different parts of the application dynamic or static

88 Application ContextThe application context should be just links to the contexts of all layers Each layer should have its own context andthus as much independent as possible

89 Othersviewspropertiesmessagesproperties

9 Why using Spring framework web MVC componentExpert one on one J2EE programming chapter 12

Problem in web applicationsThe mismatch of html tags and java objects makes the dynamic data and structure in web pages difficult A tag languageand OO language HTML is string oriented and thus we have to convert strings to whatever types we are using in java

SolutionsWhile every solution has trade-offs Spring web MVC is the closest to the right solution to solve problems in webapplications and have minimal impactside effects

Irsquove been using a similar web framework in production for 4 years in my experience this is just a bless Spring has asmall set of tags and thus the damage to the HTML pages is very small(Keep in mind the page decoration is aprofessional job that means a seasoned java developer might be a green artist) Once we are on the server side we haveeverything in objects If we need some small massage on the data PropertyEditors are very handy

The configuration file(users-servletxml) is manageable because you can separate them into different xml files

As you can see the view is completely separated from the controller

Regarding forms and form beans letrsquos consider the general case

Pages --------- forms ------------ form beans

A page could have several forms any form could be in any page a form could have several form beans any form beancould be for any form So we have many-to-many relations

Right-to-left relationsAny form could be in any page(s) there is no restrictionAny form bean could be for any form(s) there is no restriction (or we need not to implement any interface)

Left-to-right relationsAny page could have any form(s) The one-form-per-page is built in We considered the multi-form caseearlierAny form could have any form bean(s) The one-bean-per-form is built in However we canrsquot have severalform beans corresponding to one form because there is only one command object Although we couldpopulate several beans to the formpage the data on the way back has to be in one class But compositionworks in this case

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer

Page 41: Spring Web Application Framework for the Presentation Layerread.pudn.com/downloads48/ebook/163249/SpringWebFramework.pdf · 9 WHY USING SPRING FRAMEWORK WEB MVC COMPONENT ..... 40

floatercjsdncom Spring Web Framework

Revised 7262004 Page 41 of 42

10 Other View ComponentsExpert one on one J2EE programming chapter 13Spring reference chapter 12

Velocity Tapestry XSLT portal JSF tiles Webwork Struts Each deserves its own documentJSPJSTL closer to java flat learning curveVelocity script-like flat learning curveTapestry heavy weight more object orientedXSLT full blown steep learning curve

11 Comparing with other frameworksExpert one on one J2EE programming chapter 12Spring reference chapter 11

12 ReferencesSpring sitehttpwwwspringframeworkorg

Mailing listhttpnewsgmaneorggmanecompjavaspringframeworkuserhttpsourceforgenetmailgroup_id=73357

Forumshelp httpsourceforgenetforumforumphpforum_id=250340Open discussion httpsourceforgenetforumforumphpforum_id=250339httpopensourceatlassiancomconfluencespringdisplayDISCHome

Create PDF with GO2PDF for free if you wish to remove this line click here to buy Virtual PDF Printer