Skip to content

16. Przykład 13 – kontekst akcji

Ta aplikacja ma na celu pokazanie, że akcja ma dostęp do:

  • do parametrów zapytania
  • do atrybutów żądania
  • do atrybutów sesji użytkownika
 

16.1. Projekt NetBeans

Projekt NetBeans wygląda następująco:

  • w [1], widok [Context.JSP]
  • w [2], akcja [Action1.java] oraz plik konfiguracyjny Struts [example.xml]

16.2. Configuration

Konfiguracja projektu odbywa się w pliku [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>
  • wiersz 8: żądanie URL [/example/Action1] spowoduje instancjonowanie klasy [example.Action]. Ponieważ nie podano żadnej metody, zostanie wykonana metoda execute.
  • wiersz 9: akceptowany jest tylko jeden klucz. Klucz success powoduje wyświetlenie widoku [Context.JSP].

Uproszczona architektura przetwarzania zapytania będzie wyglądać następująco:

Żądanie zostanie przetworzone przez dwa elementy aplikacji internetowej: akcję [Action1] [1] oraz widok [Context.JSP] [2]. Oba te elementy mają dostęp do danych różnego rodzaju:

  • dane o zasięgu Application, [3], c.a.d – dane dostępne dla wszystkich żądań wszystkich użytkowników. Są one prawie zawsze tylko do odczytu. W danych tych często znajduje się początkowa konfiguracja aplikacji. W tym przypadku dostęp do tych danych mają [Action1] i [Context.JSP].
  • Dane o zakresie Session, [4], c.a.d. Dane dostępne dla wszystkich zapytań tego samego użytkownika. Są one dostępne w trybie odczytu i zapisu. W tym przypadku [Action1] będzie korzystać z sesji z uprawnieniami do odczytu i zapisu, podczas gdy [Context.JSP] będzie korzystać z sesji z uprawnieniami tylko do odczytu.
  • Dane o zasięgu Requête i [5], dostępne dla wszystkich elementów przetwarzających zapytanie. W tym przypadku [Action1] umieści dane w tej pamięci, a [Context.JSP] je pobierze. Dane o zasięgu „Zapytanie” umożliwiają elementowi N przekazanie informacji do elementu N+1.
  • Parametry żądania [6] przesłane przez klienta. Są one wykorzystywane wyłącznie do odczytu przez elementy przetwarzające żądanie.

16.3. Akcja [Action1]

Kod klasy [Action1] jest następujący:


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 {

  // konstruktor bez parametrów
  public Action1() {
  }
  // Sesja, żądanie, parametry
  Map<String, Object> session;
  Map<String, Object> request;
  Map<String, String[]> parameters;

  @Override
  public String execute() {
    // lista parametrów
    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));
      }
    }
    // sesja
    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));
    // żądanie
    request.put("info1", "information1");
    // wyświetlanie strony JSP
    return SUCCESS;
  }

  // sesja
  public void setSession(Map<String, Object> session) {
    this.session = session;
  }

  // żądanie
  public void setRequest(Map<String, Object> request) {
    this.request = request;
  }

  // parametry
  public void setParameters(Map<String, String[]> parameters) {
    this.parameters = parameters;
  }
}
  • wiersz 10: klasa implementuje następujące interfejsy
    • SessionAware: w celu uzyskania dostępu do słownika atrybutów sesji (wiersz 16). Interfejs ten posiada tylko jedną metodę, znajdującą się w wierszu 46.
    • RequestAware: w celu uzyskania dostępu do słownika atrybutów zapytania (wiersz 17). Interfejs ten posiada tylko jedną metodę, znajdującą się w wierszu 51.
    • ParameterAware: w celu uzyskania dostępu do słownika parametrów zapytania (wiersz 18). Należy zauważyć, że każdemu kluczowi (nazwie parametru) odpowiada tablica wartości. Jest to konieczne, aby uwzględnić pola wprowadzania danych, które przesyłają wiele wartości, na przykład listę z możliwością wielokrotnego wyboru. Interfejs ParameterAware posiada tylko jedną metodę, znajdującą się w wierszu 56.
  • wiersz 21: metoda execute, która jest wykonywana po wywołaniu akcji [Action1]. W momencie jej wykonania interceptory wykonały już swoje zadanie:
    • wywołano metodę setParameters (wiersz 56), a słownik parameters w wierszu 18 zawiera wszystkie parametry żądania.
    • wywołano metodę setSession (wiersz 46), a słownik session w wierszu 16 zawiera wszystkie atrybuty sesji.
    • wywołano metodę setRequest (wiersz 51), a słownik request w wierszu 17 zawiera wszystkie atrybuty żądania.
  • wiersze 31–38: zapisywana jest wartość powiązana z kluczem compteur w sesji
  • wiersze 32–34: w sesji wyszukiwany jest klucz compteur. Jeśli go tam nie ma, dodaje się go wraz z wartością całkowitą 0.
  • wiersze 35–37: w sesji wyszukiwany jest klucz compteur, jego wartość jest zwiększana, a następnie klucz jest ponownie zapisywany w sesji.
  • wiersz 38: wyświetlana jest wartość powiązana z kluczem compteur. Ponieważ przyrost wartości następuje przy każdym wywołaniu akcji [Action1], wartość licznika powinna rosnąć wraz z kolejnymi wywołaniami.
  • wiersz 40: do słownika atrybutów żądania dodawany jest atrybut o kluczu info1 i wartości information1. Atrybuty żądania różnią się od jego parametrów. Parametry są wysyłane przez klienta aplikacji internetowej. Atrybuty żądania umożliwiają natomiast komunikację między różnymi elementami aplikacji internetowej, które je przetwarzają. Tak więc po wykonaniu [Action1] zostanie wyświetlony widok [Context.JSP]. Zobaczymy, że jest on w stanie pobrać atrybuty żądania.
  • wiersz 42: metoda execute zwraca klucz succes.

