Spring MVC中Session的正确用法<转>

Spring MVC是个非常优秀的框架,其优秀之处继承自Spring本身依赖注入(Dependency Injection)的强大的模块化和可配置性,其设计处处透露着易用性、可复用性与易集成性。优良的设计模式遍及各处,使得其框架虽然学习曲线陡峭,但 一旦掌握则欲罢不能。初学者并不需要过多了解框架的实现原理,随便搜一下如何使用“基于注解的controller”就能很快上手,而一些书籍诸如 “spring in action”也给上手提供了非常优良的选择。

网上的帖子多如牛毛,中文的快速上手,英文的深入浅出。这样看来,Spring的学习简直是一个轻松愉快的过程。

但是!!

关于Spring中session的使用,大部分资料都讳莫如深。也许这个问题太过容易推断出?大部分资料都没有包括我下面所将要陈述的内容。关于Spring中session的正确使用方法,这里甚至建议直接使用HttpSession。但这种方法显然违背了Spring “technology agnostic” (这个名词我理解意思就是无论你是在什么具体的应用中使用类似的控制逻辑,servlet、一个本地JVM程序或者其他,你的Controller都可以得到复用)的初衷。

于是我开始从庞大的网络资源和书籍中搜索关于Session的正确用法及Spring MVC处理Session的机制,其中讲得最深入而且清楚的算是这一篇。从上文的内容,及我所查阅的比如官方文档这种资料中,我可以大约推断出几个要点:

1. Spring框架会在调用完Controller之后、渲染View之前检查Model的信息,并把@SessionAttributes()注释标明的属性加入session中

2. @ModelAttribute在声明Controller的参数的时候,可以用来表明此参数引用某个存在在Model中的对 象,如果这个对象已经存在于Model中的话(Model可以在调用Controller之前就已经保存有数据,这应该不仅仅因为 HandlerInterceptor或者@ModelAttribute标记的方法已经显式的将一些对象加入到了Model对象中,也因为Spring会默认将一些对象加入到Model中,这一点很重要)。

3. 如果Session中已经存在某个对象,那么可以直接使用ModelAttribute声明Controller的参数,在Controller中可以直接使用它。

其中1很明确,我提到的那篇文章主要就在说明这一点。而从2和3我们也许可以大胆地推出一个结论:

Spring会在调用Controller之前将session中的对象填入Model中

因为想从2得到3,这个结论就显得比较自然。那么事实上是不是如此呢?可以做一个小实验。仿效我所引用的那篇文章,我写了如下代码:

@Controller
@RequestMapping("/user")
@SessionAttributes("userId")
public class UserController {

    @RequestMapping(value="/login", method=GET)
    public String login (
            int id, Model model, HttpServletRequest request, HttpSession session) {

        model.addAttribute("userId", id);

        System.out.println("");
        System.out.println("");
        System.out.println("inside login");

        System.out.println("");
        System.out.println("--- Model data ---");
        Map modelMap = model.asMap();
        for (Object modelKey : modelMap.keySet()) {
            Object modelValue = modelMap.get(modelKey);
            System.out.println(modelKey + " -- " + modelValue);
        }

        System.out.println("");
        System.out.println("*** Session data ***");
        Enumeration<String> e = session.getAttributeNames();
        while (e.hasMoreElements()) {
            String s = e.nextElement();
            System.out.println(s + " == " + session.getAttribute(s));
        }

        return "/test";
    }

    @RequestMapping(value="/check", method=GET)
    public String check (
            Model model, HttpServletRequest request, HttpSession session) {

        System.out.println("");
        System.out.println("");
        System.out.println("inside check");

        System.out.println("");
        System.out.println("--- Model data ---");
        Map modelMap = model.asMap();
        for (Object modelKey : modelMap.keySet()) {
            Object modelValue = modelMap.get(modelKey);
            System.out.println(modelKey + " -- " + modelValue);
        }

        System.out.println("");
        System.out.println("*** Session data ***");
        Enumeration<String> e = session.getAttributeNames();
        while (e.hasMoreElements()) {
            String s = e.nextElement();
            System.out.println(s + " == " + session.getAttribute(s));
        }

        return "/test";
    }
}

而test.jsp的作用就是把Session中的对象打印出来。

调用的顺序是,在首先保证Session为空的情况下,先后输入以下链接:

http://localhost:8080/XX/user/check

http://localhost:8080/XX/user/login?id=1

http://localhost:8080/XX/user/check

页面的显示结果分别为:

1

2

3

而Tomcat的输出结果为:

inside check

