|
Recipe 6.8. Managing Related Operations from a Central ActionProblemYou want to use a single Action class to handle related operations instead of having to write separate Action classes for each operation. SolutionExtend the DispatchAction with your own class. Provide methods for each operation that you wish to be accessible as an Action. Each method should have the same signature as the execute( ) method except for the method name. The Action class shown in Example 6-4 provides three related operations in one class: create( ), update(), and delete( ). Example 6-4. Dispatch action for related operationspackage com.oreilly.strutsckbk.ch06; 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.DispatchAction; public class MyDispatchAction extends DispatchAction { public ActionForward create( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // create data request.setAttribute("dispatchedTo","create"); return mapping.findForward("success"); } public ActionForward update( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // update data request.setAttribute("dispatchedTo","update"); return mapping.findForward("success"); } public ActionForward delete( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // delete data request.setAttribute("dispatchedTo","delete"); return mapping.findForward("success"); } } In the actions that use your DispatchAction, specify the request parameter whose value will be the method to call: <action path="/DispatchActionTest" name="TestForm" scope="request" type="com.oreilly.strutsckbk.ch06.MyDispatchAction" parameter="methodToCall"> <forward name="success" path="/dispatch_test.jsp"/> </action> On a form that submits to this action, use JavaScript to set the parameter for the method to call. The name of the request parameter must match the value of the parameter attribute from the action mapping. The value of the request parameter is the name of the method. To dispatch to a method from a hyperlink, set the method parameter on the URL. Example 6-5 (dispatch_test.jsp) shows the different ways that you can specify the method parameter for a DispatchAction. Example 6-5. JSP for submitting to a DispatchAction<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <html> <head> <title>Struts Cookbook - Chapter 6 : Dispatch Action Test</title> </head> <body bgcolor="white"> <h2>Dispatch Action Test</h2> <html:form method="get" action="/DispatchActionTest"> Name: <html:text property="name"/> <input type="hidden" name="methodToCall"> <script> function set(target) { document.forms[0].methodToCall.value=target; } </script> <p> <html:submit onclick="set('create');">New</html:submit> <html:submit onclick="set('update');">Edit</html:submit> <html:link href="javascript:set('touch');document.forms[0].submit( );"> <html:img border="0" srcKey="image.touch"/> </html:link> </p> </html:form> <html:link page="/DispatchActionTest.do?methodToCall=delete"> Remove</html:link> </body> </html> DiscussionThe DispatchAction enables a single custom class to process multiple requests for similar operations. Performing create/read/update/delete(CRUD) operations for the same business object exemplifies the classic use case for the DispatchAction. traditionally, four custom Action classes would be written, one for each operation. Since the operations are for the same business object, a significant amount of code would be duplicated. The DispatchAction allows you to use a more natural programming approach. Instead of creating separate classes, you create one class with methods corresponding to the desired operations. A DispatchAction is created by subclassing org.apache.struts.actions.DispatchAction. You don't override the execute( ) method as you would for a normal custom Action. Instead, you implement methods corresponding to the operations you wish to support. Common behavior can be implemented by private methods that you call from the main dispatch operations. The method signature of each operation must be the same as the signature as the execute method: public ActionForward someOperation( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // custom code return mapping.findForward("success"); } The execute( ) method of the base DispatchAction calls a given method of your subclass using the value of a specific HTTP request parameter.
The parameter attribute of the action element in the struts-config.xml file dictates the name of that request parameter: <action path="/DispatchActionTest" type="com.foo.MyDispatchAction" parameter="methodToCall"> <forward name="success" path="/some_page.jsp"/> </action> If the action is called on form submission, use a hidden field with the value set using JavaScript. You'll want to use the HTML <input type="hidden" name="methodToCall"> tag instead of the Struts <html:hidden property="methodToCall"/>. Using the Struts tag forces you to create an artificial property in your ActionForm to hold the methodToCall parameter. If you want to use an image to perform the submission instead of a button, wrap the image in a link. Set the href attribute of the link so it sets the methodToCall property appropriately and submits the form: <script> function set(target) { document.forms[0].methodToCall.value=target; } </script> <html:link href="javascript:set('create');document.forms[0].submit( );"> <html:img border="0" srcKey="image.create"/> </html:link> Finally, all DispatchActions support the ability to define default behavior if the name of the method to call can't be resolved; that is, no matching method is defined in the DispatchAction subclass. The default behavior is implemented by overriding the protected method named unspecified( ). This method, like other custom operational methods of DispatchActions, takes the same arguments as the execute( ) method. Use the unspecified( ) method if the DispatchAction has a primary default operation; then you won't have to use an additional request parameter to access this primary flow. If you don't provide an implementation of unspecified( ), then a ServletException will be thrown if an unknown method is specified. See AlsoRecipe 6.9 provides similar functionality as the DispatchAction without requiring the use of JavaScript on the JSP page. |
|