@SessionAttributes与HttpSession之间的区别是什么? 这两个中的哪一个在会话中保留更长时间的对象? 在哪些情况下,我必须使用一个,在哪种情况下使用另一个?
由于
答案 0 :(得分:13)
@SessionAttributes启用请求之间的持久模型属性会话,并且每个hanlder都是特定的。目的是提供一个结构,该结构将朝着实现会话范围迈出一步(比会话更短,比请求更长)。在blog中解释了对会话范围的需求以及@SessionAttributes无法完全提供的原因。
它可以自动存储匹配的模型属性(匹配基于名称)。默认存储是HttpSession,但也可以以不同方式配置。文档说
使用此注释指示的会话属性对应于a 特定处理程序的模型属性,透明地存储在其中 会话会话。这些属性将被删除一次 handler表示会话会话已完成。
但是这个位这些属性将在处理程序指示其会话会话完成后被删除。不会自动发生,并且由开发人员通过使用<来指示退出会话 SessionStatus 实例上的em> setComplete 。否则,models属性将保持在会话中,通常是不希望的副作用。
理解差异的最简单方法是观察模型变量的范围和值,使用@SessionAttribute支持的模型变量和“普通”HttpSession变量。
看一下两个简单的控制器
@Controller
@SessionAttributes("modelAndSession")
@RequestMapping("/sessionattr")
public class FirstController {
protected static final String NEXT_VIEW = "next";
@RequestMapping("/init")
public String handlingMethod1( Model model, HttpSession session) {
model.addAttribute(NEXT_VIEW, "/sessionattr/afterinit");
session.setAttribute("session", "TRUE");
model.addAttribute("modelAndSession", "TRUE");
model.addAttribute("model", "TRUE");
return "index";
}
@RequestMapping("/afterinit")
public String handlingMethod2(SessionStatus status, Model model) {
model.addAttribute(NEXT_VIEW, "/nosessionattr/init");
//status.setComplete();
return "index";
}
}
第二个控制器
@Controller
@RequestMapping("/nosessionattr")
public class SecondController {
protected static final String NEXT_VIEW = "next";
@RequestMapping("/init")
public String handlingMethod3(Model model) {
model.addAttribute(NEXT_VIEW, "/sessionattr/init");
return "index";
}
}
以及将触发流程的视图
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<a href="${next}">Next step ${next}</a>
<hr/>
<table>
<thead>
<th>key</th> <th>Request scope</th> <th>Session scope</th>
</thead>
<tr>
<td>model</td> <td>${requestScope.model}</td> <td>${sessionScope.model}</td>
</tr>
<tr>
<td>model and session</td> <td>${requestScope.modelAndSession}</td> <td>${sessionScope.modelAndSession}</td>
</tr>
<tr>
<td>session</td> <td>${requestScope.session}</td> <td>${sessionScope.session}</td>
</tr>
</table>
初始请求/sessionattr/init
后,视图呈现如下
因此模型变量在请求范围内可用,sessionattribute在请求和会话范围中都可用,而“普通”会话属性仅在会话范围内可用
在下一个请求/sessionattr/afterinit
上,视图呈现如下
因此仅模型变量消失了,而@SessionAttribute模型属性从会话推送到模型并在请求之间保持不变。下一步将针对第二个控制器/nosessionattr/init
,视图将呈现如下
现在@SessionAttribute模型对象已从模型中消失,但由于status.setComplete未明确调用,因此它作为正常变量保留在会话中
这是一个特别令人困惑的场景,因为很多人希望@SessionAttribute模型对象在切换处理程序后应该消失,但是除非明确清除,否则它仍然在会话中。随意复制片段并进一步调查混淆你的组合
答案 1 :(得分:0)
奴隶大师已经回答了这些问题。关于@SessionAttributes和HttpSession之间的区别,我想补充一点
Altough @SessionAttributes保存在HTTPSession中 - 如果调用HTTPSesssion#invalidate()它们不会消失 将会有一个新会话,但标记为@SessionAttributes的变量将保留并复制到新会话中。
因此,如果需要使会话无效,或者只是在会话范围内不再需要@SessionAttributes本身,那么还要将SessionStatus接口注入适当的处理程序方法,然后调用SessionStatus#setComplete()< / p>
我还将Master Slave提供的JSP文件重写为Thymeleaf模板。可以使用相同的控制器类。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<a href="../sessionattr/init" data-th-href="@{${next}}">Next step [[${next}]]</a>
<hr>
<table>
<thead>
<tr>
<th>key</th>
<th>Request Scope</th>
<th>Session Scope</th>
</tr>
</thead>
<tbody>
<tr>
<td>model</td>
<td data-th-text="${#request.getAttribute('model')?: 'false'}">N/A</td>
<td data-th-text="${#session.getAttribute('model')?: 'false'}">N/A</td>
</tr>
<tr>
<td>modelAndSession</td>
<td data-th-text="${#request.getAttribute('modelAndSession')?: 'false'}">N/A</td>
<td data-th-text="${#session.getAttribute('modelAndSession')?: 'false'}">N/A</td>
</tr>
<tr>
<td>session</td>
<td data-th-text="${#request.getAttribute('session')}?: 'false'">N/A</td>
<td data-th-text="${#session.getAttribute('session')}?: 'false'">N/A</td>
</tr>
</tbody>
</table>
</body>
</html>