org.springframework.web.servlet.mvc
Class AbstractFormController

java.lang.Object
  extended byorg.springframework.context.support.ApplicationObjectSupport
      extended byorg.springframework.web.context.support.WebApplicationObjectSupport
          extended byorg.springframework.web.servlet.support.WebContentGenerator
              extended byorg.springframework.web.servlet.mvc.AbstractController
                  extended byorg.springframework.web.servlet.mvc.BaseCommandController
                      extended byorg.springframework.web.servlet.mvc.AbstractFormController
All Implemented Interfaces:
ApplicationContextAware, Controller
Direct Known Subclasses:
AbstractWizardFormController, SimpleFormController

public abstract class AbstractFormController
extends BaseCommandController

Form controller that autopopulates a form bean from the request. This, either using a new bean instance per request, or using the same bean when the sessionForm property has been set to true. This class is the base class for both framework subclasses like SimpleFormController and AbstractWizardFormController, and custom form controllers you can provide yourself.

Both form- input-views and after-submission-views have to be provided programmatically. To provide those views using configuration properties, use the SimpleFormController.

Subclasses need to override showForm to prepare the form view, and processFormSubmission to handle submit requests. For the latter, binding errors like type mismatches will be reported via the given "errors" holder. For additional custom form validation, a validator (property inherited from BaseCommandController) can be used, reporting via the same "errors" instance.

Comparing this Controller to the Struts notion of the Action shows us that with Spring, you can use any ordinary JavaBeans or database backed JavaBean without having to implement a framework specific class (in case of Struts, this is ActionForm). More complex properties of JavaBeans (Dates, Locales, but also your own application specific or compound types) can be represented and submitted to the controller, by using the notion of java.beans.PropertyEditors. For more information on that subject, see the workflow of this controller and the explanation of the BaseCommandController.

