Skip to content

8. Przykład 06 – Sesja

8.1. Pojęcie sesji

Gdy przeglądarka klienta łączy się po raz pierwszy z aplikacją internetową, otrzymuje token sesji – unikalny ciąg znaków, który odsyła wraz z każdym nowym żądaniem kierowanym do aplikacji internetowej. Dzięki temu aplikacja może rozpoznać przeglądarkę klienta. Do tego tokenu sesji może następnie przypisać dane. Dane te należą do jednej przeglądarki klienta. W ten sposób, wraz z kolejnymi żądaniami przeglądarki klienckiej, tworzy się pamięć.

Jak widać powyżej, każdy użytkownik (przeglądarka) posiada własną pamięć, zwaną sesją. Pamięć ta jest wspólna dla wszystkich żądań tego samego użytkownika. Istnieje również pamięć wyższego poziomu, zwana pamięcią aplikacji. Pamięć ta jest wspólna dla wszystkich żądań wszystkich użytkowników. Zazwyczaj jest to pamięć tylko do odczytu.

8.2. Projekt NetBeans

Projekt [exemple-06] powstał poprzez skopiowanie projektu [exemple-05]. Zmienimy kilka elementów, aby

  • wykorzystać sesję użytkownika.
  • dodać nową akcję [Effacer] [1] w celu wyczyszczenia pola wprowadzania danych.

8.3. Configuration

Plik [struts.xml] zmienia się w następujący sposób:


<?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>
  <!-- internacjonalizacja -->
  <constant name="struts.custom.i18n.resources" value="messages" />
  <!-- pakiet domyślny -->
  <package name="default" namespace="/" extends="struts-default">
    <default-action-ref name="index" />
    <action name="index">
      <result type="redirectAction">
        <param name="actionName">Saisir</param>
        <param name="namespace">/actions</param>
      </result>
    </action>
  </package>
  <!-- pakiet akcji -->
  <package name="actions" namespace="/actions" extends="struts-default">
    <action name="Saisir">
      <result name="success">/vues/Saisie.JSP</result>
    </action>
    <action name="Confirmer" class="actions.Confirmer">
      <result name="success">/vues/Confirmation.JSP</result>
    </action>
    <action name="Effacer" class="actions.Effacer">
      <result name="success">/vues/Saisie.JSP</result>
    </action>
  </package>
</struts>

Wiersze 27–29 definiują nową akcję [Effacer] powiązaną z klasą [Effacer]. Odpowiedzią na tę akcję jest widok [Saisie.JSP].

8.4. Akcja [Confirmer]

Zmienia się ona w następujący sposób:


package actions;

import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;

public class Confirmer extends ActionSupport implements SessionAware{
  
  // szablon
  private String nom;
  // sesja
  private Map<String, Object> session;
  
  // metody pobierające i ustawiające

  public String getNom() {
    return nom;
  }

  public void setNom(String nom) {
    this.nom = nom;
  }

  @Override
  public void setSession(Map<String, Object> session) {
    this.session=session;
  }
  
  @Override
  public String execute(){
    // zapisujemy nazwę w sesji
    session.put("nom",nom);
    // nawigacja
    return SUCCESS;
  }
  
}
  • wiersz 7: klasa [Confirmer] implementuje interfejs SessionAware. Interfejs ten posiada tylko jedną metodę – metodę setSession z wierszy 25–27. Przed wywołaniem metody execute jeden z interceptorów żądania wstrzykuje, za pośrednictwem metody setSession, sesję użytkownika w postaci słownika Map<String, Object> (wiersz 25). Postanawiamy zapisać ten słownik w polu session w wierszu 12.
  • wiersze 30–34: metoda execute akcji. Podczas jej wykonywania pole session zostało zainicjowane przez jeden z interceptorów, a pole nom przez inny interceptor. Słownik session służy do przechowywania pola nom. W ten sposób nazwa zostanie zapisana w pamięci użytkownika i będzie dostępna przy każdym jego zapytaniu.

8.5. Widoki [Confirmation.JSP] i [Saisie.JSP]

Widok [Confirmation.JSP] pozostaje bez zmian. Widok [Saisie.JSP] zmienia się w następujący sposób:


