8. 示例 06 – 会话
8.1. 会话的概念
当客户端浏览器首次连接到 Web 应用程序时,它会收到一个会话令牌,即一串唯一的字符,并在向 Web 应用程序发送每次新请求时将其返回。这使得 Web 应用程序能够识别该客户端浏览器。随后,Web 应用程序可以将数据与该会话令牌相关联。这些数据仅属于该唯一的客户端浏览器。 因此,随着客户端浏览器的请求不断进行,会形成一个数据缓存。
![]() |
如上所述,每个用户(浏览器)都有自己的存储空间,称为会话。该存储空间由同一用户的所有请求共享。此外,还存在一个更高层次的存储空间,称为应用程序存储。该存储空间由所有用户的所有请求共享,通常为只读模式。
8.2. NetBeans 项目
![]() |
项目 [exemple-06] 是通过复制项目 [exemple-05] 获得的。我们将修改一些内容,以便
- 利用用户的会话。
- 添加新操作 [Effacer] [1] 以清空输入字段。
8.3. Configuration
文件 [struts.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>
<!-- 国际化 -->
<constant name="struts.custom.i18n.resources" value="messages" />
<!-- 默认包 -->
<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>
<!-- 操作包 -->
<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>
第 27-29 行定义了一个新的操作 [Effacer],该操作关联到类 [Effacer]。此操作的响应是视图 [Saisie.jsp]。
8.4. 操作 [Confirmer]
其演变如下:
package actions;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
public class Confirmer extends ActionSupport implements SessionAware{
// 模型
private String nom;
// 会话
private Map<String, Object> session;
// 获取器和设置器
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(){
// 将名称放入会话中
session.put("nom",nom);
// 导航
return SUCCESS;
}
}
- 第 7 行:类 [Confirmer] 实现了接口 SessionAware。该接口仅有一个方法,即第 25-27 行中的方法 setSession。 在调用方法 execute 之前,请求拦截器之一将通过方法 setSession,以 Map<String, Object> 字典的形式注入用户会话(第 25 行)。 我们选择将该字典存储在第 12 行的 session 字段中。
- 第 30-34 行:操作的 execute 方法。 当该方法执行时,字段 session 已被其中一个拦截器初始化,而字段 nom 则被另一个拦截器初始化。 我们使用该字典 session 来存储字段 nom。这样,该名称将成为用户内存的一部分,并可供用户的所有请求使用。
8.5. 视图 [Confirmation.jsp] 和 [Saisie.jsp]
视图 [Confirmation.jsp] 保持不变。视图 [Saisie.jsp] 的变更如下:
<%@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>
- 第 12 行:我们在 value 标签中引入了一个 value 属性。该属性用于设定在输入框中显示的值。 若未设置此属性,则 value = name。此处,属性的值是一个 OGNL(对象图导航语言)表达式,形式为 %{expression_à_évaluer} 形式的 OGNL 表达式。此处待求值的表达式为 #attr['nom']。系统将按当前操作、页面、请求、会话、应用程序的顺序查找 nom 属性。 由于操作 [Confirmer] 将属性 nom 放入会话中,因此该属性将在会话中被找到。下述请求即说明了这一点:
![]() |
在 [1] 操作中,输入的名称是 ST。 我们知道操作 [Confirmer] 将该名称放入了会话中。链接 [2] 引导我们访问 URL [3]。 此时显示的是视图 [Saisie.jsp]。对于输入字段,属性 %{#attr['nom']} 可用于从会话中检索该名称。
- 第 14 行:按钮 [Effacer] 将触发操作 [Effacer] 的执行,并显示视图 [Saisie.jsp]
<action name="Effacer" class="actions.Effacer">
<result name="success">/vues/Saisie.jsp</result>
</action>
8.6. 操作 [Effacer]
操作 [Effacer] 的代码如下:
package actions;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
public class Effacer extends ActionSupport implements SessionAware{
// 会话
private Map<String, Object> session;
@Override
public String execute(){
// 从会话中获取用户名
String nom=(String)session.get("nom");
// 如有需要,将其从会话中移除
if(nom!=null){
session.remove("nom");
}
// 导航
return SUCCESS;
}
@Override
public void setSession(Map<String, Object> map) {
this.session=map;
}
}
- 第 7 行:类 [Effacer] 实现了接口 [SessionAware],与操作 [Confirmer] 一样。
- 第 13 行:操作 [Effacer] 必须清除视图 [Saisie.jsp] 中名称输入字段的内容。 我们知道该视图会从会话中获取该名称。因此,必须从会话中移除该名称。这就是方法 execute 所做的工作。
让我们看看效果如何:
![]() |
在 [1] 中,我们希望清除该输入字段。点击按钮 [Effacer]。
<s:submit key="saisie.effacer" action="Effacer"/>
此时将执行操作 [Effacer]。 在 [2] 中,我们注意到调用的 URL 是操作 [Confirmer] 的 URL。这是由于表单中的 <s:form> 标签所致:
<s:form action="Confirmer">
该标签导致表单被提交至操作 [Confirmer]。点击按钮 [Effacer] 时,参数
action:Effacer=Effacer
被提交至 URL [/actions/Confirmer.action]。Struts 使用该参数将数据处理交由操作 [Effacer] 处理。该操作会移除会话名称。 页面 [Saisie.jsp] 是动作 [Effacer] 的响应:
<action name="Effacer" class="actions.Effacer">
<result name="success">/vues/Saisie.jsp</result>
</action>
该页面原本应显示会话名称,但此时却显示了一个空字符串 [3]。
我们编写了几个简单的示例,以介绍 Struts 2 的重要概念:
- 页面的国际化
- 将表单提交参数注入到操作字段中
- 会话的概念
- Action与View之间的关联
掌握了这些概念后,我们现在可以着手处理更复杂的示例了。首先,我们将介绍表单中可用的各种标签。



