Either way is acceptable, but as we have mentioned before, if the list of pages for the wiz-
ard is fairly static, we prefer using the constructor method.
URI Mapping
Be aware that there is a single URI for the entire work flow, including all steps and the finish
page. This effectively means that a user is prohibited from entering into the middle of a wiz-
ard. Luckily, this protects the wizard from ever being in an incorrect state. Any user who
attempts to access the wizard via a bookmark will simply be presented with the first page of
the wizard.
Validation
Just like SimpleFormController, the wizard controller supports one or more Validators. How-
ever, unlike SimpleFormController, the Validators are not automatically invoked during each
request. Because each request only fills out some information of the command bean, the stan-
dard Validatorhas no way of knowing which properties of the command bean are missing or
simply haven’t been filled out yet. Therefore, doing a full validation of the command only
makes sense at the end of the wizard.
To validate the command object during the wizard, you must call the appropriate method
on your Validatorthat matches the current page of the wizard. The controller provides a
validatePage(Object command, Errors errors, int pageNumber)method for you to imple-
ment, where you will call the appropriate validateXxx()method on your Validatorgiven the
pageNumber. In other words, you must control how validation is to be performed, because the
validate()method will not be called automatically.
Note that at the end of the work flow, and on the _finishevent, the controller will again
loop through the number of pages and validate each again. This effectively validates the entire
command object before the processFinish()method is called.
Page Change Callback
Although life cycle handlers exist for wizard completion and wizard cancellation, you may also
optionally implement postProcessPage() to perform some action after a normal page change
request.
This method is very useful when the state of the wizard must be persistent, allowing the
user to come back and finish the work flow at a later time. If you wish to support something
similar to this, persist the command bean inside postProcessPage()to somewhere more per-
manent than the HTTP session. You will most likely also need to override formBackingObject()
to pull the command bean back out of persistence when the user begins the wizard again.
Don’t forget to also override getInitialPage(), which you can first check to see whether the
user had already started the work flow earlier and return the page he left off on.
CHAPTER 6 ■THE CONTROLLER MENAGERIE 179