Skip to content

17. 示例 15 – Struts 2 与 Spring 的集成

在前面的示例中,我们没有所有用户的所有请求共享的范围数据。这里我们展示一个示例。为了实现这一点,我们使用 Spring 框架。Spring 是一个非常有价值的工具。 本示例仅展示了其中极小的一部分。后续示例将更深入地运用它。

本应用程序的目的是显示 Application 范围内的数据。

17.1. NetBeans 项目

该应用程序的 NetBeans 项目如下:

  • 在 [1] 中:
  • 用于配置Web应用程序的[web.xml]文件将与之前版本相比有所更新
  • [applicationContext.xml] 是 Spring 的配置文件
  • 在 [2] 中:视图 [Context.jsp] 将显示应用范围内的数据
  • 在 [3] 中:
  • 消息文件 [messages.properties]
  • Struts的主配置文件 [struts.xml]。与之前的应用程序相比将有所变化。
  • 在 [4] 中:
  • Struts 操作 [Action1.java]
  • [Config.java] 类,用于存储应用程序作用域数据
  • Struts 辅助配置文件 [example.xml]
  • 在 [5] 中:Struts 2 库
  • 在 [6] 中:
  • Spring所需的压缩包 [spring-core, spring-context, spring-beans, spring-web, commons-logging]
  • Struts 2 的 Spring 插件归档。支持 Spring 与 Struts 2 的集成 [struts2-spring-plugin]

与之前版本相比:

  • 需向项目中添加压缩包
  • 修改文件 [web.xml] 和 [struts.xml]

17.2. Configuration

17.2.1. 文件 [web.xml]

文件 [web.xml] 的变更如下:


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

修改发生在第12至14行。一个名为listener的文件被添加到Web应用程序中。当Web应用程序启动时,实现该listener的类将被实例化。 这是一个 Spring 类。该类将调用文件 [WEB-INF/applicationContext.xml]。该文件内容如下:


<?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">
  
  <!-- 应用程序范围 Bean 的配置 -->
  <bean id="config" class="example.Config" >
    <property name="nbMaxUsers" value="10"/>
  </bean>

</beans>
  • Spring配置文件的根标签为<beans>(第2行和第11行)。 我们可以将 beans 理解为“对象”。Spring 会实例化该配置文件中找到的所有对象(bean)。这一操作仅在 Web 应用程序启动时 Spring 加载 listener 时执行一次。
  • 第7-9行:定义了一个名为config(ID)的Bean。该配置Bean与类(class)[example.Config]相关联。Spring将实例化该类。
  • 第 8 行:定义了类 [example.Config] 的一个属性。Spring 将调用方法 [example.Config].setNbMaxUsers(10)。 因此,该类中必须存在 setNbMaxUsers 方法。该方法如下:

package example;

public class Config {

  private int nbMaxUsers;

  public int getNbMaxUsers() {
    return nbMaxUsers;
  }

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

该类仅定义了一个字段 nbMaxUsers,以及其关联的 getset。 如果大家跟上了之前的说明,那么在 Web 应用程序启动时,会实例化一个 [Config] 类的实例,其 nbMaxUsers 字段的值为 10。 虽然我们只定义了一个字段,但这已足以满足演示需求。我们希望说明,该字段(可能代表最大用户数)属于 Application 作用域,所有操作均可访问该数据。我们将通过操作 [Action1] 来演示这一点。

17.2.2. 文件 [struts.xml]

Struts 的主配置文件如下:


<?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" />
  <!-- Spring 集成 -->
  <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>

仅第 10 行与该文件的前几个版本不同。它定义了一个 Struts 常量。 由 Spring 实例化的对象可以注入到其他对象中。这正是 Spring 的核心原理。在此,Spring 创建的 [Config] 类型对象的引用将被注入到 Struts 对象中。这就是 Struts 2 的 Spring 插件发挥作用的地方,它确保了 Spring 与 Struts 的集成。

第 10 行表明,Spring 对象将通过名称(value)自动注入到 Struts 对象(autowire)中。让我们回到配置文件 [applicationContext.xml]:


<!-- 应用程序作用域 Bean 的配置 -->
  <bean id="config" class="example.Config" >
    <property name="nbMaxUsers" value="10"/>
  </bean>

Struts 2 所称的 Bean 名称,在此实际上是 id。因此,此处实例化的 [Config] 类型的 Bean 名称为 config

[Action1.java] 动作如下:


package example;

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

  // 无参构造器
  public Action1() {
  }
  
  // 会话、请求、参数
  private Map<String, Object> session;
  private Map<String, Object> request;
  private Map<String, String[]> parameters;
  private Config config;

  @Override
  public String execute() {
  ....
    // 请求
    request.put("nbMaxUsers", config.getNbMaxUsers());

    // 页面显示 JSP
    return SUCCESS;
  }
...
  public Config getConfig() {
    return config;
  }

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

操作 [Action1] 与前一个应用程序中的操作完全相同,仅存在以下细微差异:

  • 第 15 行:新增了一个名为 config 的字段。由于该字段名称与 Spring 实例化的 Bean 名称一致,因此该字段将自动获得该对象的引用。这样,该操作即可访问应用程序配置,或者更普遍地说,访问作用域为 Application 的数据。
  • 第 31 行:Spring 将通过其 set 方法实例化 config 字段。因此该方法必须存在。
  • 第 21 行:该操作访问作用域 Application 中的信息。我们将最大用户数 nbMaxUsers 放入查询中,以便视图 [Context.jsp] 能够显示该数据。

17.2.3. 文件 [example.xml]

Struts 的辅助配置文件与上一版本相同:


<?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. 视图 [Context.jsp]

视图 [Context.jsp] 如下所示:


<%@ 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. 测试

一个执行示例如下:

Image