|
Recipe 7.6. Creating a Wizard-Style Page FlowProblemYou want users to have a wizard-style page flow experience. SolutionImplement a subclass of LookupDispatchAction that supports operations for the navigational functionsprevious, next, and finishand template methods for the business logic. For each discrete step of the workflow, extend this subclass, placing the business logic for each step in the provided template methods. (See Example 7-4.) Example 7-4. LookupDispatchAction for wizardspackage com.oreilly.strutsckbk.ch07; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.actions.LookupDispatchAction; public class WizardLookupDispatchAction extends LookupDispatchAction { public WizardLookupDispatchAction( ) { keyMethodMap = new HashMap( ); keyMethodMap.put("button.previous", "doPrevious"); keyMethodMap.put("button.next", "doNext"); keyMethodMap.put("button.finish", "doFinish"); } public ActionForward doPrevious( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { processPrevious(mapping, form, request, response); return mapping.findForward("previous"); } protected void processPrevious( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { } public ActionForward doNext( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { processNext(mapping, form, request, response); return mapping.findForward("next"); } protected void processNext( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { } public ActionForward doFinish( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { processFinish(mapping, form, request, response); return mapping.findForward("finish"); } protected void processFinish( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { } protected Map getKeyMethodMap( ) { return keyMethodMap; } } Specify the workflow for the wizard in the struts-config.xml file: <!-- Wizard mappings --> <!-- Step 1 --> <action path="/ViewStep1" name="WizardForm" scope="session" type="org.apache.struts.actions.ForwardAction" parameter="/step1.jsp"/> <action path="/ProcessStep1" name="WizardForm" scope="session" type="com.oreilly.strutsckbk.ch07.WizardLookupDispatchAction" parameter="methodToCall"> <forward name="next" path="/ViewStep2.do"/> </action> <!-- Step 2 --> <action path="/ViewStep2" name="WizardForm" scope="session" type="org.apache.struts.actions.ForwardAction" parameter="/step2.jsp"/> <action path="/ProcessStep2" name="WizardForm" scope="session" type="com.oreilly.strutsckbk.ch07.WizardLookupDispatchAction" parameter="methodToCall"> <forward name="previous" path="/ViewStep1.do"/> <forward name="next" path="/ViewStep3.do"/> </action> <!-- Step 3 --> <action path="/ViewStep3" name="WizardForm" scope="session" type="org.apache.struts.actions.ForwardAction" parameter="/step3.jsp"/> <action path="/ProcessStep3" name="WizardForm" scope="session" type="com.oreilly.strutsckbk.ch07.WizardLookupDispatchAction" parameter="methodToCall"> <forward name="previous" path="/ViewStep2.do"/> <forward name="finish" path="/wizard_done.jsp"/> </action> DiscussionThe topic of wizard-style applications comes up frequently on the Struts mailing lists. Struts doesn't have a silver bullet solution for this problem. Wizard interfaces can be built many ways; there is no "right way" to do it. The Solution leverages the ability of the LookupDispatchAction and the use of a session-scoped form to pass data from page to page. If it doesn't meet your needs, it will at least provide the basis of a custom solution. The WizardLookupDispatchAction subclasses LookupDispatchAction, implementing the getKeyMethodMap( ) method to map a button label key to the corresponding method. Methods are provided for handling previous, next, and finish buttons. Each of these methods delegates processing to a no-op protected method. The business logic for processing the form from each JSP would be added to the processNext( ) method. Business logic required when clicking previous would be implemented in the processPrevious( ) and logic to be handled when clicking finish is implemented in the processFinish( ) method. A benefit of this Solution is you can see the flow from page to page in the struts-config.xml. You can look at the mappings and follow the steps in the flow: <forward name="previous" path="/ViewStep1.do"/> <forward name="next" path="/ViewStep3.do"/> The solution works even if the user clicks the browser's back or forward buttons instead of using the navigation buttons. One common gripe about the LookupDispatchAction is it doesn't work well if you are using images for buttons. In this case, you may want to extend DispatchAction and set the dispatch action using JavaScript. See AlsoUse of the LookupDispatchAction is presented in Recipe 6.9. The DispatchAction is shown in Recipe 6.8. The basic approach shown here is similar to that presented in the Struts Newbie FAQ at http://struts.apache.org/faqs/newbie.html#wizard. An extension to Struts for complex workflows has been developed by Matthias Bauer and can be found at http://www.livinglogic.de/Struts/index.html. This extension utilizes a custom ActionMapping and RequestProcessor. In addition to the basic workflow steps discussed in this recipe, it supports workflow branching and custom authentication. |
|