Spring MVC是个很是优秀的框架,其优秀之处继承自Spring自己依赖注入(Dependency Injection)的强大的模块化和可配置性,其设计到处透露着易用性、可复用性与易集成性。优良的设计模式遍布各处,使得其框架虽然学习曲线陡峭,但一旦掌握则欲罢不能。初学者并不须要过多了解框架的实现原理,随便搜一下如何使用“基于注解的controller”就能很快上手,而一些书籍诸如“spring in action”也给上手提供了很是优良的选择。java
网上的帖子多如牛毛,中文的快速上手,英文的深刻浅出。这样看来,Spring的学习简直是一个轻松愉快的过程。web
可是!!spring
关于Spring中session的使用,大部分资料都讳莫如深。也许这个问题太过容易推断出?大部分资料都没有包括我下面所将要陈述的内容。关于Spring中session的正确使用方法,这里甚至建议直接使用HttpSession。但这种方法显然违背了Spring “technology agnostic” (这个名词我理解意思就是不管你是在什么具体的应用中使用相似的控制逻辑,servlet、一个本地JVM程序或者其余,你的Controller均可以获得复用)的初衷。设计模式
因而我开始从庞大的网络资源和书籍中搜索关于Session的正确用法及Spring MVC处理Session的机制,其中讲得最深刻并且清楚的算是这一篇。从上文的内容,及我所查阅的好比官方文档这种资料中,我能够大约推断出几个要点:spring-mvc
1. Spring框架会在调用完Controller以后、渲染View以前检查Model的信息,并把@SessionAttributes()注释标明的属性加入session中网络
2. @ModelAttribute在声明Controller的参数的时候,能够用来代表此参数引用某个存在在Model中的对象,若是这个对象已经存在于Model中的话(Model能够在调用Controller以前就已经保存有数据,这应该不只仅由于HandlerInterceptor或者@ModelAttribute标记的方法已经显式的将一些对象加入到了Model对象中,也由于Spring会默认将一些对象加入到Model中,这一点很重要)。session
3. 若是Session中已经存在某个对象,那么能够直接使用ModelAttribute声明Controller的参数,在Controller中能够直接使用它。mvc
其中1很明确,我提到的那篇文章主要就在说明这一点。而从2和3咱们也许能够大胆地推出一个结论:app
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中是否已经注册了这个属性
Done,初学而已,随便谈谈,欢迎讨论。