»
S
I
D
E
B
A
R
«
Spring AbstractWizardFormController, how to manipulate pages at runtime
Jul 19th, 2009 by franciov

spring-framework-2.5
The Abstract Wizard Form Controller is a form controller for typical wizard-style workflows, provided by Spring, a Java Web Application Framework.

In contrast to classic forms, wizards have more than one form view page. Therefore, there are various actions instead of one single submit action:

  • finish: trying to leave the wizard successfully, i.e. performing its final action, and thus needing a valid state;
  • cancel: leaving the wizard without performing its final action, and thus without regard to the validity of its current state;
  • page change: showing another wizard page, e.g. the next or previous one, with regard to “dirty back” and “dirty forward”.

In this article I want to focus on pages, how to set them up, expecially in the uncommon situation in which you don’t know exactly the number of pages you want to put in your wizard before running the application.

Every Spring manual would suggest you to put WizardFormController’s pages in the Spring XML configuration file, and actually this is the best way to set up your pages. Let’s consider the following configuration:

<bean name="myWizardForm"
          class="forms.MyWizardForm">

    </bean>

    <bean name="/myWizard.html"
          class="control.MyWizardFormController"
          p:sessionForm="true"
          p:commandClass="forms.MyWizardForm"
          p:commandName="myWizardForm">

        <property name="pages">
            <list>
                <value>page0</value>
                <value>page1</value>
                <value>page2</value>
            </list>
        </property>
    </bean>

We have put a property named pages inside myWizard.html bean, in which we listed the page values. Each value is used as the name of the view inside your jsp folder.

And now the wizard form, you can set it up for your needs.

public class MyWizardForm {

    // put your fields here

    public MyWizardForm() {
        // initialization
    }

    // put your setters and getters here
}

Finally the wizard controller.

public class MyWizardFormController extends AbstractWizardFormController {

    public MyWizardFormController() {
    }

    protected Map referenceData(HttpServletRequest request, Object command, Errors errors, int page) throws Exception {

        Map map = new HashMap();
        // put information you need into the map

        return map;
    }

    protected ModelAndView processFinish(HttpServletRequest request, HttpServletResponse response, Object object, BindException exception) throws Exception {
        return new ModelAndView("finish");
    }

What if, for some reasons, you need to create or edit your wizard page list at runtime? Let’s face the problem.

First of all, you can override the XML configuration through the setPages method. The following example replaces the page list specified in the XML file with an identical one but that has been built at run-time in MyWizardFormController constructor.

public MyWizardFormController() {
        String pages[] = new String[3];
        pages[0] = "page0";
        pages[1] = "page1";
        pages[2] = "page2";
        this.setPages(pages);
    }
}

This doesn’t help much: we moved the configuration outside XML (that’s a bad thing) but we still have a fixed number of pages with fixed values.

Let’s consider an application in which the page values are the request parameter keys for the first step (i.e. _target0). We might call setPages inside an overridden method used before the wizard controller accesses to page list, such as the getInitialPage method.

public class MyWizardFormController extends AbstractWizardFormController {

    public MyWizardFormController() {
    }

    protected int getInitialPage(HttpServletRequest request, Object command) {

        // override pages only when the target page is 0
        if (this.getTargetPage(request, 0) == 0) {

            // retrieve keys from request parameters
            Set parameters = new HashSet(request.getParameterMap().keySet());
            Iterator parametersIterator = parameters.iterator();
            String pages[] = new String[parameters.size()1];
            int i = 0;

            // fill wizard pages
            while (parametersIterator.hasNext()) {
                String page = (String) parametersIterator.next();
                // let’s ignore the ‘_target0′ parameter key
                if (page.startsWith("_") == false){
                    pages[i] = page;
                    i++;
                }
            }

            this.setPages(pages);  
        }

        return super.getInitialPage(request, command);
    }

In this way, as soon as myWizard.html bean is invoked by clicking on a link (i.e. GET http request) or submitting a form (i.e. POST http request), the page list is dinamically built starting from request parameter keys. This would be more useful if you decide to use request parameters values, or attributes.

For my purposes I used request parameter keys retrieved from a form submission in order to run an unordered set of pages and reporting each result (i.e. validation) in the final step.

»  Substance: WordPress   »  Style: Ahren Ahimsa
© www.francesco.iovine.name