Skip to content

17. Przykład 15 – Integracja Struts 2 / Spring

W poprzednim przykładzie nie mieliśmy danych o zakresie Application, które byłyby wspólne dla wszystkich żądań wszystkich użytkowników. Tutaj przedstawiamy taki przykład. Aby go zrealizować, wykorzystujemy framework Spring [http://www.springsource.org/]. Spring jest narzędziem o ogromnej wartości. W tym przykładzie pokazujemy jedynie niewielką część jego możliwości. W kolejnym przykładzie wykorzystamy go w szerszym zakresie.

Celem tej aplikacji jest wyświetlenie danych z zakresu Application.

17.1. Projekt NetBeans

Projekt NetBeans tej aplikacji wygląda następująco:

  • w [1]:
    • [web.xml], który konfiguruje aplikację internetową, ulegnie zmianie w stosunku do poprzednich wersji
    • [applicationContext.xml] to plik konfiguracyjny Spring
  • na [2]: widok [Context.JSP], który będzie wyświetlał dane z zakresu aplikacji
  • w pliku [3]:
    • plik komunikatów [messages.properties]
    • główny plik konfiguracyjny Strutsa [struts.xml]. Będzie się różnił od plików stosowanych w poprzednich aplikacjach.
  • w [4]:
    • akcja Struts [Action1.java]
    • klasa [Config.java], która będzie przechowywać dane o zasięgu aplikacji
    • dodatkowy plik konfiguracyjny Struts o nazwie [example.xml]
  • w [5]: biblioteka Struts 2
  • w [6]:
    • archiwa niezbędne dla Springa [spring-core, spring-context, spring-beans, spring-web, commons-logging]
    • archiwum wtyczki Spring dla Struts 2. Umożliwia integrację Springa ze Struts 2 [struts2-spring-plugin]

W porównaniu z poprzednimi wersjami:

  • należy dodać archiwa do projektu
  • zmodyfikować pliki [web.xml] i [struts.xml]

17.2. Configuration

17.2.1. Plik [web.xml]

Plik [web.xml] ulega następującym zmianom:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>Exemple 14</display-name>
  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>struts2</filter-name>
    <URL-pattern>/*</URL-pattern>
  </filter-mapping>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

Modyfikacja ma miejsce w wierszach 12–14. Do aplikacji internetowej dodawany jest plik listener. Po uruchomieniu aplikacji internetowej zostanie utworzony egzemplarz klasy implementującej ten plik listener. Jest to klasa biblioteki Spring. Klasa ta będzie korzystać z pliku [WEB-INF/applicationContext.xml]. Wygląda on następująco:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
  
  <!-- konfiguracja beanów o zasięgu aplikacji -->
  <bean id="config" class="example.Config" >
    <property name="nbMaxUsers" value="10"/>
  </bean>

</beans>
  • Plik konfiguracyjny Springa zawiera tag główny <beans> (wiersze 2 i 11). Nazwę beans można by przetłumaczyć jako „obiekty”. Spring utworzy instancje wszystkich obiektów (bean) znalezionych w tym pliku konfiguracyjnym. Czyni to tylko raz, podczas uruchamiania Springa przy starcie aplikacji internetowej.
  • wiersze 7–9: definiują bean o nazwie config (id). Bean config jest powiązany z klasą (class) [example.Config]. Spring utworzy instancję tej klasy.
  • wiersz 8: definiuje właściwość klasy [example.Config]. Spring wywoła metodę [example.Config].setNbMaxUsers(10). W związku z tym w klasie musi istnieć metoda setNbMaxUsers. Wygląda ona następująco:

package example;

public class Config {

  private int nbMaxUsers;

  public int getNbMaxUsers() {
    return nbMaxUsers;
  }

  public void setNbMaxUsers(int nbMaxUsers) {
    this.nbMaxUsers = nbMaxUsers;
  }
  
}

Klasa ta definiuje jedynie pole nbMaxUsers wraz z polami get i set. Jeśli dobrze zrozumieliśmy powyższe wyjaśnienia, to przy uruchomieniu aplikacji internetowej tworzona jest instancja klasy [Config] z wartością 10 w polu nbMaxUsers. Zdefiniowaliśmy tylko jedno pole, ale to wystarczy do naszej demonstracji. Chcemy pokazać, że to pole, które mogłoby reprezentować maksymalną liczbę użytkowników, jest danymi o zasięgu Application, dostępnymi dla wszystkich akcji. Właśnie to pokażemy za pomocą akcji [Action1].

17.2.2. Plik [struts.xml]

Główny plik konfiguracyjny Struts wygląda następująco:


<?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" />
  <!-- integracja ze Springiem -->
  <constant name="struts.objectFactory.spring.autoWire" value="name" />

  <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">Action1</param>
        <param name="namespace">/example</param>
      </result>
    </action>
  </package>

</struts>

Jedynie wiersz 10 różni się od poprzednich wersji tego pliku. Definiuje on stałą Struts. Obiekty instancjonowane przez Spring mogą być wstrzykiwane do innych obiektów. To właśnie stanowi podstawę działania Spring. W tym przypadku odwołanie do obiektu typu [Config], utworzonego przez Spring, będzie mogło zostać wstrzyknięte do obiektów Struts. W tym miejscu do akcji wkracza wtyczka Spring dla Struts 2, która zapewnia integrację Spring z Struts.

Wiersz 10 wskazuje, że wstrzykiwanie obiektów Spring do obiektu Struts (autowire) nastąpi automatycznie na podstawie nazwy (value). Wróćmy do pliku konfiguracyjnego [applicationContext.xml]:


<!-- konfiguracja beanów o zasięgu aplikacji -->
  <bean id="config" class="example.Config" >
    <property name="nbMaxUsers" value="10"/>
  </bean>

To, co Struts 2 nazywa nazwą bean, jest w tym przypadku id. Zatem w tym przypadku instancja bean typu [Config] nosi nazwę config.

Akcja [Action1.java] wygląda następująco:


package example;

import com.opensymphony.xwork2.ActionSupport;
...
public class Action1 extends ActionSupport implements SessionAware, RequestAware, ParameterAware {

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

  @Override
  public String execute() {
  ....
    // żądanie
    request.put("nbMaxUsers", config.getNbMaxUsers());

    // wyświetlanie strony JSP
    return SUCCESS;
  }
...
  public Config getConfig() {
    return config;
  }

  public void setConfig(Config config) {
    this.config = config;
  }
}

Akcja [Action1] jest identyczna jak w poprzedniej aplikacji, z wyjątkiem następujących szczegółów:

  • wiersz 15: dodano pole config. Ponieważ nosi ono nazwę bean’a instancjonowanego przez Spring, pole to automatycznie otrzyma odwołanie do tego obiektu. W ten sposób akcja ma dostęp do konfiguracji aplikacji lub, bardziej ogólnie, do danych o zasięgu Application.
  • wiersz 31: Spring utworzy instancję pola config za pomocą swojej metody set. Metoda ta musi więc być obecna.
  • wiersz 21: akcja uzyskuje dostęp do informacji o zakresie Application. W zapytaniu podajemy maksymalną liczbę użytkowników nbMaxUsers, aby widok [Context.JSP] mógł ją wyświetlić.

17.2.3. Plik [example.xml]

Dodatkowy plik konfiguracyjny Struts jest identyczny jak w poprzedniej wersji:


<?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>

17.3. Widok [Context.JSP]

Widok [Context.JSP] wygląda następująco:


<%@ 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>
    nom : <s:property value="#parameters['nom']"/><br/>
    age : <s:property value="#parameters['age']"/>
    <h3><s:text name="Context.session"/></h3>
    compteur : <s:property value="#session['compteur']"/>
    <h3><s:text name="Context.request"/></h3>
    nbMaxUsers : <s:property value="#request['nbMaxUsers']"/>
  </body>
</html>

17.4. Testy

Przykładowe wykonanie wygląda następująco: