Wizard Functionality

The SimpleFormController supports single-page forms. When going through an order or signup process, you probably need multiple pages including forms that together fill a certain domain object: one page that fills the personal details, one that contains address data, and one that contains payment information. Spring offers a controller specifically designed to support wizard-style forms. The org.springframework.web.servlet.mvc.AbstractWizardFormController supports multiple pages including finish and cancel actions and events that change the page in the wizard. As with any other controller, you can adjust it to your needs using Spring's Dependency Injection features. Also, as the name implies, it's abstract, so you will have to extend it to add behavior to it such as the saving of objects.

The AbstractWizardFormController's workflow resembles the workflow of the AbstractFormController a lot, but where the latter works for "one pagers," a wizard of course has multiple pages. To support this, the callback and template methods offered by the AbstractFormContoller are all mirrored to include a page number. It contains, for example, a referenceData() method that does not include the request and the command object, but also an integer representing the page number to allow you to return reference data specific to the page that is currently being displayed to the user.

Basic Configuration

Let's first review the properties the wizard controller supports:

  • pages: A String array, representing the logical view names of the wizard's pages. To have everything work correctly with arrays, page numbers in a wizard are zero-based. The view names in this array are used in the ModelAndView objects returned from the processXXX methods we'll be reviewing later.

  • allowDirtyBack and allowDirtyFoward: Because navigation through the wizard and moving from one page to another is regarded as a form submission, data binding and validation will always take place. The default behavior of the wizard controller is to prevent the user from going to the next or the previous page if validation errors occur. In such a case, the controller will redisplay the current page, allowing you to display the error messages. allowDirtyBack and allowDirtyForward allow you to modify this behavior in which the controller will ignore validation errors when moving to the previous and to the next page respectively. As said, the default value is false.

  • pageAttribute: If you set this parameter, the controller will put the current page number (as an integer) in the model, using the String you specify. You need this in case you have one view that renders multiple view pages (we'll review the different options to render pages in a minute).

The wizard controller derives from AbstractFormController, so parameters such as sessionForm, commandClass, commandName, and bindOnNewForm are all at your disposal.

Template Methods

As already mentioned, the wizard mirrors the different callback and template methods from the AbstractFormController. In addition to passing the request and the command object around, the page number is often also given to you when overriding such methods. Let's briefly review those before diving into the flow of the wizard controller:

  • referenceData(HttpServletRequest request, Object command, Errors errors, int pageNumber): Method you can override to add page-specific reference data to the model.

  • onBindAndValidate(HttpServletRequest request, Object command, BindException ex, int pageNumber): Page-specific data binding and validation can be done if you override this method.

  • processCancel(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors): Called in case the user indicates he wants to cancel the wizard using a cancel button, for example. You can trigger the cancellation process by including a request parameter keyed _cancel. This method should return a ModelAndView object that will be used to render the cancellation page.

  • processFinish(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors): Called in case the user indicates he wants to finish the wizard. You can trigger the process of finishing the wizard by including a request parameter while submitting keyed _finish. This method is called only if all pages will have been successfully validated (which is done by calling the validatePage() method for all pages).

  • validatePage(Object command, Errors errors, int page) and validatePage(Object command, Errors errors, int page, boolean finish): Template methods to override if you want to do validation. You have to decide yourself here how you are going to do validation. One option is to append the page number to the validate() method of the Validator, and call it using reflection.

Flow of a Wizard

The typical flow of a wizard and the interaction with the AbstractWizardFormController is displayed in Figure 12-8. As you can see, the finishing and cancellation of the wizard will result in calls to processFinish() and processCancel(), respectively.

image from book
Figure 12-8

Page Changes, Numbering, and Other Actions

A wizard consists of multiple pages and hence needs to maintain state between individual HTTP requests. Most importantly, we need to keep track of what page is currently showing. In addition to that, we also need to trigger actions that change the page. This section briefly discusses how to change pages and trigger the finish and cancel actions.

The AbstractWizardFormController keeps track of page numbers using either the user's session or a request parameter. It's best to choose which to use based upon the actual project you're using the controller in. Often we'll turn on the session support when using this controller because keeping the actual state of the domain object across multiple requests and with partial elements filled in throughout the wizard can prove to be a hassle.

Back to what we were discussing: the page numbers. To be able to call the correct methods including the correct page numbers (for example the referenceData() method, but also the validatePage() method) with session support disabled, we need to include a request parameter in our HTML page, containing the current page. The AbstractWizardFormController will automatically pick this up when you submit the form. In fact, it's a good thing to do this anyway because we need to ensure the controller picks up on the right page also when the user clicks the Back button. Including a request parameter alongside a session attribute guarantees we'll always get the right page communicated to the controller. The parameter has to be keyed _page and include the current page number, nothing more.


Note that you can expose the current page as an attribute in the model. Configure the pageAttribute parameter of the controller in your context (for example, with currentPage) and after that simply output it, like this:

<input type="hidden" name="_page" value="${currentPage}">

Triggering the finish and cancel actions is a matter of including a _finish or _cancel parameter in your request, such as this:

<input type="hidden" name="_cancel" value="value">

The AbstractWizardFormController will pick up on these and trigger the right processes. As you might know, image buttons don't communicate the name of the input element itself, but the coordinates at which it has been clicked, prepended with the name of the input element. <input type="image" src="/books/1/382/1/html/2/submit.gif" name="_cancel"> will result in a _cancel.x and _cancel.y parameter being communicate through the request. The AbstractWizardFormController fortunately supports this.

Professional Java Development with the Spring Framework
Professional Java Development with the Spring Framework
ISBN: 0764574833
EAN: 2147483647
Year: 2003
Pages: 188

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net