Skip to content

16. Esempio 13 - Il contesto di un'azione

Questa applicazione ha lo scopo di dimostrare che un'azione ha accesso a:

  • parametri della richiesta
  • agli attributi della richiesta
  • agli attributi della sessione utente

Image

16.1. Il progetto NetBeans

Il progetto NetBeans è il seguente:

  • in [1], la vista [Context.jsp]
  • in [2], l'azione [Action1.java] e il file di configurazione Struts [example.xml]

16.2. Configurazione

La configurazione del progetto è definita in [example.xml]:


<?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="Action1" class="example.Action1">
      <result name="success">/example/Context.jsp</result>
    </action>
  </package>
</struts>
  • Riga 8: La richiesta per l'URL [/example/Action1] attiverà l'istanziazione della classe [example.Action]. Poiché non è specificato alcun metodo, verrà eseguito il metodo execute.
  • Riga 9: È accettata una sola chiave. La chiave "success" fa sì che venga visualizzata la vista [Context.jsp].

L'architettura semplificata per l'elaborazione di una richiesta è la seguente:

La richiesta verrà elaborata da due componenti dell'applicazione web: l'azione [Action1] [1] e la vista [Context.jsp] [2]. Questi due componenti hanno accesso a diversi tipi di dati:

  • Dati a livello di applicazione [3], ovvero dati accessibili a tutte le richieste di tutti gli utenti. Sono quasi sempre di sola lettura. Questi dati contengono spesso la configurazione iniziale dell'applicazione. In questo caso, [Action1] e [Context.jsp] hanno accesso a questi dati.
  • Dati a livello di sessione [4], ovvero dati accessibili a tutte le richieste provenienti dallo stesso utente. Questi dati sono in modalità lettura/scrittura. In questo caso, [Action1] utilizzerà la sessione in modalità lettura/scrittura, mentre [Context.jsp] la utilizzerà in modalità di sola lettura.
  • Dati nell'ambito della richiesta [5], accessibili a tutti gli elementi che elaborano la richiesta. In questo caso, [Action1] memorizzerà i dati in questa memoria e [Context.jsp] li recupererà. I dati nell'ambito della richiesta consentono all'elemento N di passare informazioni all'elemento N+1.
  • Parametri di richiesta [6] inviati dal client. Sono utilizzati in modalità di sola lettura dai componenti che elaborano la richiesta.

16.3. L'azione [Action1]

Il codice per la classe [Action1] è il seguente:


package example;
 
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import java.util.Set;
import org.apache.struts2.interceptor.ParameterAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
 
public class Action1 extends ActionSupport implements SessionAware, RequestAware, ParameterAware {
 
  // constructor without parameters
  public Action1() {
  }
  // Session, Request, Parametres
  Map<String, Object> session;
  Map<String, Object> request;
  Map<String, String[]> parameters;
 
  @Override
  public String execute() {
    // parameter list
    System.out.println("Paramètres...");
    Set<String> clés = parameters.keySet();
    for (String clé : clés) {
      for (String valeur : parameters.get(clé)) {
        System.out.println(String.format("[%s,%s]", clé, valeur));
      }
    }
    // session
    System.out.println("Session...");
    if (session.get("compteur") == null) {
      session.put("compteur", new Integer(0));
    }
    Integer compteur = (Integer) session.get("compteur");
    compteur = compteur + 1;
    session.put("compteur", compteur);
    System.out.println(String.format("compteur=%s", compteur));
    // request
    request.put("info1", "information1");
    // display page JSP
    return SUCCESS;
  }
 
  // session
  public void setSession(Map<String, Object> session) {
    this.session = session;
  }
 
  // request
  public void setRequest(Map<String, Object> request) {
    this.request = request;
  }
 