--- Model data ---

*** Session data ***

inside login

--- Model data ---
userId -- 1

*** Session data ***

inside check

--- Model data ---
userId -- 1

*** Session data ***
userId == 1

结果如我所料。首先Session中并没有userId属性,在某个Controller加入了它之后,随后的Controller中的Model
会自动加入已经存在于Session的对象。虽然确实有很多很多帖子提到了@SessionAttributes并不是使用session的正确方法,但
是如实验所得,使用它使得最终属性都加入到了HttpSession对象中,夫复何求?(这里也许需要更多的讨论,我倒希望能有什么更值得信服的说法让我
乖乖用回HttpSession)。那么,在Spring中使用Session的一个相对比较“technology agnostic”的方法就是:

1 使用@SessionAttributes提示框架哪些属性需要存在Session中

2 在某些Controller中将这些属性加入到Model中

3 在另外一些Controler中直接使用这些属性

4 在其他Controller中判断Model中是否存在相应属性,以确定Session中是否已经注册了这个属性

时间: 2024-10-11 12:50:07

Spring MVC中Session的正确用法<转>的相关文章

Spring mvc中@RequestMapping 6个基本用法小结

小结下spring mvc中的@RequestMapping的用法. 1)最基本的,方法级别上应用,例如: Java代码 @RequestMapping(value="/departments") public String simplePattern(){ System.out.println("simplePattern method was called"); return "someResult"; } 则访问http://localho

Spring mvc中@RequestMapping 6个基本用法小结(转载)

小结下spring mvc中的@RequestMapping的用法. 1)最基本的,方法级别上应用,例如: Java代码   @RequestMapping(value="/departments") public String simplePattern(){ System.out.println("simplePattern method was called"); return "someResult"; } 则访问http://local

(转载)Spring mvc中@RequestMapping 6个基本用法小结

小结下spring mvc中的@RequestMapping的用法. 1)最基本的,方法级别上应用,例如: Java代码 @RequestMapping(value="/departments") public String simplePattern(){ System.out.println("simplePattern method was called"); return "someResult"; } 则访问http://localho

Spring Session在Spring MVC中的使用.md

Web项目会通过Session进行会话保持,Session是保存在服务器内存中: 现在为了提高站点的性能和稳定性,将Web项目发布到多个服务器,通过代理如Nginx或F5做负载均衡: 由于负载均衡正常配置,会对客户端的请求随机转发到某一个服务器,这会导致Session丢失: 解决方案:一种是可将代理如Nginx或F5配置为高可用,即用户访问时,在同一会话期间内,只往一台服务器转发:另一种是引入Spring Session,对Session进行持久化.统一管理: Spring Session对Se

Spring MVC中基于注解的 Controller

终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响应请求.实际上,ControllerClassNameHandlerMapping, MultiActionController 和选择恰当的 methodNameResolver(如 InternalPathMethodNameResolver) 就已经可以在很大程度上帮助我们省去不少的 XML 配置,谁让

Spring MVC 中采用注解方式 Action中跳转到另一个Action的写法

Spring MVC 中采用注解方式 Action中跳转到另一个Action的写法 在Action中方法的返回值都是字符串行,一般情况是返回某个JSP,如: return "xx":意思是返回到某个JSP页面上 如果想在此Action中跳转到另一个Action中怎样做呢? return "redirect://.do?" 例如: @RequestMapping(params = "action=delete") public String del

ExtJS4.2.1与Spring MVC实现Session超时控制

如果你的项目使用ExtJS作为表现层,你会发现,SESSION超时控制将是一个问题. 本文将就自己的经验,来解决这一问题,当然,解决问题并非只有一种方法,我只是提出我的方法. 首先,做超时控制,必需使用过滤器,而我们既然使用了Spring MVC,那就用拦截器取代吧,写一个拦截器,用来拦截用户请求,当然,这个拦截器还需要可以配置哪些请求是不需要拦截的. /** * */ package net.bioslink.business.intercepter; import java.io.Print

Spring MVC 中的基于注解的 Controller【转】

原文地址:http://my.oschina.net/abian/blog/128028 终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响应请求.实际上,ControllerClassNameHandlerMapping, MultiActionController 和选择恰当的 methodNameResolver(如 InternalPathMetho

Spring MVC 中的基于注解的 Controller(转载)

  终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响应请求.实际上,ControllerClassNameHandlerMapping, MultiActionController 和选择恰当的 methodNameResolver(如 InternalPathMethodNameResolver) 就已经可以在很大程度上帮助我们省去不少的 XML 配置,