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