  // settings
  public void setParameters(Map<String, String[]> parameters) {
    this.parameters = parameters;
  }
}
  • riga 10: la classe implementa le seguenti interfacce
  • SessionAware: per accedere al dizionario degli attributi di sessione (riga 16). Questa interfaccia ha un solo metodo, quello alla riga 46.
  • RequestAware: per accedere al dizionario degli attributi della richiesta (riga 17). Questa interfaccia ha un solo metodo, quello alla riga 51.
  • ParameterAware: per accedere al dizionario dei parametri della richiesta (riga 18). Si noti che ogni chiave (il nome del parametro) corrisponde a un array di valori. Ciò è necessario per gestire i campi di input che inviano più valori, come un elenco a selezione multipla. L'interfaccia ParameterAware ha un solo metodo, quello alla riga 56.
  • Riga 21: il metodo execute, che viene eseguito quando viene richiesta l'azione [Action1]. Al momento dell'esecuzione, gli intercettatori hanno già svolto il loro compito:
  • il metodo setParameters (riga 56) è stato chiamato e il dizionario dei parametri alla riga 18 contiene tutti i parametri della richiesta.
  • Il metodo setSession (riga 46) è stato chiamato e il dizionario session alla riga 16 contiene tutti gli attributi di sessione.
  • il metodo setRequest (riga 51) è stato chiamato e il dizionario request alla riga 17 contiene tutti gli attributi della richiesta.
  • Righe 31–38: Il valore associato alla chiave `compteur` viene scritto nella sessione
  • Righe 32–34: La chiave `compteur` viene cercata nella sessione. Se non viene trovata, viene aggiunta con il valore intero 0.
  • Righe 35–37: La chiave `counter` viene cercata nella sessione, il suo valore viene incrementato e quindi la chiave viene reinserita nella sessione.
  • Riga 38: viene visualizzato il valore associato alla chiave `counter`. Poiché l'incremento viene eseguito ad ogni richiesta sull'azione [Action1], dovremmo vedere il valore del contatore aumentare man mano che vengono effettuate le richieste.
  • Riga 40: un attributo con la chiave `info1` e il valore `information1` viene inserito nel dizionario degli attributi della richiesta. Gli attributi della richiesta sono diversi dai parametri della richiesta. I parametri vengono inviati dal client dell'applicazione web. Gli attributi della richiesta, invece, consentono la comunicazione tra i vari componenti dell'applicazione web che elaborano la richiesta. Pertanto, dopo l'esecuzione di [Action1], verrà visualizzata la vista [Context.jsp]. Vedremo che è in grado di recuperare gli attributi della richiesta.
  • Riga 42: Il metodo execute restituisce la chiave "success".

16.4. Il file dei messaggi

Il file [messages.properties] è il seguente:


Context.titre=Contexte de l''action
Context.message=Contexte de l''action
Context.parameters=Param\u00E8tres de l''action
Context.session=Elements de session
Context.request=Attributs de requ\u00EAte

16.5. La vista [Context.jsp]

La vista [Context.jsp] è responsabile della visualizzazione di:

  • alcuni parametri di richiesta
  • il valore della chiave counter nella sessione
  • il valore della chiave info1 nella richiesta

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="Context.titre"/></title>
    <s:head/>
  </head>
 
  <body background="<s:url value="/ressources/standard.jpg"/>">
    <h2><s:text name="Context.message"/></h2>
    <h3><s:text name="Context.parameters"/></h3>
    <s:iterator value="#parameters['nom']" var="nom">
      nom : <s:property value="nom"/><br/>
    </s:iterator>
    <s:iterator value="#parameters['prenom']" var="prenom">
      prenom : <s:property value="prenom"/><br/>
    </s:iterator>
    <s:iterator value="#parameters['age']" var="age">
      âge : <s:property value="age"/><br/>
    </s:iterator>
    <h3><s:text name="Context.session"/></h3>
    compteur : <s:property value="#session['compteur']"/>
    <h3><s:text name="Context.request"/></h3>
    info1 : <s:property value="#request['info1']"/>
  </body>
</html>
  • Righe 12–14: visualizza tutti i valori associati al parametro "name"
  • righe 15-17: visualizza tutti i valori associati al parametro 'first_name'
  • righe 18-20: visualizza tutti i valori associati al parametro age
  • riga 22: visualizza il valore associato alla chiave counter nella sessione
  • riga 24: visualizza il valore associato alla chiave info1 nella query

16.6. I test

  • In [1], Action1 viene chiamata senza parametri
  • in [2], [Context.jsp] non ha trovato alcun parametro
  • in [3], [Context.jsp] ha trovato la chiave counter nella sessione
  • in [4], [Context.jsp] ha trovato la chiave info1 nella richiesta

Eseguiamo un altro test:

  • In [1], Action1 viene richiesta con i parametri
  • In [2], [Context.jsp] visualizza questi parametri
  • In [3], [Context.jsp] ha trovato la chiave "compteur" nella sessione. Il contatore è stato effettivamente incrementato di 1, dimostrando che i dati sono stati conservati con successo tra le due richieste.
  • In [4], [Context.jsp] ha trovato la chiave "info1" nella richiesta

Ricordiamo che il metodo [Action1.execute] ha scritto sulla console del server web. Ecco un esempio:

1
2
3
4
5
6
7
Paramètres...
[prenom,y]
[prenom,y2]
[age,z]
[nom,x]
Session...
compteur=2

16.7. Conclusione

Tenete a mente i seguenti punti:

  • Per memorizzare le informazioni da condividere tra tutte le richieste di tutti gli utenti, useremo la memoria dell'applicazione. Ne mostreremo un esempio tra poco.
  • Per memorizzare le informazioni da condividere tra tutte le richieste dello stesso utente, useremo la sessione di quell'utente.
  • Per memorizzare le informazioni da condividere tra tutti i componenti che elaborano una richiesta, useremo l'ambito della richiesta.