11. Esempio 09 - Conversione e convalida dei numeri interi
Passiamo ora a una serie di esempi sulla conversione e la convalida dei parametri di un modulo. Il problema è il seguente. Per elaborare un URL del tipo [http://machine:port/.../Action], il controller [FilterDispatcher] istanzia la classe che implementa l’azione richiesta ed esegue uno dei suoi metodi, per impostazione predefinita il metodo denominato execute. La chiamata a questo metodo execute passa attraverso una serie di intercettatori:
![]() |
L'elenco degli intercettatori è definito nel file [struts-default.xml] nella directory principale dell'archivio [struts2-core.jar]. L'elenco degli intercettatori ivi definito è il seguente:
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
Tra gli intercettatori, ce n’è uno che si occupa di inserire nell’azione i valori valeuri dei parametri parami che accompagnano la richiesta nella forma parami=valeuri. È noto che valeuri verrà iniettato nel campo parami dell'azione tramite il metodo setParami, se presente. In caso contrario, non avviene alcuna iniezione e non viene segnalato alcun errore.
La stringa parami=valeuri è una stringa di caratteri. Finora, l’inserimento di valeuri è stato effettuato nei campi parami di tipo String:
L'inserimento della stringa valeuri come valore della stringa parami non ha presentato alcun problema. Se parami non è di tipo String, allora valeuri deve essere convertito dal tipo parami al tipo Ti. Questo è il problema della conversione. Ad esempio, si vorrà che un’età sia un numero intero e si scriverà nell’azione:
Inoltre, si potrebbe voler limitare l’età tra 1 e 150. In questo caso si presenta un problema di validazione. Il parametro parami può essere convertito nel tipo corretto senza però essere valido. Ci sono quindi due fasi da superare. Se torniamo allo schema di elaborazione di una richiesta:
![]() |
Due intercettatori si occuperanno rispettivamente della conversione e della convalida dei parametri. Se una delle fasi fallisce, la richiesta non prosegue il suo percorso verso l’azione (percorso rosso sopra). Il modulo da cui sono stati inviati i parametri errati viene visualizzato nuovamente con i messaggi di errore.
Gli intercettatori coinvolti nella conversione e nella convalida dei parametri sono gli intercettatori conversionError e validation delle righe 19 e 20 dell'elenco degli intercettatori presentato in precedenza. Si noti, alle righe 20-22, che l’intercettatore validation non viene applicato se il metodo chiamato è uno dei seguenti: input, back, cancel, browse. Sfrutteremo questa proprietà in seguito.
Iniziamo esaminando la conversione e la convalida dei numeri interi. Dedicheremo un po’ di tempo a questo primo esempio poiché la convalida coinvolge numerosi elementi. Una volta compresi questi, procederemo più rapidamente con gli esempi successivi.
11.1. Il modulo
![]() |
- in [1], il modulo di inserimento
- in [2], il risultato quando si conferma senza inserire valori
11.2. Il progetto NetBeans
Il progetto NetBeans è il seguente:
![]() |
- in [1], le tre viste dell'applicazione
- in [2], i codici sorgente, i file dei messaggi internazionalizzati e i file di configurazione di Struts.
11.3. Configurazione di Struts
L'applicazione è configurata dai file [struts.xml] e [example.xml].
Il file [struts.xml] è il seguente:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.custom.i18n.resources" value="messages" />
<include file="example/example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Accueil</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
</struts>
Le righe 12-18 definiscono l’azione [/example/Accueil] come azione predefinita quando l’utente non ne specifica una.
Il file [example.xml] è il seguente:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Accueil">
<result name="success">/example/Accueil.JSP</result>
</action>
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
</package>
</struts>
- righe 8-10: l'azione [Accueil] fa visualizzare la vista [Accueil.JSP]
- riga 11: l'azione [FormInt] esegue per impostazione predefinita il metodo execute della classe [example.FormInt]. Vedremo che verranno eseguiti altri due metodi, ovvero i metodi input e cancel. Questi metodi verranno quindi specificati nei parametri della query.
- riga 12: la chiave input farà visualizzare la vista [FormInt.JSP] (riga 5). Questa vista è quella del modulo.
- riga 13: la chiave cancel verrà restituita da un metodo cancel associato al link [Annuler]. La vista restituita sarà quindi la vista [Accueil.JSP] dopo un reindirizzamento (type=redirect).
- Riga 14: la chiave success viene restituita dal metodo execute dell'azione [FormInt]. Se la richiesta arriva fino al metodo execute, significa che ha superato con successo tutti gli intercettatori, in particolare quelli che verificano la validità dei parametri. Il metodo execute si limita quindi a restituire la chiave success, che provvederà a visualizzare la vista di conferma [ConfirmationInt.JSP].
11.4. I file dei messaggi
Il file [messages.properties] è il seguente:
Accueil.titre=Accueil
Accueil.message=Struts 2 - Conversions et validations
Accueil.FormInt=Saisie de nombres entiers
Form.titre=Conversions et validations
FormInt.message=Struts 2 - Conversion et validation de nombres entiers
Form.submitText=Valider
Form.cancelText=Annuler
Form.clearModel=Raz mod\u00e8le
Confirmation.titre=Confirmation
Confirmation.message=Confirmation des valeurs saisies
Confirmation.champ=champ
Confirmation.valeur=valeur
Confirmation.lien=Formulaire de test
Oltre a questo file, le viste utilizzano il seguente file [FormInt.properties]:
int1.prompt=1-Nombre entier positif de deux chiffres
int1.error=Tapez un nombre entier positif de deux chiffres
int2.prompt=2-Nombre entier
int2.error=Tapez un nombre entier
int3.prompt=3-Nombre entier >=-1
int3.error=Tapez un nombre entier >=-1
int4.prompt=4-Nombre entier <=10
int4.error=Tapez un nombre entier <=10
int5.prompt=5-Nombre entier dans l''intervalle [1,10]
int5.error=Tapez un nombre entier dans l''intervalle [1,10]
int6.prompt=6-Nombre entier dans l''intervalle [2,20]
int6.error=Tapez un nombre entier dans l''intervalle [2,20]
Il file [FormInt.properties] viene utilizzato solo quando l'azione che ha generato la vista è l'azione [FormInt]. Si tratta di un modo per segmentare il file dei messaggi qualora questo risulti troppo grande. I messaggi dell’azione vengono internazionalizzati nel file [Action.properties].
11.5. Le viste e le azioni
Presentiamo ora le viste e le azioni dell’applicazione. In base alla configurazione dell’applicazione:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Accueil">
<result name="success">/example/Accueil.JSP</result>
</action>
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
</package>
</struts>
si nota che sono presenti tre viste [Accueil.JSP, FormInt.JSP, ConfirmationFormInt.JSP] e due azioni [Accueil, FormInt].
11.5.1. Accueil.JSP
La vista [Accueil.JSP] è la seguente:
![]() |
Il suo codice è il seguente:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Accueil.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Accueil.message"/></h2>
<ul>
<li>
<s:url id="URL" action="FormInt!input"/>
<s:a href="%{URL}"><s:text name="Accueil.FormInt"/></s:a>
</li>
</ul>
</body>
</html>
Il link della riga 14 genera il seguente codice HTML:
<a href="<a href="view-source:http://localhost:8084/exemple-09/example/FormInt.action">/exemple-09/example/FormInt!input.action</a>">Saisie de nombres entiers</a>
Si tratta quindi di un collegamento all'azione [FormInt] configurata come segue in [example.xml]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
Cliccando sul link verrà quindi istanziata la classe [example.FormInt] e verrà eseguito il metodo input di quest'ultima. Poiché quest’ultima non esiste, verrà eseguito il metodo input della classe padre ActionSupport. Quest’ultimo non fa altro che restituire la chiave input. Verrà quindi visualizzata la vista [/example/FormInt.JSP].
Inoltre, il metodo input è uno dei metodi ignorati dall’intercettatore di convalida:
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
Pertanto non verrà effettuata alcuna convalida dei parametri. Questo è importante perché in questo caso non ci sono parametri e vedremo in seguito che le regole di convalida imporranno l’esistenza di sei parametri.
11.5.2. L'azione [FormInt]
L’azione [FormInt] è associata alla seguente classe [FormInt]:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.interceptor.validation.SkipValidation;
public class FormInt extends ActionSupport implements ModelDriven, SessionAware {
// costruttore senza parametri
public FormInt() {
}
// modello dell'azione
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
public String cancel() {
// si pulisce il modello
((FormIntModel) getModel()).clearModel();
// risultato
return "cancel";
}
@SkipValidation
public String clearModel() {
// azzeramento del modello
((FormIntModel) getModel()).clearModel();
// risultato
return INPUT;
}
// SessionAware
private Map<String, Object> session;
public void setSession(Map<String, Object> session) {
this.session = session;
}
// convalida
@Override
public void validate() {
// valido per int6?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
}
}
Commenteremo questo codice man mano che se ne presenterà la necessità. Per ora:
- riga 9, la classe [FormInt] implementa due interfacce:
- ModelDriven, che ha un solo metodo, getModel alla riga 16
- SessionAware, che ha un solo metodo, setSession alla riga 41
- righe 16-21: implementazione dell'interfaccia ModelDriven. Si ricorda che questa interfaccia consente di esternalizzare il modello di una vista in una classe esterna, in questo caso la seguente classe [FormIntModel]:
package example;
public class FormIntModel {
// costruttore senza parametri
public FormIntModel() {
}
// campi del modulo
private String int1;
private Integer int2;
private Integer int3;
private Integer int4;
private Integer int5;
private String int6;
// campo modello vuoto
public void clearModel(){
int1=null;
int2=null;
int3=null;
int4=null;
int5=null;
int6=null;
}
// getter e setter
...
}
Il modello [FormIntModel] presenta sei campi corrispondenti ai sei campi di immissione della vista [FormInt.JSP]. Sono proprio questi sei campi che riceveranno i valori inviati. Quattro di essi sono di tipo Integer. Per essi si presenterà quindi il problema della conversione da String a Integer. Il metodo clearModel consente di reinizializzare il modello.
Torniamo al metodo getModel dell’azione [FormInt]:
// modello dell'azione
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
- righe 3-5: il modello viene cercato nella sessione. Se non è presente, viene creata un'istanza del modello e inserita nella sessione.
- riga 6: mentre per ogni nuova richiesta all’azione viene creata un’istanza dell’azione, il suo modello rimarrà nella sessione.
Notiamo che la classe non definisce alcun metodo input, ma la classe padre ne possiede uno che restituisce la chiave input. L’esecuzione di questo metodo comporta la visualizzazione della vista [FormInt.JSP] che presentiamo ora.
11.5.3. La vista [FormInt.JSP]
La vista [FormInt.JSP] è la seguente:
![]() |
- in [1], il modulo vuoto
- in [2], il modulo dopo la convalida di parametri errati.
Il codice è il seguente:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="FormInt.message"/></h2>
<s:form name="formulaire" action="FormInt">
<s:textfield name="int1" key="int1.prompt"/>
<s:textfield name="int2" key="int2.prompt"/>
<s:textfield name="int3" key="int3.prompt"/>
<s:textfield name="int4" key="int4.prompt"/>
<s:textfield name="int5" key="int5.prompt"/>
<s:textfield name="int6" key="int6.prompt"/>
<s:submit key="Form.submitText" method="execute"/>
</s:form>
<br/>
<s:url id="URL" action="FormInt" method="cancel"/>
<s:a href="%{URL}"><s:text name="Form.cancelText"/></s:a>
<br/>
<s:url id="URL" action="FormInt" method="clearModel"/>
<s:a href="%{URL}"><s:text name="Form.clearModel"/></s:a>
</body>
</html>
- righe 12-17: i sei campi di immissione corrispondenti ai sei campi del modello [FormIntModel] dell'azione [FormInt]. Quando viene visualizzata la vista, sono gli attributi value dei campi di immissione che vengono utilizzati per il valore visualizzato da tali campi. In assenza dell’attributo value, viene utilizzato l’attributo name.
- riga 12: il campo di immissione è associato (name) al campo int1 dell’azione o del suo modello, se l’azione implementa l’interfaccia ModelDriven. È il caso qui. Lo stesso vale anche per tutti gli altri campi.
- riga 18: il pulsante [Valider] invia i dati inseriti all’azione [FormInt] definita alla riga 11. Verrà eseguito il suo metodo execute.
- righe 21-22: il collegamento [Annuler] esegue il metodo [FormInt.cancel].
- righe 24-25: il collegamento [Raz modèle] esegue il metodo [FormInt.clearModel].
11.5.4. La vista [ConfirmationFormInt.JSP]
![]() |
Viene visualizzata quando tutti i dati inseriti nel modulo [FormInt.JSP] sono validi.
- in [1], si registrano i valori validi
- in [2], la pagina di conferma
Il codice della vista [ConfirmationInt.JSP] è il seguente:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Confirmation.titre"/></title>
<s:head/>
</head>
<body background="<s:url value="/ressources/standard.jpg"/>">
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.champ"/></th>
<th><s:text name="Confirmation.valeur"/></th>
</tr>
<tr>
<td><s:text name="int1.prompt"/></td>
<td><s:property value="int1"/></td>
</tr>
<tr>
<td><s:text name="int2.prompt"/></td>
<td><s:property value="int2"/></td>
</tr>
<tr>
<td><s:text name="int3.prompt"/></td>
<td><s:property value="int3"/></td>
</tr>
<tr>
<td><s:text name="int4.prompt"/></td>
<td><s:property value="int4"/></td>
</tr>
<tr>
<td><s:text name="int5.prompt"/></td>
<td><s:property value="int5"/></td>
</tr>
<tr>
<td><s:text name="int6.prompt"/></td>
<td><s:property value="int6"/></td>
</tr>
</table>
<br/>
<s:url id="URL" action="FormInt" method="input"/>
<s:a href="%{URL}"><s:text name="Confirmation.lien"/></s:a>
</body>
</html>
Per comprendere questo codice, occorre ricordare che la vista viene visualizzata dopo l’istanziazione della classe [FormInt]. I campi di quest’ultima e del suo modello [FormIntModel] sono quindi accessibili alla vista.
- righe 16-38: vengono visualizzati i valori dei sei campi
- righe 42-43: un collegamento all’azione [FormInt]. Il codice generato per questo collegamento è il seguente:
<a href="/exemple-09/example/FormInt!input.action">Formulaire de test</a>
Il codice specifico URL del collegamento indica che il metodo input dell’azione [FormInt] deve elaborare la richiesta. Ricordiamo la configurazione dell’azione [FormInt] in [example.xml]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
Il metodo input della classe [FormInt] sarà quello della sua classe padre ActionSupport. L'esecuzione del metodo input della classe [FormInt] avviene dopo l'esecuzione degli intercettatori
![]() |
È noto che la chiamata al metodo input viene ignorata dall'intercettatore di convalida. Non verrà quindi eseguita alcuna convalida.
Viene visualizzata la vista [FormInt.JSP]:
![]() |
In [2], i campi di immissione recuperano i valori immessi. Questo può sembrare normale, ma non lo è. Essendo stata richiamata l’azione [FormInt], è stata istanziata la classe associata [FormInt]. Poiché questa classe implementa l’interfaccia ModelDriven, è stato richiamato il suo metodo getModel:
// modello dell'azione
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
Si nota che il modello dell’azione viene recuperato dalla sessione. Nella fase precedente, tale modello era stato aggiornato con i valori inviati. Si ritrovano quindi questi valori. Se il modello non fosse stato inserito nella sessione, nella vista [FormInt.JSP] ci sarebbero stati sei campi vuoti.
11.5.5. L'azione [FormInt!clearModel]
L'azione [Formint!clearModel] viene attivata cliccando sul link [Raz modèle]:
![]() |
- in [1], il modulo dopo un inserimento errato
- in [2], il modulo dopo aver cliccato sul link [Raz modèle].
Il metodo [FormInt.clearModel] è il seguente:
@SkipValidation
public String clearModel() {
// reset del modello
((FormIntModel) getModel()).clearModel();
// risultato
return INPUT;
}
- riga 1: non è necessaria alcuna convalida. Si utilizza la notazione @SkipValidation per indicarlo. L’intercettatore di convalida non effettuerà quindi le convalide.
- riga 4: viene eseguito il metodo [FormIntModel].clearModel. Lo abbiamo già incontrato. Reimposta a null i sei campi del modello.
- riga 7: il metodo restituisce la chiave input.
Se torniamo alla configurazione dell’azione [FormInt]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
si nota che la chiave input farà visualizzare la vista [FormInt.JSP]. Quest’ultima mostra i sei campi del modello. Poiché questi si trovano in null, la vista visualizza sei campi vuoti [2].
11.5.6. L'azione [FormInt!cancel]
L'azione [Formint!cancel] viene attivata cliccando sul link [Annuler]:
![]() |
- in [1], il modulo dopo un inserimento errato
- in [2], la pagina iniziale dopo aver cliccato sul link [Annuler].
Il metodo [FormInt.cancel] è il seguente:
public String cancel() {
// si pulisce il modello
((FormIntModel) getModel()).clearModel();
// risultato
return "cancel";
}
- riga 1: si noti che il metodo non è preceduto dall'annotazione SkipValidation. Tuttavia, non si desidera eseguire le validazioni. Il metodo cancel fa parte dei quattro metodi input, back, cancel, browse ignorati dall’intercettatore di validazione, pertanto l’annotazione SkipValidation non è necessaria.
- riga 3: svuota il modello
- riga 5: restituisce la chiave cancel
Se torniamo alla configurazione dell’azione [FormInt]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
si nota che la chiave cancel farà visualizzare la vista [Accueil.JSP] dopo un reindirizzamento del client. È quanto mostra la vista [2].
11.6. Il processo di convalida
Passiamo ora alla convalida dei sei campi di immissione associati ai seguenti sei campi del modello:
// campi del modulo
private String int1;
private Integer int2;
private Integer int3;
private Integer int4;
private Integer int5;
private String int6;
Questa convalida avviene ogni volta che la classe [FormInt] viene istanziata e il metodo eseguito non viene ignorato dall’intercettatore di convalida. È gestita da:
- il file [FormInt-validation.xml], se presente nella stessa cartella della classe [FormInt]
- il metodo [FormInt.validate], se presente.
![]() |
- in [1]: il file [xwork-validator-1.0.2.dtd] necessario per il processo di convalida
- in [2]: il file [FormInt-validation.xml] nella stessa cartella della classe [FormInt]
Il file [FormInt-validation.xml] è il seguente:
<!--
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
-->
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://localhost:8084/esempio-09/example/xwork-validator-1.0.2.dtd">
<validators>
<field name="int1" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int1.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{2}$</param>
<param name="trim">true</param>
<message key="int1.error"/>
</field-validator>
</field>
<field name="int2" >
...
</field>
...
</validators>
- in [3], il file URL della DTD (Document Type Definition) del file di validazione. Quest’ultima deve essere accessibile, altrimenti il file di validazione non viene utilizzato.
- in [7], il URL del DTD utilizzato dall'applicazione. Abbiamo inserito il file DTD nella cartella [example] del progetto exemple-09 [1] in modo da averlo a disposizione anche in assenza di connessione a Internet.
- righe 11-20: definiscono le condizioni di convalida del parametro int1 associato al campo int1 del modello.
Il tag denominato int1 nel modulo è il seguente:
<s:textfield name="int1" key="int1.prompt" />
Il campo int1 del modello è dichiarato come segue:
private String int1;
- righe 12-14: verificano che il parametro int1 esista (non null) e abbia lunghezza diversa da zero. In caso contrario, al campo di immissione viene associato un messaggio di errore. È definito in [FormInt.properties] come segue:
int1.error=Tapez un nombre entier positif de deux chiffres
In caso di errore, il processo di convalida del parametro int1 viene interrotto (short-circuit=true).
- righe 15-19: la validità del parametro int1 viene verificata tramite un'espressione regolare.
- riga 16: l'espressione regolare, in questo caso 2 cifre senza nulla né prima né dopo.
- riga 17: il parametro int1, prima di essere confrontato con l’espressione regolare, verrà privato degli spazi iniziali e finali.
- riga 18: l'eventuale messaggio di errore. È lo stesso del validatore precedente.
Vediamo come funziona:
![]() |
- in [1], un inserimento errato per il campo int1
- in [2], la pagina restituita:
- è presente il messaggio di errore relativo alla chiave int1.error. È in rosso.
- anche la dicitura del campo errato è in rosso.
- Il dato errato viene visualizzato nuovamente. È necessario tenerne conto poiché non si tratta necessariamente del comportamento predefinito.
Abbiamo visto che la convalida del modulo provoca l’esecuzione del metodo [FormInt].execute se la richiesta riesce a superare tutti gli intercettatori, in particolare quello di convalida:
![]() |
- se la richiesta arriva al metodo execute dell’azione, quest’ultimo restituisce la chiave success al controller, come abbiamo visto...
- se l’intercettatore di validazione blocca la richiesta perché i parametri verificati non sono validi, allora la chiave input viene restituita al controller.
Poiché l’azione [FormInt] è configurata come segue:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.JSP</result>
<result name="cancel" type="redirect">/example/Accueil.JSP</result>
<result name="success">/example/ConfirmationFormInt.JSP</result>
</action>
in caso di errore di convalida, viene visualizzata la vista [FormInt.JSP], ovvero il modulo. I tag Struts sono realizzati in modo tale da visualizzare eventuali messaggi di errore ad essi associati. Si otterrà quindi la vista [FormInt.JSP] con i messaggi di errore associati ai diversi campi. È quanto mostra la vista [2].
Esaminiamo ora la convalida del campo int2, dichiarato come segue nel modello:
private Integer int2;
La convalida del campo int2 in [FormInt-validation.xml] è la seguente:
<field name="int2" >
<field-validator type="required" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
</field>
- righe 2-4: verificano che il parametro int2 esista.
- righe 5-7: verificano che la conversione da String a Integer sia possibile
- righe 3 e 6: il messaggio di errore della chiave int2.error è il seguente:
int2.error=Tapez un nombre entier
La convalida dei campi Integer e int3 del modello in [FormInt-validation.xml] è la seguente:
<field name="int3" >
<field-validator type="required" short-circuit="true">
<message key="int3.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">-1</param>
<message key="int3.error"/>
</field-validator>
</field>
- righe 8-11: verificano che il campo int3 sia di tipo intero >=-1
- righe 3 e 7: il messaggio di errore relativo alla chiave int3.error è il seguente:
int3.error=Tapez un nombre entier >=-1
La convalida dei campi Integer e int4 del modello in [FormInt-validation.xml] è la seguente:
<field name="int4" >
<field-validator type="required" short-circuit="true">
<message key="int4.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="max">10</param>
<message key="int4.error"/>
</field-validator>
</field>
- righe 8-11: verificano che sia di tipo intero <=10
- righe 3 e 7: il messaggio di errore della chiave int4.error è il seguente:
int4.error=Tapez un nombre entier <=10
La convalida del campo Integer int5 del modello in [FormInt-validation.xml] è la seguente:
<field name="int5" >
<field-validator type="required" short-circuit="true">
<message key="int5.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">1</param>
<param name="max">10</param>
<message key="int5.error"/>
</field-validator>
</field>
- righe 5-9: verificano che sia di tipo intero nell'intervallo [1, 10].
- righe 3 e 8: il messaggio di errore relativo alla chiave int5.error è il seguente:
int5.error=Tapez un nombre entier dans l''intervalle [1,10]
La convalida del campo String int6 del modello in [FormInt-validation.xml] è la seguente:
<field name="int6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{1,2}$</param>
<param name="trim">true</param>
<message key="int6.error"/>
</field-validator>
</field>
- righe 5-9: verificano che int6 sia una stringa di 2 cifre.
- riga 3, 8: il messaggio di errore relativo alla chiave int6.error è il seguente:
int6.error=Tapez un nombre entier dans l''intervalle [2,20]
La verifica precedente non controlla che il parametro int6 sia un numero intero compreso nell'intervallo [2,20]. Tale verifica viene effettuata nel metodo [FormInt].validate, che viene eseguito dopo l’elaborazione del file [FormInt-validation.xml]. Il metodo è il seguente:
// convalida
@Override
public void validate() {
// valido l'inserimento di int6?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
}
- riga 5: si verifica se sono presenti errori associati al campo int6. In caso affermativo, non si procede oltre.
- riga 6: se non si sono verificati errori, si recupera il campo String int6 del modello e lo si converte in un numero intero.
- riga 7: si verifica che il numero intero recuperato rientri nell’intervallo [2,20].
- riga 8: in caso contrario, al campo int6 viene associato un messaggio di errore. Tale messaggio di errore viene ricercato nel file dei messaggi con la chiave int6.error.
Se al termine di questo processo di convalida si riscontrano errori, la chiamata al metodo [FormInt].execute viene interrotta e la chiave input viene restituita al controller Struts.
![]() |
11.7. Ultimi dettagli
Abbiamo visto diversi modi per inserire numeri interi. Non sono tutti equivalenti. Consideriamo ad esempio i campi di immissione int5 e int6:
Nella vista [FormInt.JSP], sono dichiarati come segue:
<s:textfield name="int5" key="int5.prompt"/>
<s:textfield name="int6" key="int6.prompt"/>
Il loro modello è dichiarato in [FormIntModel.java]:
private Integer int5;
private String int6;
Il campo int5 è di tipo Integer, mentre il campo int6 è di tipo String. Le loro regole di convalida sono diverse:
<field name="int5" >
<field-validator type="required" short-circuit="true">
<message key="int5.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">1</param>
<param name="max">10</param>
<message key="int5.error"/>
</field-validator>
</field>
<field name="int6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{1,2}$</param>
<param name="trim">true</param>
<message key="int6.error"/>
</field-validator>
</field>
La convalida del campo int6 viene completata dal metodo validate dell’azione [FormInt]:
public void validate() {
// valido?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
Sebbene espresse in modo diverso, entrambe le regole di convalida mirano a verificare che il campo inserito sia un numero intero compreso in un intervallo. Il comportamento dei campi int5 e int6 è tuttavia diverso in fase di esecuzione, come mostrano le seguenti schermate:
![]() |
- in [1], lo stesso inserimento errato per entrambi i campi
- in [2], la pagina di errore restituita. I due campi presentano messaggi di errore diversi.
- in [3] appare per il campo int5 un messaggio indesiderato perché è in inglese. Deriva dalla conversione fallita da String a Integer. Si riscontra inoltre un'eccezione nei log di Apache:
Curiosamente, Struts ha cercato un metodo FormIntModel.setInt5(String value) che non ha trovato.
La chiave del messaggio indesiderato è xwork.default.invalid.fieldvalue. Per tradurlo in francese, basta associare un testo in francese a questa chiave. Si aggiunge quindi al file [messages.properties] la seguente riga:
...
xwork.default.invalid.fieldvalue=Valeur invalide pour le champ "{0}".
11.8. Conclusion
L’analisi di questa prima applicazione dedicata alla convalida dei parametri è terminata. È stata complessa da spiegare. Ora esamineremo applicazioni simili. Pertanto, commenteremo solo le parti che cambiano.