Workflow (and that defined by superclass):

  1. GET request on the controller is received
  2. call to formBackingObject() which by default, returns an instance of the commandClass that has been configured (see the properties the superclass exposes), but can also be overriden to - for instance - retrieve an object from the database (that - for instance - needs to be modified using the form)
  3. call to initBinder() which allows you to register custom editors for certain fields (often properties of non-primitive or non-Sring types) or the command class. This render appropriate Strings for for instance locales
  4. binding of the ServletRequestDataBinder in the request to be able to use the property editors in the form rendering (only if bindOnNewForm is set to true)
  5. call to showForm() to return a View that should be rendered (typically the view that renders the form). This method has be overridden in extending classes
  6. call to referenceData() to allow you to bind any relevant reference data you might need when editing a form (for instance a List of Locale objects you're going to let the user select one from)
  7. model gets exposed and view gets rendered. Continue after user has filled in form
  8. POST request on the controller is received
  9. if sessionForm is not set, getCommand() is called to retrieve a command class. Otherwise, the controller tries to find the command object which is already bound in the session. If it cannot find the object, it'll do a call to handleInvalidSubmit which - by default - tries to create a new command class and resubmit the form
  10. controller tries to put all parameters from the request into the JavaBeans (command object) and if validateOnBinding is set, validation will occur
  11. call to onBindAndValidate() which allows you to do custom processing after binding and validation (for instance to perform database persistency)
  12. call to processFormSubmission which, in implementing classes returns a sort of successview, for instance congratulating the user with a successfull form submission

Note that by default POST requests are treated as form submissions. This can be customized by overriding isFormSubmission. Custom binding can be achieved either by registering custom property editors before binding in an initBinder implementation, or by custom bean population from request parameters after binding in an onBindAndValidate implementation.

In session form mode, a submission without an existing form object in the session is considered invalid, like in case of a resubmit/reload by the browser. The handleInvalidSubmit method is invoked then, trying a resubmit by default. It can be overridden in subclasses to show respective messages or redirect to a new form, in order to avoid duplicate submissions. The form object in the session can be considered a transaction token in this case.

Note that views should never retrieve form beans from the session but always from the request, as prepared by the form controller. Remember that some view technologies like Velocity cannot even access a HTTP session.

Exposed configuration properties (and those defined by superclass):

name default description
bindOnNewForm false Indicates whether to bind servletrequestparameters as well when creating a new form. If set to true this will happen, if set to false, the parameters will only be bound on formsubmissions
sessionForm false Indicates whether or not the command object should be bound onto the session when a user asks for a new form. This allows you to for instance retrieve an object from the database, let the user edit it, and then persist it again. If this is set to false, a new command object will be created on all requests (both requests for the form and submissions of the form)

Author:
Rod Johnson, Juergen Hoeller, Alef Arendsen
See Also:
SimpleFormController, AbstractWizardFormController

Field Summary
 
Fields inherited from class org.springframework.web.servlet.mvc.BaseCommandController
DEFAULT_COMMAND_NAME
 
Fields inherited from class org.springframework.web.servlet.support.WebContentGenerator
HEADER_CACHE_CONTROL, HEADER_EXPIRES, HEADER_PRAGMA, METHOD_GET, METHOD_POST
 
Fields inherited from class org.springframework.context.support.ApplicationObjectSupport
logger
 
Constructor Summary
AbstractFormController()
          Create a new AbstractFormController.
 
Method Summary
protected  java.lang.Object formBackingObject(javax.servlet.http.HttpServletRequest request)
          Retrieve a backing object for the current form from the given request.
protected  java.lang.Object getCommand(javax.servlet.http.HttpServletRequest request)
          Return the form object for the given request.
protected  java.lang.String getFormSessionAttributeName()
          Return the name of the session attribute that holds the form object for this controller.
protected  ModelAndView handleInvalidSubmit(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Handle an invalid submit request, e.g.
protected  ModelAndView handleRequestInternal(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Handles two cases: form submissions and showing a new form.
protected  boolean isBindOnNewForm()
          Return if request parameters should be bound in case of a new form.
protected  boolean isFormSubmission(javax.servlet.http.HttpServletRequest request)
          Determine if the given request represents a form submission.
protected  boolean isSessionForm()
          Return if session form mode is activated.
protected abstract  ModelAndView processFormSubmission(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.Object command, BindException errors)
          Process form submission request.
protected  java.util.Map referenceData(javax.servlet.http.HttpServletRequest request, java.lang.Object command, Errors errors)
          Create a reference data map for the given request, consisting of bean name/bean instance pairs as expected by ModelAndView.
 void setBindOnNewForm(boolean bindOnNewForm)
          Set if request parameters should be bound to the form object in case of a non-submitting request, i.e.
 void setSessionForm(boolean sessionForm)
          Activate resp.
protected  ModelAndView showForm(javax.servlet.http.HttpServletRequest request, BindException errors, java.lang.String viewName)
          Prepare model and view for the given form, including reference and errors.
protected  ModelAndView showForm(javax.servlet.http.HttpServletRequest request, BindException errors, java.lang.String viewName, java.util.Map controlModel)
          Prepare model and view for the given form, including reference and errors, adding a controller-specific control model.
protected abstract  ModelAndView showForm(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, BindException errors)
          Prepare the form model and view, including reference and error data.
protected  ModelAndView showNewForm(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Show a new form.
 
Methods inherited from class org.springframework.web.servlet.mvc.BaseCommandController
bindAndValidate, checkCommand, createBinder, createCommand, getCommandClass, getCommandName, getValidator, initBinder, isValidateOnBinding, onBind, onBindAndValidate, setCommandClass, setCommandName, setValidateOnBinding, setValidator
 
Methods inherited from class org.springframework.web.servlet.mvc.AbstractController
handleRequest, setSynchronizeOnSession
 
Methods inherited from class org.springframework.web.servlet.support.WebContentGenerator
applyCacheSeconds, applyCacheSeconds, cacheForSeconds, cacheForSeconds, checkAndPrepare, preventCaching, setCacheSeconds, setRequireSession, setSupportedMethods, setUseCacheControlHeader, setUseExpiresHeader
 
Methods inherited from class org.springframework.web.context.support.WebApplicationObjectSupport
getServletContext, getTempDir, getWebApplicationContext, requiredContextClass
 
Methods inherited from class org.springframework.context.support.ApplicationObjectSupport
getApplicationContext, getMessageSourceAccessor, initApplicationContext, setApplicationContext
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

AbstractFormController

public AbstractFormController()
Create a new AbstractFormController.

Subclasses should set the following properties, either in the constructor or via a BeanFactory: commandName, commandClass, bindOnNewForm, sessionForm. Note that commandClass doesn't need to be set when overriding formBackingObject, as the latter determines the class anyway.

See Also:
BaseCommandController.setCommandName(java.lang.String), BaseCommandController.setCommandClass(java.lang.Class), setBindOnNewForm(boolean), setSessionForm(boolean), formBackingObject(javax.servlet.http.HttpServletRequest)
Method Detail

setBindOnNewForm

public final void setBindOnNewForm(boolean bindOnNewForm)
Set if request parameters should be bound to the form object in case of a non-submitting request, i.e. a new form.


isBindOnNewForm

protected final boolean isBindOnNewForm()
Return if request parameters should be bound in case of a new form.


setSessionForm

public final void setSessionForm(boolean sessionForm)
Activate resp. deactivate session form mode. In session form mode, the form is stored in the session to keep the form object instance between requests, instead of creating a new one on each request.

This is necessary for either wizard-style controllers that populate a single form object from multiple pages, or forms that populate a persistent object that needs to be identical to allow for tracking changes.


isSessionForm

protected final boolean isSessionForm()
Return if session form mode is activated.


getFormSessionAttributeName

protected final java.lang.String getFormSessionAttributeName()
Return the name of the session attribute that holds the form object for this controller.

Returns:
the name of the form session attribute, or null if not in session form mode.

handleRequestInternal

protected final ModelAndView handleRequestInternal(javax.servlet.http.HttpServletRequest request,
                                                   javax.servlet.http.HttpServletResponse response)
                                            throws java.lang.Exception
Handles two cases: form submissions and showing a new form. Delegates the decision between the two to isFormSubmission, always treating requests without existing form session attribute as new form when using session form mode.

Specified by:
handleRequestInternal in class AbstractController
Throws:
java.lang.Exception
See Also:
AbstractController.handleRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)

isFormSubmission

protected boolean isFormSubmission(javax.servlet.http.HttpServletRequest request)
Determine if the given request represents a form submission.

Default implementation treats a POST request as form submission. Note: If the form session attribute doesn't exist when using session form mode, the request is always treated as new form by handleRequestInternal.

Subclasses can override this to use a custom strategy, e.g. a specific request parameter (assumably a hidden field or submit button name).

Parameters:
request - current HTTP request
Returns:
if the request represents a form submission

showNewForm

protected final ModelAndView showNewForm(javax.servlet.http.HttpServletRequest request,
                                         javax.servlet.http.HttpServletResponse response)
                                  throws java.lang.Exception
Show a new form. Prepares a backing object for the current form and the given request, including checking its validity.

Parameters:
request - current HTTP request
response - current HTTP response
Returns:
the prepared form view
Throws:
java.lang.Exception - in case of an invalid new form object

formBackingObject

protected java.lang.Object formBackingObject(javax.servlet.http.HttpServletRequest request)
                                      throws java.lang.Exception
Retrieve a backing object for the current form from the given request.

The properties of the form object will correspond to the form field values in your form view. This object will be exposed in the model under the specified command name, to be accessed under that name in the view: for example, with a "spring:bind" tag. The default command name is "command".

Note that you need to activate session form mode to reuse the form-backing object across the entire form workflow. Else, a new instance of the command class will be created for each submission attempt, just using this backing object as template for the initial form.

Default implementation calls BaseCommandController.createCommand, creating a new empty instance of the command class. Subclasses can override this to provide a preinitialized backing object.

Parameters:
request - current HTTP request
Returns:
the backing objact
Throws:
java.lang.Exception - in case of invalid state or arguments
See Also:
BaseCommandController.setCommandName(java.lang.String), BaseCommandController.setCommandClass(java.lang.Class), BaseCommandController.createCommand()

showForm

protected abstract ModelAndView showForm(javax.servlet.http.HttpServletRequest request,
                                         javax.servlet.http.HttpServletResponse response,
                                         BindException errors)
                                  throws java.lang.Exception
Prepare the form model and view, including reference and error data. Can show a configured form page, or generate a programmatic form view.

A typical implementation will call showForm(request,errors,"myView") to prepare the form view for a specific view name.

Note: If you decide to have a "formView" property specifying the view name, consider using SimpleFormController.

Parameters:
request - current HTTP request
response - current HTTP response
errors - validation errors holder
Returns:
the prepared form view, or null if handled directly
Throws:
java.lang.Exception - in case of invalid state or arguments
See Also:
showForm(HttpServletRequest, BindException, String), SimpleFormController.setFormView(java.lang.String)

showForm

protected final ModelAndView showForm(javax.servlet.http.HttpServletRequest request,
                                      BindException errors,
                                      java.lang.String viewName)
                               throws java.lang.Exception
Prepare model and view for the given form, including reference and errors. In session form mode: Re-puts the form object in the session when returning to the form, as it has been removed by getCommand. Can be used in subclasses to redirect back to a specific form page.

Parameters:
request - current HTTP request
errors - validation errors holder
viewName - name of the form view
Returns:
the prepared form view
Throws:
java.lang.Exception - in case of invalid state or arguments

showForm

protected final ModelAndView showForm(javax.servlet.http.HttpServletRequest request,
                                      BindException errors,
                                      java.lang.String viewName,
                                      java.util.Map controlModel)
                               throws java.lang.Exception
Prepare model and view for the given form, including reference and errors, adding a controller-specific control model. In session form mode: Re-puts the form object in the session when returning to the form, as it has been removed by getCommand. Can be used in subclasses to redirect back to a specific form page.

Parameters:
request - current HTTP request
errors - validation errors holder
viewName - name of the form view
controlModel - model map containing controller-specific control data (e.g. current page in wizard-style controllers).
Returns:
the prepared form view
Throws:
java.lang.Exception - in case of invalid state or arguments

referenceData

protected java.util.Map referenceData(javax.servlet.http.HttpServletRequest request,
                                      java.lang.Object command,
                                      Errors errors)
                               throws java.lang.Exception
Create a reference data map for the given request, consisting of bean name/bean instance pairs as expected by ModelAndView.

Default implementation returns null. Subclasses can override this to set reference data used in the view.

Parameters:
request - current HTTP request
command - form object with request parameters bound onto it
errors - validation errors holder
Returns:
a Map with reference data entries, or null if none
Throws:
java.lang.Exception - in case of invalid state or arguments
See Also:
ModelAndView

handleInvalidSubmit

protected ModelAndView handleInvalidSubmit(javax.servlet.http.HttpServletRequest request,
                                           javax.servlet.http.HttpServletResponse response)
                                    throws java.lang.Exception
Handle an invalid submit request, e.g. when in session form mode but no form object was found in the session (like in case of an invalid resubmit by the browser).

Default implementation simply tries to resubmit the form with a new form object. This should also work if the user hit the back button, changed some form data, and resubmitted the form.

Note: To avoid duplicate submissions, you need to override this method. Either show some "invalid submit" message, or call showNewForm for resetting the form (prepopulating it with the current values if "bindOnNewForm" is true). In this case, the form object in the session serves as transaction token.

Parameters:
request - current HTTP request
response - current HTTP response
Returns:
a prepared view, or null if handled directly
Throws:
java.lang.Exception - in case of errors
See Also:
showNewForm(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse), setBindOnNewForm(boolean)

getCommand

protected final java.lang.Object getCommand(javax.servlet.http.HttpServletRequest request)
                                     throws java.lang.Exception
Return the form object for the given request. In session form mode: Retrieve the form object from the session. The form object gets removed from the session, but it will be re-added when showing the form for resubmission.

Overrides:
getCommand in class BaseCommandController
Parameters:
request - current HTTP request
Returns:
object form to bind onto
Throws:
java.lang.Exception - in case of invalid state or arguments
See Also:
BaseCommandController.createCommand()

processFormSubmission

protected abstract ModelAndView processFormSubmission(javax.servlet.http.HttpServletRequest request,
                                                      javax.servlet.http.HttpServletResponse response,
                                                      java.lang.Object command,
                                                      BindException errors)
                                               throws java.lang.Exception
Process form submission request. Called by handleRequestInternal in case of a form submission.

Subclasses can override this to provide custom submission handling like triggering a custom action. They can also provide custom validation and call showForm or proceed with the submission accordingly.

Can call errors.getModel() to populate the ModelAndView model with the command and the Errors instance, under the specified bean name.

Parameters:
request - current servlet request
response - current servlet response
command - form object with request parameters bound onto it
errors - holder without errors (subclass can add errors if it wants to)
Returns:
the prepared model and view, or null
Throws:
java.lang.Exception - in case of errors
See Also:
isFormSubmission(javax.servlet.http.HttpServletRequest), showForm(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.validation.BindException), Errors


Copyright (C) 2003-2004 The Spring Framework Project.