知识大全 Spring2.5访问Session属性的四种策略

Posted 属性

篇首语:登山则情满于山,观海则意溢于海。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Spring2.5访问Session属性的四种策略相关的知识,希望对你有一定的参考价值。

Spring2.5访问Session属性的四种策略  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  WEB 应用通常会引入 Session 用来在服务端和客户端之间保存一系列动作/消息的状态 比如网上购物维护 user 登录信息直到 user 退出 在 user 登录后 Session 周期里有很多 action 都需要从 Session 中得到 user 再验证身份权限 或者进行其他的操作 这其中就会涉及到程序去访问 Session属性的问题 在java中 Servlet 规范提供了 HttpSession对象来满足这种需求 开发人员可以从 HttpServletRquest对象得到 HttpSession 再从HttpSession中得到状态信息

  还是回到购物车的例子 假设在 controller 某个方法(本文简称为action)中我们要从HttpSession中取到user对象 如果基于Servlet 标准的代码会是这样的

  Java代码

  public void doGet(HttpServletRequest req HttpServletResponse resp) throws ServletException IOException

  User user = (User)req getSession() getAttribute( currentUser );

  //

  

  这样的代码在传统的Servlet程序中是很常见的 因为使用了 Servlet API 从而对 Servlet API产生依赖 这样如果我们要测试 action 我们就必须针对 HttpServletRequest HttpServletResponse 和 HttpSession类提供 mock 或者 stub 实现 当然现在已经有很多开源的 Servlet 测试框架帮助我们减轻这个痛苦 包括 Spring 就自带了对了这些类的 stub 实现 但那还是太冗繁琐碎了 那有没有比较好的办法来让我们的 controller 更 POJO 让我们的 action 脱离 Servlet API 依赖 更有益于测试和复用呢?我们来看看在 Spring 中访问 Session 属性的几种解决方案 并将在本博的后续文章继续探究解决方案选择背后的深层含义

  (一)通过方法参数传入HttpServletRequest对象或者HttpSession对象

  笔者的前一篇文章已经简单介绍了Spring 的annotation使得 controller 摆脱了 Servlet API 对方法参数的限制 这里就不赘述了 有兴趣的同学可以参考<a >这里</a> Spring对annotationed的 action 的参数提供自动绑定支持的参数类型包括 Servlet API 里面的 Request/Response/HttpSession(包含Request Response在Servlet API 中声明的具体子类) 于是开发人员可以通过在 action 参数中声明 Request 对象或者 HttpSession 对象 来让容器注入相应的对象

  action 的代码如下

  Java代码

  @RequestMapping

  public void hello(HttpSession session)

  User user = (User)session getAttribute( currentUser );

  //

  

  优点

   程序中直接得到底层的 Request/HttpSession 对象 直接使用 Servlet API 规范中定义的方法操作这些对象中的属性 直接而简单

   action 需要访问哪些具体的 Session 属性 是由自己控制的 真正精确到 Session 中的每个特定属性

  不足

   程序对 Servlet API 产生依赖 虽然 controller 类已经不需要从 HttpServlet 继承 但仍需要 Servlet API 才能完成编译运行 乃至测试

   暴露了底层 Servlet API 暴露了很多并不需要的底层方法和类 开发人员容易滥用这些 API

  (二)通过定制拦截器(Interceptor)在controller类级别注入需要的User对象

  Interceptor 是 Spring 提供的扩展点之一 SpringMVC 会在 handle 某个 request 前后调用在配置中定义的 Interceptor 完成一些切面的工作 比如验证用户权限 处理分发等 类似于 AOP 那么 我们可以提取这样一个 横切点 在 SpringMVC 调用 action 前 在 Interceptor 的 preHandle 方法中给 controller 注入 User 成员变量 使之具有当前登录的 User 对象

  此外还需要给这些特定 controller 声明一类 interface 比如 IUserAware 这样开发人员就可以只针对这些需要注入 User 对象的 controller 进行注入增强

  IUserAware 的代码

  Java代码

  public interface IUserAware

  public void setUser();

  

  controller 的代码

  Java代码

  @Controller

  public GreetingController implements IUserAware

  private User user;

  public void setUser(User user)

  this user = user;

  

  @RequestMapping

  public void hello()

  //user sayHello();

  

  //

  

  Interceptor 的代码

  Java代码

  public class UserInjectInterceptor extends HandlerInterceptorAdapter

  @Override

  public boolean preHandle(HttpServletRequest ServletRequest HttpServletResponse ServletResponse Object handler) throws Exception

  if (handler isAssignableFrom(IUserAware))

  User user = (User)() getAttribute( currentUser );

  IUserAware userAware = (IUserAware) handler;

  userAware setUser(user);

  

  return super preHandle(ServletRequest ServletResponse handler);

  

  //

  

  为了让 SpringMVC 能调用开发人员定义的 Interceptor 我们还需要在 SpringMVC 配置文件中声明该 Interceptor 比如

  Xml代码

  <bean class= springframework web servlet mvc annotation DefaultAnnotationHandlerMapping >

  <property name= interceptors >

  <list>

  <ref bean= userInjectInterceptor /><! userInjectInterceptor bean 的声明省略 >

  </list>

  </property>

  </bean>

  优点

   对 Servlet API 的访问被移到了自 SpringMVC API 扩展的 Interceptor controller 不需要关心 User 如何得到

   开发人员可以通过随时添加或移除 Interceptor 来完成对不同参数在某一类型 controller 上的注入

   controller 的 User 对象通过外界注入 测试时开发人员可以很容易地注入自己想要的 User 对象

   controller 类去掉了对 Servlet API 的依赖 更 POJO 和通用

   controller 类是通过对 interface 的声明来辅助完成注入的 并不存在任何继承依赖

  不足

   SpringMVC 对 controller 默认是按照单例(singleton)处理的 在 controller 类中添加一个成员变量 可能会引起多线程的安全问题

   因为 User 对象是定义为 controller 的成员变量 而且是通过 setter 注入进来 在测试时需要很小心地保证对controller 注入了 User 对象 否则有可能我们拿到的就不一定是一个 好公民 (Good Citizen)

  其实 一言而蔽之 这些不足之所以出现 是因为我们把某个 action 级别需要的 User 对象上提到 controller 级别 破坏了 the convention of stateless for controller classes 而 setter 方式的注入又带来了一些隐含的繁琐和不足 当然 我们可以通过把 controller 声明为 prototype 来绕过 stateless 的约定 也可以保证每次 new 一个 controller 的同时给其注入一个 User 对象 但是我们有没有更简单更 OO 的方式来实现呢?答案是有的

  (三)通过方法参数处理类(MethodArgumentResolver)在方法级别注入User对象

  正如前面所看到的 SpringMVC 提供了不少扩展点给开发人员扩展 让开发人员可以按需索取 plugin 上自定义的类或 handler 那么 在 controller 类的层次上 SpringMVC 提供了 Interceptor 扩展 在 action 上有没有提供相应的 handler 呢?如果我们能够对 action 实现注入 出现的种种不足了

  通过查阅 SpringMVC API 文档 SpringMVC 其实也为 action 级别提供了方法参数注入的 Resolver 扩展 允许开发人员给 HandlerMapper 类 set 自定义的 MethodArgumentResolver

  action 的代码如下

  Java代码

  @RequestMapping

  public void hello(User user)

  //user sayHello()

  

  Resolver 的代码如下

  Java代码

  public class UserArgumentResolver implements WebArgumentResolver

  public Object resolveArgument(MethodParameter methodParameter NativeWebRequest webRequest) throws Exception

  if (methodParameter getParameterType() equals(User class))

  return webRequest getAttribute( currentUser RequestAttributes SCOPE_SESSION);

  

  return UNRESOLVED;

  

  

  配置文件的相关配置如下

  Xml代码

  <bean class= springframework web servlet mvc annotation OwnAnnotationMethodHandlerAdapter >

  <property name= customArgumentResolver >

  <ref bean= userArgumentResolver /><! userArgumentResolver bean 的定义省略 >

  </property>

  </bean>

  优点

   具备第二种方案的所有优点

   真正做到了按需分配 只在真正需要对象的位置注入具体的对象 减少其他地方对该对象的依赖

   其他人能很容易地从 action 的参数列表得知 action 所需要的依赖 API 更清晰易懂

   对于很多 action 需要的某一类参数 可以在唯一的设置点用很方便一致的方式进行注入

  不足

   对象依赖注入是针对所有 action 注入粒度还是较粗 不能做到具体 action 访问具体的 Session 属性

  (四)通过 SpringMVC 的 SessionAttributes Annotation 关联 User 属性

  SpringMVC 文档提到了 @SessionAttributes annotation 和 @ModelAttribute 配合使用可以往 Session 中存或者从 Session 中取指定属性名的具体对象 文档里说

  引用

  The type level @SessionAttributes annotation declares session attributes used by a specific handler This will typically list the names of model attributes which should be transparently stored in the session or some conversational storage serving as form backing beans beeen subsequent requests

  很明显 @SessionAttributes 是用来在 controller 内部共享 model 属性的 从文档自带的例子来看 标注成 @SessionAttributes 属性的对象 会一直保留在 Session 或者其他会话存储中 直到 SessionStatus 被显式 setComplete() 那这个 annotation 对我们有什么帮助呢?

  答案就是我们可以在需要访问 Session 属性的 controller 上加上 @SessionAttributes 然后在 action 需要的 User 参数上加上 @ModelAttribute 并保证两者的属性名称一致 SpringMVC 就会自动将 @SessionAttributes 定义的属性注入到 ModelMap 对象 在 setup action 的参数列表时 去 ModelMap 中取到这样的对象 再添加到参数列表 只要我们不去调用 SessionStatus 的 setComplete() 方法 这个对象就会一直保留在 Session 中 从而实现 Session 信息的共享

  controller的代码如下

  Java代码

  @Controller

  @SessionAttributes( currentUser )

  public class GreetingController

  @RequestMapping

  public void hello(@ModelAttribute( currentUser ) User user)

  //user sayHello()

  

  //

  

  使用这种方案 还需要在 SpringMVC 配置文件中 在定义 ViewResolver 时 加上 p:allowSessionOverride= true 这样如果你对 User 对象做了修改 就会在渲染 View 的同时覆写 Session 中的相关属性

  优点

   具备第二种方案的所有优点

   使用 Annotation 声明对 Session 特定属性的存取 每个 action 只需要声明自己想要的 Session 属性

   其他人能很容易地从 action 的参数列表得知 action 所需要的依赖 API 更清晰易懂

  不足

   对于相同属性的 Session 对象 需要在每个 action 上定义

   这种方案并不是 SpringMVC 的初衷 因此有可能会引起一些争议

  纵观这四类方法 我们可以看出我们对 Session 属性的访问控制设置 是从所有 Servlet 到某一类型的 controller 的成员变量 到所有 action 的某一类型参数 再到具体 action 的具体对象 每种方案都有各自的优点和不足 第一种方案虽然精确 但可惜引入了对 Servlet API 的依赖 不利于 controller 的测试和逻辑复用 第二 三种方案虽然解决了对 Servlet API 的依赖 也分别在 controller 和 action 级别上提供了对 Session 属性的访问 但注入粒度在一定程度上还是不够细 要想对具体属性进行访问可能会比较繁琐 不过 这在另一方面也提供了简便而统一的方法来对一系列相同类型的参数进行注入 第四种方案通过使用 Annotation 不仅摆脱了 Servlet API 的依赖 而且在 action 级别上提供了对 Session 具体属性的访问控制 但是这种访问有可能会粒度过细 需要在很多不同 action 上声明相同的 annotation 而且 毕竟这种用法并不是 SpringMVC 的初衷和推荐的 可能会带来一些争议

