Spesso le azioni sembrano essere troppo numerose e troppo piccole, sarebbe utile raggruppare azioni correlate in una classe facilitando il riutilizzo.
A tale scopo Struts mette a disposizione le DispatchAction (org.apache.struts.action.DispatchAction
). Il principio alla base è che ci possano essere funzionalità correlate per un servizio che, invece di essere suddivise in molteplici classi Action, si possono tenere insieme nella medesima classe.
DispatchAction è una classe astratta che estende la classe Action. Anziché avere un singolo metodo execute, si ha un metodo per ciascuna azione logica.
Nella request, infatti, bisogna inserire un parametro di nome method
che sarà usato dalla DispatchAction
per determinare quale metodo invocare.
Per implementare una DispatchAction
bisognerà creare:
- una classe action handler che estenda
DispatchAction
; - un metodo per ciascuna azione logica;
- un action-mapping per questo action handler
// Un esempio di DispatchAction
import javax.servlet.http.*;
import javax.servlet.*;
import org.apache.struts.actions.*;
import org.apache.struts.action.*;
public class UserDispatchAction extends DispatchAction {
public ActionForward remove(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
System.out.println("REMOVE USER!!!!");
return mapping.findForward("success");
}
public ActionForward save(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
System.out.println("SAVE USER!!!!");
return mapping.findForward("success");
}
}
È utile notare che tutti i metodi hanno la stessa firma del metodo Action.execute()
.
Produciamo il bean che conterrà il valore di method, unica proprietà del form inviante:
// Bean che contiene il valore di method
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class UserForm1 extends ActionForm {
private String method = null;
public String getMethod() { return method; }
public void setMethod(String method) { this.method = method; }
public void reset(ActionMapping mapping, HttpServletRequest request) {
this.method = method;
}
}
Il terzo step è quello per creare un action mapping per questo action handler e aggiungendo un elemento <form-bean> nel struts-config.xml:
<form-beans>
<form-bean name="userForm1" type="fulvios.UserForm1" />
</form-beans>
<action path="/dispatchUserSubmit"
type="fulvios.UserDispatchAction"
parameter="method"
input="/userForm1.jsp"
name="userForm1"
scope="request"
validate="false">
<forward name="success" path="/success.jsp" />
</action>
Ecco quindi lo step finale: creare la userForm1.jsp
.
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<body>
<html:form action="/dispatchUserSubmit">
action:
<html:select property="method" size="2">
<html:option value="save">Save</html:option>
<html:option value="remove">Remove</html:option>
</html:select>
<br/>
<html:submit/><html:cancel/>
</html:form>
success!!
In questo esempio abbiamo la DispachtAction
che contiene due metodi remove()
e save()
. Questa classe raggruppa tutte le funzionalità a disposizione dell'utente. Se non avessimo utilizzato una DispachtAction
avremmo dovuto creare due Action
e implementare i due metodi excute()
.
DispacthAction
utilizza la reflection per individuare un metodo che corrisponda perfettamente al nome contenuto nel valore del parametro della richiesta, controllando anche la corrispondenza del numero e del tipo degli argomenti. Una volta trovato, il metodo sarà invocato e l'oggetto ActionForward restituito proprio come per una qualunque Action
.
Sebbene si tratti di una soluzione valida, è importante utilizzarla con criterio. La DispatchAction
risulta particolarmente utile quando le classi da raggruppare rappresentano azioni simili tra loro o hanno parti comuni da eseguire prima di effettuare operazioni specifiche. Ad esempio se dobbiamo prelevare dei dati da un database e modificarli in modo differente a seconda della scelta di un utente conviene utilizzare una DispatchAction
per evitare di scrivere uno stesso metodo più volte. Inoltre combinando le operazioni, si renderà più semplice la manutenzione dell'applicazione, infatti se si vuole cambiare l'implementazione di una funzionalità basterà agire solo su una classe.