Uno dei problemi più noiosi da gestire nello sviluppo di una web-application è il caso in cui non si conosce a priori il numero di elementi che saranno postati attraverso una form. Questo capita quando c’è di mezzo una tabella con dati provenienti da database e bisogna eseguire su questi piu operazioni con un solo submit della form stessa.
Un esempio classico è il carrello. Un carrello contiene da 1 a infiniti elementi e per ognuno di essi è definita una quantità. Questo viene mostrato all’utente sottoforma di una tabella e l’utente può modificare più quantità contemporaneamente ed eseguire, quando tutto è a posto, un singolo “aggiorna totali” o “check-out”.

Per gestire questo problema senza l’ausilio di un framework bisognerebbe decidere una strategia di naming dei campi della form che permetta ovviamente la non-sovrapposizione dei dati inseriti dall’utente e garantisca la possibilità di ricollegare le modifiche richieste agli oggetti su cui bisogna effettivamente effettuarle. Fisicamente il name del tag <input /> dovrebbe avere una parte fissa e una parte dinamica che varia di riga in riga. Quando questi dati vengono poi postati vanno riorganizzati in una struttura sensata (una lista, un vettore ….) e trattati dalla business-logic. E’ piu semplice dirlo che farlo.
Se invece utiliziamo Struts qualche aiuto c’è.
Abbiamo fondamentalmente 4 oggetti in gioco. Una pagina JSP che si occupa di visualizzare il contenuto di una lista, e contiene una form. Un oggetto di tipo actionForm che recepisce tutti i dati provenienti dalla from, sia indicizzati sottoforma di una lista che non. Un oggetto che costituisce il modello della singola riga e una Action che costituisce il punto di accesso alla logica applicativa ( a.k.a. fa quello che l’utente si aspetta che faccia)
La JSP è necessario che sia già fatta utilizzando gli strumenti del framework, e non scrivendo codice java.
Per esempio per generare la visualizzazione di una lista di elementi di un carrello faremo quacola di simile a:

<logic:present name="carrello" scope="request">
<logic:iterate id="elemento" name="carrello">
<tr>
<td class="small">
<html:hidden name="elemento" property="id" indexed="true"/>
<bean:write name="elemento"  property=" descr" />&nbsp;</td>
<td>
<html:text  name="elemento" property="qt"  indexed="true"  ></html:text></td>
</tr>
</logic:iterate>
</logic:present>

Gli elementi indicizzati in questo caso sono 2, un tag nascosto contenente un identificativo e un TextField contente la quantità. Il framework in fase di rendering si preoccupera di generare un nome differente per ogni volta che viene iterata questa porzione di codice. Il primo giro i due elementi della form si chiameranno elemento[0].id e elemento[0].qt, la seconda volta elemento[1].id e elemento[1].qt e cosi via.
Ora serve predisporre i due oggetti che “tasportano” i dati dalla visualizzazione al controllore. Il primo di cui ci occupiamo è quello che descrive una “riga” e che verrà istanziato tante volte quante sono le righe stesse. E sarà, pressapoco, simile a quanto segue :

package form;

public class Line {

private string id;
private string qt;

public Line() {
;
}
[… getter e setter standard per entrambe per le proprietà…]
}

Basta costruire un oggetto con proprietà adatte a contenere i dati della singola riga di tabella e relativi metodo per accedervi … semplice no ? Ora l’oggetto che descrive la form è un pochetto più complesso. Se la form contiene dati non indicizzati vanno inserite le relative proprietà come di consueto. Mentre per le righe, non sapendo a priori quante sono, ci affidiamo ad una lista ( LinkedList, ArrayList … o quello che vi sembra più opportuno )

Package form;
[... include vari...]
Public class formCarrello extends ActionForm {
Private List elemento;
Public List getElemento() {   // Non verrà mai usato dal framework, ma puo tornare utile
Return this.elemento;
}

Public void populateElemento(List elemento) {  //Inutilizzato dal FW, di comodo
This.elemento = element
}

Public void setElemento(Line myLine) {
elemento.add(myLine);
}
Public Line getElemento(int index) {
If(this.elemento == null) {
This.elemento = new ArrayList();
}

While (index >= elemento.size) {
This.elemento.add(new Line());
}

Return (Line)this.elemento.get(index);
}

}

La proprietà deve avere lo stesso nome utilizzato in visualizzazione. Il metodo che serve al framework è solo il getter con parametro.

Tutto questo perchè ? Perche il framework non crea autonomamente una lista e la assegna tramite una singola chiamata ad un setter non potendo immaginare che tipo di lista volete usare, o costituita da che tipo di oggetti. Questa è una vostra scelta e tocca quindi a voi l’implementazione. Il framework chiama prima il getter con l’indice della riga, riceve un oggetto di cui non sà nulla, chiama i setter in base al nome delle proprieta nella form e stop. In effeti l’unico metodo strettamente necessario è l’ultimo, che crea la lista se non c’è e crea l’oggetto di indice “index” se non esiste. Gli atri verranno usati nella logica applicativa per-fare-ciò-che-ci-si-aspetta-che-faccia.
Il file di configurazione si configura in modo usuale. Il form-bean è ovviamente “formCarrello” , la Action è quella che andrete a definire per gestire questa complicatissima logica applicativa.