8. 示例 06 – 会话
8.1. 会话的概念
当客户端浏览器首次连接到 Web 应用程序时,它会收到一个会话令牌——这是一串唯一的字符,客户端浏览器在向 Web 应用程序发送的每次新请求中都会将其一并发送回去。这使得 Web 应用程序能够识别该客户端浏览器。随后,Web 应用程序可以将数据与该会话令牌相关联。这些数据专属于单个客户端浏览器。因此,随着客户端浏览器发出请求,系统会逐步构建起数据存储。
![]() |
如上所述,每个用户(浏览器)都有自己的存储空间,称为会话。该存储空间由同一用户的所有请求共享。此外,还有一种更高层次的存储空间,称为应用程序存储空间。该存储空间由所有用户的所有请求共享,通常为只读模式。
8.2. NetBeans 项目
![]() |
[example-06] 项目是通过复制 [example-05] 项目创建的。我们将修改其中几个元素,以
- 以充分利用用户会话。
- 添加一个新操作 [Clear] [1] 来清空输入字段。
8.3. 配置
[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>
<!-- internationalization -->
<constant name="struts.custom.i18n.resources" value="messages" />
<!-- default package -->
<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>
<!-- equity 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 行定义了一个与类 [Delete] 相关联的新操作 [Delete]。该操作的响应是视图 [Input.jsp]。
8.4. [Confirm] 操作
其演变过程如下:
package actions;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
public class Confirmer extends ActionSupport implements SessionAware{
// model
private String nom;
// session
private Map<String, Object> session;
// getters and setters
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(){
// put the name in the session
session.put("nom",nom);
// navigation
return SUCCESS;
}
}
- 第 7 行:[Confirm] 类实现了 SessionAware 接口。该接口仅有一个方法,即第 25–27 行中的 setSession 方法。在调用 execute 方法之前,某个请求拦截器会通过 setSession 方法,将用户的会话以 Map<String, Object> 字典的形式注入(第 25 行)。 我们选择将此字典存储在第 12 行的 session 字段中。
- 第 30–34 行:Action 的 `execute` 方法。当该方法执行时,session 字段已由某个拦截器初始化,name 字段则由另一个拦截器初始化。我们使用这个会话字典来存储 name 字段。因此,name 将成为用户会话的一部分,并在用户的所有请求中可用。
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 行:我们在 `<s:textfield>` 标签中添加了一个 `value` 属性。该属性用于设置输入字段中显示的值。如果省略此属性,`value` 的默认值为 `name`。此处的属性值为一个 OGNL(对象图导航语言)表达式,格式为 `%{expression_to_evaluate}`。 此处的待评估表达式为 #attr['name']。系统将按以下顺序在当前操作、页面、请求、会话和应用程序中搜索 name 属性:当前操作、页面、请求、会话、应用程序。由于 [Confirm] 操作将 name 属性存储在会话中,因此该属性将在会话中被找到。如下请求所示:
![]() |
在 [1] 中,输入的名称为 ST。我们知道 [Confirm] 操作已将该名称存入会话。点击链接 [2] 将跳转至 URL [3]。此时显示 [Saisie.jsp] 视图。对于输入字段,属性 %{#attr['name']} 会从会话中检索该名称。
- 第 14 行:[清除] 按钮,该按钮会触发 [Clear] 操作的执行并显示 [Saisie.jsp] 视图
<action name="Effacer" class="actions.Effacer">
<result name="success">/vues/Saisie.jsp</result>
</action>
8.6. [删除] 操作
[删除] 操作的代码如下:
package actions;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
public class Effacer extends ActionSupport implements SessionAware{
// session
private Map<String, Object> session;
@Override
public String execute(){
// retrieve the name from the session
String nom=(String)session.get("nom");
// remove it from the session if necessary
if(nom!=null){
session.remove("nom");
}
// navigation
return SUCCESS;
}
@Override
public void setSession(Map<String, Object> map) {
this.session=map;
}
}
- 第 7 行:[Delete] 类实现了 [SessionAware] 接口,这与 [Confirm] 操作一样。
- 第 13 行:[Delete] 操作必须清除 [Input.jsp] 视图中 name 输入字段的内容。我们知道该视图是从会话中获取此 name 的。因此,我们必须从会话中移除该 name。这就是 execute 方法所做的工作。
让我们看看它是如何工作的:
![]() |
在[1]中,我们希望清空输入字段。我们点击[清空]按钮。
<s:submit key="saisie.effacer" action="Effacer"/>
[清除] 操作将被执行。在 [2] 中,我们注意到调用的 URL 是 [确认] 操作的 URL。这是由于表单中的 <s:form> 标签所致:
<s:form action="Confirmer">
这将导致表单提交至 [Confirm] 操作。当点击 [Clear] 按钮时,参数
action:Delete=Delete
被发送到 URL [/actions/Confirm.action]。Struts 使用此参数来处理由 [Delete] 操作提交的数据。该操作会删除会话名称。[Input.jsp] 页面是 [Delete] 操作的响应:
<action name="Effacer" class="actions.Effacer">
<result name="success">/vues/Saisie.jsp</result>
</action>
此操作会显示会话名称,随后显示一个空字符串 [3]。
我们编写了几个简单的示例,以介绍 Struts 2 的重要概念:
- 页面国际化
- 将提交的参数注入到 Action 字段中
- 会话的概念
- Action 与 View 之间的关系
既然我们已经掌握了这些概念,就可以着手处理更复杂的示例了。我们将首先介绍表单中可以使用的各种标签。



