DispatchAction:
This is an abstract Action that dispatches to a public method that is named by the request parameter whose name is specified by the parameter property of the corresponding ActionMapping. This Action is useful for developers who prefer to combine many similar actions into a single Action class, in order to simplify their application design. To configure the use of this action in our struts-config.xml file, create an entry like this:
<action
path="/saveSubscription"
type="org.apache.struts.actions.DispatchAction"
name="subscriptionForm"
scope="request"
input="/subscription.jsp"
parameter="method"/> which will use the value of the request parameter named "method" to pick the appropriate "execute" method, which must have the same signature of the standard Action.execute method. For example, we might have the following three methods in the same action:
- Public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
- Public ActionForward insert(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
- Public ActionForward update(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
and call one of the methods with a URL like this:
http://localhost:8080/myapp/saveSubscription.do?method=update
It should be noted that we don't have to use the DispatchAction to group multiple actions into one Actionclass. We could just use a hidden field that we inspect to delegate to member() methods inside of our action. On the other hand, we could use the action element's parameter attribute and decide which method to invoke based on the value of the parameter attribute.
The DispatchAction uses a hidden request parameter to determine which method to invoke. Thus, subclasses of the DispatchAction have many methods with the same signature of the execute() method. The name of the hidden request parameter specifies the name of the method to invoke. We specify the name of the hidden parameter by using the parameter attribute of the action element.
Rather than having a single execute() method, we have a method for each logical action. The DispatchAction dispatches to one of the logical actions represented by the methods. It picks a method to invoke based on anincoming request parameter. The value of the incoming request parameter is the name of the method that the DispatchAction will invoke.
All of the other mapping characteristics of this action must be shared by the various handlers. This places some constraints over what types of handlers may reasonably be packaged into the same DispatchAction subclass. If the value of the request parameter is empty, a method named unspecified is called. The default action is to throw an exception. If the request was cancelled, the custom handler cancelled, will be used instead. We can also override the getMethodName method to override the action's default handler selection. Here is an example that groups multiple actions into one action.
- Create an action handler class that subclasses DispatchAction:
public class UserRegistrationMultiAction extends DispatchAction { ... } - Create a method to represent each logical related action:
public ActionForward processPage1(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ... } public ActionForward processPage2(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ... }
These methods have the same signature other than the method name of the standard Action method. - Create an Action Mapping for this action handler using the parameter attribute to specify the request parameter that carries the name of the method that we want to invoke:
<action path="/userRegistrationMultiPage1" type="strutsTutorial.UserRegistrationMultiAction" name="userRegistrationForm" attribute="user" parameter="action" input="/userRegistrationPage1.jsp"> ... </action> <action path="/userRegistrationMultiPage2" type="strutsTutorial.UserRegistrationMultiAction" name="userRegistrationForm" attribute="user" parameter="action" input="/userRegistrationPage2.jsp"> ... </action>
Based on this code, the DispatchAction that we created uses the value of the request parameter named method to pick the appropriate method to invoke. The parameter attribute specifies the name of the request parameter that is inspected by the DispatchAction. - Pass the action a request parameter that refers to the method we want to invoke. TheuserRegistrationPage1.jsp contains this hidden parameter:
<html:hidden property="action" value="processPage1"/> while the userRegistrationPage2.jsp contains this hidden parameter: <html:hidden property="action" value="processPage2"/>
This implementation sends a hidden field parameter instead that specifies which method to invoke.
LookupDispatchAction:
This is an abstract Action that dispatches to the subclass mapped execute method. This is useful in cases where an HTML form has multiple submit buttons with the same name. The button name is specified by theparameter property of the corresponding ActionMapping. To configure the use of this action in our struts-config.xml file, create an entry like this:
<action
path="/test"
type="org.example.MyAction"
name="MyForm"
scope="request"
input="/test.jsp"
parameter="method"/> which will use the value of the request parameter named "method" to locate the corresponding key in ApplicationResources. For example, we might have the following ApplicationResources.properties:
button.add=Add Record
button.delete=Delete Record And our JSP would have the following format for submit buttons:
<html:form action="/test">
<html:submit property="method">
<bean:message key="button.add"/>
</html:submit>
<html:submit property="method">
<bean:message key="button.delete"/>
</html:submit>
</html:form> Our subclass must implement both getKeyMethodMap and the methods defined in the map. An example of such implementations are:
protected Map getKeyMethodMap() {
Map map = new HashMap();
map.put("button.add", "add");
map.put("button.delete", "delete");
return map;
}
public ActionForward add(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
// do add
return mapping.findForward("success");
}
public ActionForward delete(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
// do delete
return mapping.findForward("success");
} If duplicate values exist for the keys returned by getKeys, only the first one found will be returned. If no corresponding key is found then an exception will be thrown. We can override the method unspecified to provide a custom handler. If the submit was cancelled, the custom handler cancelled will be used instead.
For this example, we use the registration form to use the LookupDispatchAction. We will add two buttons. One button will be labeled Save; this button will save the user to the system. The second button will be called Removeto use the LookupDispatchAction, perform the following steps:
- Create an action handler class that subclasses LookupDispatchAction:
public class UserRegistrationAction extends LookupDispatchAction {...} - Next, we create a method to represent each logical related action: save and remove:
public class UserRegistrationAction extends LookupDispatchAction { private static Log log = LogFactory.getLog(UserRegistrationAction.class); public ActionForward remove( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { log.debug("IN REMOVE METHOD"); return mapping.findForward("success"); } public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { /* Create a User DTO and copy the properties from the userForm */ User user = new User(); BeanUtils.copyProperties(user, form); DataSource dataSource = getDataSource(request, "userDB"); Connection conn = dataSource.getConnection(); try { /* Create UserDAO */ UserDAO dao = DAOFactory.createUserDAO(conn); /* Use the UserDAO to insert the new user into the system */ dao.createUser(user); } finally { conn.close(); } return mapping.findForward("success"); } }
The two action methods, save and remove, have identical signatures to the standard Action.execute()method except for the method name. - Implement the getKeyMethodMap() method to map the resource keys to method names:
protected Map getKeyMethodMap() { Map map = new HashMap(); map.put("userRegistration.removeButton", "remove"); map.put("userRegistration.saveButton", "save"); return map; }
- Create an action mapping for this action handler using the parameter attribute to specify the request parameter that carries the name of the method we want to invoke:
<action path="/userRegistration" type="strutsTutorial.UserRegistrationAction" name="userRegistrationForm" attribute="user" input="/userRegistration.jsp" parameter="action" > ... <forward name="success" path="/regSuccess.jsp" /> <forward name="failure" path="/regFailure.jsp" /> </action>
Here we specify the parameter to the action. This has a similar meaning to the DispatchAction. Essentially, this means the LookupDispatchAction inspects the label of the button called action. The label will be looked up from the resource bundle, the corresponding key will be found, and the key will be used against the method map to find the name of the method to invoke. - Set up the messages in the resource bundle for the labels and values of the buttons. Inside our resource bundle, add the following two entries:
userRegistration.removeButton=Remove userRegistration.saveButton=Save
Here the keys are the same keys we used in the getKeyMethodMap. - Use the bean:message tag to display the labels of the button and associate the buttons with the name action:
<%@ taglib uri="/tags/struts-html" prefix="html"%> <%@ taglib uri="/tags/struts-bean" prefix="bean"%> ... <html:submit property="action"> <bean:message key="userRegistration.removeButton"/> </html:submit> ... <html:submit property="action"> <bean:message key="userRegistration.saveButton"/> </html:submit> ...
The final result depends on the user clicks.
Posted in: