Skip to content

16. 示例 13 - 操作的上下文

本应用程序旨在演示操作可以访问:

  • 请求参数
  • 请求属性
  • 用户会话属性

Image

16.1. NetBeans 项目

NetBeans 项目如下:

  • 在 [1] 中,视图 [Context.jsp]
  • 在 [2] 中,包含操作 [Action1.java] 以及 Struts 配置文件 [example.xml]

16.2. 配置

项目配置在 [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>
  • 第 8 行:对 URL [/example/Action1] 的请求将触发 [example.Action] 类的实例化。由于未指定方法,将执行 execute 方法。
  • 第 9 行:仅接受一个键。键“success”将导致显示 [Context.jsp] 视图。

处理请求的简化架构如下:

该请求将由 Web 应用程序的两个组件进行处理:操作 [Action1] [1] 和视图 [Context.jsp] [2]。这两个组件可以访问不同类型的数据:

  • 应用程序范围数据 [3],即所有用户发出的所有请求均可访问的数据。该数据几乎总是只读的。此类数据通常包含应用程序的初始配置。在此,[Action1] 和 [Context.jsp] 均可访问此数据。
  • 会话范围数据 [4],即同一用户所有请求均可访问的数据。该数据为可读写数据。在此,[Action1] 将以读写模式使用会话,而 [Context.jsp] 将以只读模式使用。
  • 请求作用域数据 [5],所有处理该请求的组件均可访问。在此示例中,[Action1] 将数据存储于此内存中,而 [Context.jsp] 将从中检索数据。请求作用域数据允许组件 N 向组件 N+1 传递信息。
  • 请求参数 [6] 由客户端发送。处理请求的组件以只读模式使用这些参数。

16.3. [Action1] 操作

[Action1]类的代码如下:


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;
  }
}
  • 第 10 行:该类实现了以下接口
  • SessionAware:用于访问会话属性字典(第 16 行)。该接口仅有一个方法,即第 46 行中的方法。
  • RequestAware:用于访问请求属性字典(第 17 行)。该接口仅有一个方法,即第 51 行中的方法。
  • ParameterAware:用于访问请求参数字典(第 18 行)。请注意,每个键(参数名)对应一个值数组。这是为了处理提交多个值的输入字段,例如多选列表。ParameterAware 接口仅有一个方法,即第 56 行中的方法。
  • 第 21 行:execute 方法,当请求 [Action1] 操作时执行。此时,拦截器已完成其工作:
  • setParameters 方法(第 56 行)已被调用,第 18 行的参数字典中已包含所有请求参数。
  • setSession 方法(第 46 行)已被调用,第 16 行的 session 字典中包含所有会话属性。
  • 已调用 setRequest 方法(第 51 行),第 17 行的 request 字典中包含所有请求属性。
  • 第 31–38 行:将与 `compteur` 键关联的值写入会话
  • 第 32–34 行:在会话中查找 `compteur` 键。如果未找到,则将其添加并赋予整数值 0。
  • 第 35–37 行:在会话中查找 `counter` 键,将其值递增,然后将该键放回会话中。
  • 第 38 行:显示与 `counter` 键关联的值。由于每次对 [Action1] 操作发起请求时都会执行递增操作,因此随着请求的增加,计数器值应随之递增。
  • 第 40 行:将键为 `info1`、值为 `information1` 的属性插入请求属性字典。请求属性与请求参数不同。参数由 Web 应用程序客户端发送。而请求属性则用于处理请求的 Web 应用程序各组件之间的通信。因此,执行 [Action1] 之后,将显示 [Context.jsp] 视图。 我们将看到它能够检索请求属性。
  • 第 42 行:execute 方法返回“success”键。

16.4. 消息文件

[messages.properties] 文件内容如下:


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

[Context.jsp] 视图负责显示:

  • 某些请求参数
  • 会话中 counter 键的值
  • 请求中 info1 键的值

其代码如下:


<%@ 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>
  • 第 12–14 行:显示与“name”参数关联的所有值
  • 第 15–17 行:显示与 'first_name' 参数关联的所有值
  • 第 18–20 行:显示与 age 参数关联的所有值
  • 第 22 行:显示会话中与 counter 键关联的值
  • 第 24 行:显示查询中与 info1 键关联的值

16.6. 测试

  • 在 [1] 中,调用 Action1 时未传入参数
  • 在 [2] 中,[Context.jsp] 未找到任何参数
  • 在 [3] 中,[Context.jsp] 在会话中找到了 counter
  • 在 [4] 中,[Context.jsp] 在请求中找到了 info1

让我们再进行一次测试:

  • 在 [1] 中,通过参数调用了 Action1
  • 在[2]中,[Context.jsp]显示了这些参数
  • 在 [3] 中,[Context.jsp] 在会话中找到了键 "compteur"。计数器确实增加了 1,这表明数据在两次请求之间成功保留了下来。
  • 在 [4] 中,[Context.jsp] 在请求中找到了 "info1"

回顾一下,[Action1.execute] 方法向 Web 服务器控制台写入了内容。以下是一个示例:

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

16.7. 结论

请牢记以下几点:

  • 为了存储所有用户所有请求中共享的信息,我们将使用应用程序的内存。稍后我们将展示一个示例。
  • 若要存储供同一用户所有请求共享的信息,我们将使用该用户的会话。
  • 若要存储供处理该请求的所有组件共享的信息,我们将使用请求作用域。