<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title><s:text name="saisie.titre1"/></title>
  </head>
  <body>
    <h1><s:text name="saisie.titre2"/></h1>
    <s:form action="Confirmer">
      <s:textfield key="saisie.libelle" name="nom" value="%{#attr['nom']}"/>
      <s:submit key="saisie.valider" action="Confirmer"/>
      <s:submit key="saisie.effacer" action="Effacer"/>
    </s:form>
  </body>
</html>
  • wiersz 12: dodajemy atrybut value do tagu <s:textfield>.. Atrybut ten określa wartość, która ma być wyświetlana w polu wprowadzania danych. W przypadku braku tego atrybutu value = name. W tym przypadku wartością atrybutu jest wyrażenie OGNL (Object-Graph Navigation Language) o postaci %{expression_à_évaluer}. W tym przypadku wyrażeniem do obliczenia jest #attr['nom']. Atrybut nom będzie wyszukiwany kolejno w bieżącej akcji, na stronie, w zapytaniu, w sesji oraz w aplikacji. Ponieważ akcja [Confirmer] umieszcza atrybut nom w sesji, zostanie on tam znaleziony. Pokazuje to następujące zapytanie:

W akcji [1] wprowadzona nazwa brzmiała ST. Wiadomo, że akcja [Confirmer] umieściła tę nazwę w sesji. Link [2] prowadzi nas do URL i [3]. Wyświetlany jest widok [Saisie.JSP]. W przypadku pola wprowadzania danych atrybut %{#attr['nom']} pozwala odzyskać nazwę z sesji.

  • wiersz 14: przycisk [Effacer], który uruchomi akcję [Effacer] i spowoduje wyświetlenie widoku [Saisie.JSP]

<action name="Effacer" class="actions.Effacer">
      <result name="success">/vues/Saisie.JSP</result>
</action>

8.6. Akcja [Effacer]

Kod akcji [Effacer] jest następujący:


package actions;

import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;

public class Effacer extends ActionSupport implements SessionAware{
  
  // sesja
  private Map<String, Object> session;
  
  @Override
  public String execute(){
    // pobieranie nazwy z sesji
    String nom=(String)session.get("nom");
    // w razie potrzeby usuwamy ją z sesji
    if(nom!=null){
      session.remove("nom");
    }
    // nawigacja
    return SUCCESS;
  }

  @Override
  public void setSession(Map<String, Object> map) {
    this.session=map;
  }
}
  • wiersz 7: klasa [Effacer] implementuje interfejs [SessionAware], podobnie jak robiła to akcja [Confirmer].
  • wiersz 13: akcja [Effacer] musi wyczyścić zawartość pola wprowadzania nazwy w widoku [Saisie.JSP]. Wiadomo, że ten widok pobiera tę nazwę z sesji. Należy zatem usunąć nazwę z sesji. Tak właśnie działa metoda execute.

Zobaczmy, jak to wygląda:

W widoku [1] chcemy usunąć pole wprowadzania danych. Klikamy przycisk [Effacer].


<s:submit key="saisie.effacer" action="Effacer"/>

Zostanie wykonana akcja [Effacer]. W [2] widać, że wywołana funkcja URL była tą z akcji [Confirmer]. Wynika to z tagu <s:form> w formularzu:


<s:form action="Confirmer">

, co powoduje, że formularz jest wysyłany do akcji [Confirmer]. Po kliknięciu przycisku [Effacer] parametr

action:Effacer=Effacer

został przesłany do akcji URL [/actions/Confirmer.action]. Struts wykorzystuje ten parametr do przetworzenia danych przesłanych przez akcję [Effacer]. Akcja ta usuwa nazwę sesji. Strona [Saisie.JSP] stanowi odpowiedź akcji [Effacer]:


<action name="Effacer" class="actions.Effacer">
      <result name="success">/vues/Saisie.JSP</result>
</action>

Ta akcja, która wyświetla nazwę sesji, zwraca wówczas pusty ciąg znaków [3].

Przygotowaliśmy kilka prostych przykładów, aby przedstawić ważne koncepcje Struts 2:

  • internacjonalizacja stron
  • wstrzykiwanie parametrów przesłanych w polach akcji
  • pojęcie sesji
  • powiązania między akcjami a widokami

Po opanowaniu tych pojęć możemy teraz przejść do bardziej złożonych przykładów. Zaczniemy od przedstawienia różnych tagów, które można wykorzystać w formularzu.