Spring:@SessionAttributes vs HttpSession

时间:2014-11-28 15:30:06

标签: spring spring-mvc

@SessionAttributes与HttpSession之间的区别是什么? 这两个中的哪一个在会话中保留更长时间的对象? 在哪些情况下,我必须使用一个,在哪种情况下使用另一个?

由于

2 个答案:

答案 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后,视图呈现如下

enter image description here

因此模型变量在请求范围内可用,sessionattribute在请求和会话范围中都可用,而“普通”会话属性仅在会话范围内可用

在下一个请求/sessionattr/afterinit上,视图呈现如下

enter image description here

因此仅模型变量消失了,而@SessionAttribute模型属性从会话推送到模型并在请求之间保持不变。下一步将针对第二个控制器/nosessionattr/init,视图将呈现如下

enter image description here

现在@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>