16. 示例 13 - 操作的上下文
本应用程序旨在演示操作可以访问:
- 请求参数
- 请求属性
- 用户会话属性

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 服务器控制台写入了内容。以下是一个示例:
16.7. 结论
请牢记以下几点:
- 为了存储所有用户所有请求中共享的信息,我们将使用应用程序的内存。稍后我们将展示一个示例。
- 若要存储供同一用户所有请求共享的信息,我们将使用该用户的会话。
- 若要存储供处理该请求的所有组件共享的信息,我们将使用请求作用域。