cha138/Article/program/Java/ky/201311/28209

相关参考

知识大全 hibernate的查询策略有哪些

导航对象图从一个已经装载的对象开始通过像aUsergetAddress()getCity()的属性访问器方法访问相关的对象如果Session是打开的当你导航图时Hibernate会自动装载图的节点当对

知识大全 为tomcat页面设置访问权限

  在web应用中对页面的访问控制通常通过程序来控制流程为登录>设置session>访问受限页面时检查session是否存在如果不存在禁止访问  对于较小型的web应用可以通过tomcat

牛皮癣的四种护理方法

牛皮癣的四种护理方法?牛皮癣是种常见的皮肤病,并且非常的顽固,给患者及其家人都带来了很大的影响,所以我们要在生活中尽量的来护理其症状,那么牛皮癣的四中护理方法都有哪些呢?牛皮癣的四种护理方法?1、牛皮

牛皮癣的四种护理方法

牛皮癣的四种护理方法?牛皮癣是种常见的皮肤病,并且非常的顽固,给患者及其家人都带来了很大的影响,所以我们要在生活中尽量的来护理其症状,那么牛皮癣的四中护理方法都有哪些呢?牛皮癣的四种护理方法?1、牛皮

知识大全 访问JAR和JAD文件中的属性

访问JAR和JAD文件中的属性  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  MIDIet能够访