16.4. Plik komunikatów

Plik [messages.properties] ma następującą treść:


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. Widok [Context.JSP]

Widok [Context.JSP] służy do wyświetlania:

  • niektóre parametry zapytania
  • wartość klucza compteur w sesji
  • wartość klucza info1 w zapytaniu

Jej kod jest następujący:


<%@ 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>
  • wiersze 12–14: wyświetlają wszystkie wartości powiązane z parametrem nom
  • wiersze 15–17: wyświetlają wszystkie wartości powiązane z parametrem prenom
  • wiersze 18–20: wyświetlają wszystkie wartości powiązane z parametrem age
  • wiersz 22: wyświetla wartość powiązaną z kluczem compteur w sesji
  • wiersz 24: wyświetla wartość powiązaną z kluczem info1 w zapytaniu

16.6. Testy

  • w [1], Action1 jest wywoływane bez parametrów
  • w [2], [Context.JSP] nie znaleziono parametrów
  • w [3], [Context.JSP] znaleziono klucz compteur w sesji
  • w [4], [Context.JSP] znalazł klucz info1 w zapytaniu

Przeprowadźmy kolejny test:

  • w [1], Action1 jest wywoływany z parametrami
  • w [2], [Context.JSP] wyświetla te parametry
  • w [3], [Context.JSP] znalazł klucz compteur w sesji. Licznik został prawidłowo zwiększony o 1, co wskazuje, że między dwoma żądaniami rzeczywiście nastąpiło zapamiętanie.
  • W [4], [Context.JSP] znalazło klucz info1 w żądaniu

Przypomnijmy, że metoda [Action1.execute] zapisywała dane na konsoli serwera WWW. Oto przykład:

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

16.7. Conclusion

Należy pamiętać o następujących kwestiach:

  • aby zapisać informacje, które mają być wspólne dla wszystkich żądań wszystkich użytkowników, wykorzystamy pamięć aplikacji. Wkrótce pokażemy tego przykład.
  • aby zapisać informacje, które mają być wspólne dla wszystkich żądań tego samego użytkownika, wykorzystamy sesję tego użytkownika.
  • Aby zapisać informacje, które mają być wspólne dla wszystkich elementów przetwarzających żądanie, wykorzystamy pamięć żądania.