抗衡股市风险的四种能力

抗衡股市风险的四种能力1、资金管理的能力;综观股市中的成功投资者基本上都是善于运用资金管理艺术的行家。面对着股市瞬息万变的市场环境和高速扩容的市场容量,过去陈旧的资金管理理念逐渐不能适应市场的变化,那

知识大全 浅析.NET类型转换的四种方法

浅析.NET类型转换的四种方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  NET类型转型的四

牛皮癣的四种症状

牛皮癣的四种症状?牛皮癣是种很让人头疼的一种皮肤病,并且非常顽固难除。牛皮癣在早期的时候症状不是太明显,所以导致患者在牛皮癣比较重的时候才重视治疗,这时候对于治疗是非常不利的,那么今天我们就来给大家讲

人身保险保险利益的四种情况

人身保险保险利益的四种情况1.本人对自己的生命和身体的保险利益任何人都对自己的生命和身体都具有无限的保险利益,这是各国法律都承认的一条原则。因此,任何人都可以为自己投保任何保险责任的人身保险合同,保险

激光去疤痕的四种手术方法

激光去疤痕的四种手术方法,洁净姣好的皮肤是我们每一位爱美人士所共同追求的,俗话说的好爱美之心人皆有之嘛。生活长路漫漫,若是不小心在脸上或是哪个部位的皮肤上留下了疤痕那可真是让人头疼的一件事,此时去、疤