转载: http://blog.csdn.net/lexang1/article/details/52619215

在使用spring时,经常需要在普通类中获取session,request等对像.

比如一些AOP拦截器类,在有使用struts2时,因为struts2有一个接口使用org.apache.struts2.ServletActionContext即可很方便的取到session对像.

用法:

  1. //获取请求对像
  2. public static HttpServletRequest getRequest() {
  3. return  ServletActionContext.getRequest();
  4. }
  5. //获取输出对象
  6. public static HttpServletResponse getResponse(){
  7. return ServletActionContext.getResponse();
  8. }

但在单独使用spring时如何在普通类中获取session,reuqest呢?

首先要在web.xml增加如下代码:

  1. <listener>
  2. <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  3. </listener>

使用方法:

  在普通bean中

  1. @Autowired
  2. private HttpSession session;
  3. @Autowired
  4. private HttpServletRequest request;

在普通类中

  1. public static HttpServletRequest getRequest(){
  2. HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  3. return req;
  4. }
  5. public static HttpServletResponse getResponse(){
  6. HttpServletResponse resp = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
  7. return resp;
  8. }

你必须要有一个request的引用,否则是取不到的。request可以通过控制器传入,有了request自然就可以取到session了,或者可以通过spring的WebUtils取Session数据,如下:

拦截器举例:

  1. public boolean preHandle(HttpServletRequest request,
  2. HttpServletResponse response, Object handler) throws
  3. Exception {
  4. String context = (String) WebUtils.getSessionAttribute(request,
  5. "context_key");
  6. return context != null ;
  7. }

RequestContextHolder使用误区

在spring mvc中,为了随时都能取到当前请求的request对象,可以通过RequestContextHolder的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。 

  在大部分的情况下,它都能很好地工作,但在商品管理编辑中,新增商品时,却出现了意外的问题:通过RequestHolder.getRequest().getParameter()得不到参数值,通过debug发现,通过spring mvc的method注入的request对象实际为MultipartHttpServletRequest,而通过RequestHolder.getRequest()获取到的request对象却是RequestFacfade的实例。 

        原来在商品新增时,由于使用了文件上传,form表单的enctype类型为”multipart/form-data”,spring mvc对文件上传的处理类实际却为spring-mvc.xml文件中配置的CommonsMultipartResolver, 该类先判断当前请求是否为multipart类型,如果是的话,将request对象转为MultipartHttpServletRequet,相关的源码见DisptcherServlet

  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. HttpServletRequest processedRequest = request;
  3. ......
  4. processedRequest = checkMultipart(request);
  5. multipartRequestParsed = processedRequest != request;
  6. ......
  7. // Actually invoke the handler.
  8. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  9. ......
  10. }
  11. protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
  12. if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
  13. if (request instanceof MultipartHttpServletRequest) {
  14. logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
  15. "this typically results from an additional MultipartFilter in web.xml");
  16. }
  17. else {
  18. return this.multipartResolver.resolveMultipart(request);
  19. }
  20. }
  21. // If not returned before: return original request.
  22. return request;
  23. }

那么,RequestContextHolder中的request又是从哪来的呢? 

继续翻看DispatcherServlet的源码,从其父类FrameworkServlet中找到的processRequest()以相关方法源码:

  1. protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  2. throws ServletException, IOException {
  3. ......
  4. RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
  5. ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
  6. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  7. asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
  8. initContextHolders(request, localeContext, requestAttributes);
  9. try {
  10. doService(request, response);
  11. }
  12. ......
  13. }
  14. protected ServletRequestAttributes buildRequestAttributes(
  15. HttpServletRequest request, HttpServletResponse response, RequestAttributes previousAttributes) {
  16. if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
  17. return new ServletRequestAttributes(request);
  18. }
  19. else {
  20. return null;  // preserve the pre-bound RequestAttributes instance
  21. }
  22. }
  23. private void initContextHolders(
  24. HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {
  25. if (localeContext != null) {
  26. LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
  27. }
  28. if (requestAttributes != null) {
  29. RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
  30. }
  31. if (logger.isTraceEnabled()) {
  32. logger.trace("Bound request context to thread: " + request);
  33. }
  34. }

从这里可以看到,initContextHolder()方法中完成了RequestContextHolder的requestAttributes设置,而doService()在这之后调用,DispatcherServlet中的processRequest()方法即在doService()之中,所以从RequestContextHolder中获取到的就是原来的RequestFacade对象,而不是经过spring mvc处理之后的MultipartHttpServletRequest对象,其后果就是,从RequestContextHolder获取request后,无法直接通过getParameter()获取参数值。

最便捷的解决办法: 

直接将HttpServletRequest作为spring mvc的方法入参,即可以正确获取参数值。

AOP 获取 RequestContextHolder的更多相关文章

  1. AOP获取方法注解实现动态切换数据源

    AOP获取方法注解实现动态切换数据源(以下方式尚未经过测试,仅提供思路) ------ 自定义一个用于切换数据源的注解: package com.xxx.annotation; import org. ...

  2. Spring AOP获取不了增强类(额外方法)或无法通过getBean()获取对象

    Spring AOP获取不了增强类(额外方法)和无法通过getBean()获取对象 今天在学习AOP发现一个小问题 Spring AOP获取不了额外方法,左思右想发现是接口上出了问题 先上代码 获取不 ...

  3. spring aop 获取request、response对象

    在网上看到有不少人说如下方式获取: 1.在web.xml中添加监听 <listener>          <listener-class>              org. ...

  4. Spring-boot 配置Aop获取controller里的request中的参数以及其返回值

    首先在你的Maven的pom文件里加入aop的依赖: <dependency> <groupId>org.springframework.boot</groupId> ...

  5. spring aop获取目标对象的方法对象(包括方法上的注解)

    这两天在学习权限控制模块.以前看过传智播客黎活明老师的巴巴运动网视频教程,里面就讲到权限控制的解决方案,当时也只是看看视频,没有动手实践,虽说看过几遍,可是对于系统中的权限控制还是很迷茫,所以借着这次 ...

  6. Spring AOP获取方法的参数名称和参数值

    aop配置: <aop:aspectj-autoproxy expose-proxy="true" /> @Before(value = "execution ...

  7. Spring AOP获取拦截方法的参数名称跟参数值

    注意:这种方式需要JDK1.8版本支持 开始:http://www.cnblogs.com/wing7319/p/9592184.html 1.aop配置: <aop:aspectj-autop ...

  8. 2018-02-11 发布 spring 自定义注解(annotation)与 aop获取注解

    知识点: Java自定义注解.spring aop @aspect的使用 首先我们先介绍Java自定义注解. 在开发过程中,我们实现接口的时候,会出现@Override,有时还会提示写@Suppres ...

  9. 【转】spring 自定义注解(annotation)与 aop获取注解

    首先我们先介绍Java自定义注解. 在开发过程中,我们实现接口的时候,会出现@Override,有时还会提示写@SuppressWarnings.其实这个就是Java特有的特性,注解. 注解就是某种注 ...

随机推荐

  1. Linux下DHCP服务安装配置

    简介 安装配置 一.简介 DHCP (Dynamic Host Configuration Protocol,动态主机管理协议)是一种基于UDP协议且仅限用于局域网的网络协议,主要用途是为局域网内部设 ...

  2. 盖茨基金会:如何使用Python拯救生命

    每年全球都要花费数十亿美元来预防疾病,减少死亡,资助预防保健及治疗的各种研发项目,以及其他的健康方案.但资金毕竟是有限的,所以一些组织,比如全球卫生资金的主要捐助者比尔&梅林达·盖茨基金会(B ...

  3. php中按值传递和按引用传递的一个问题

    php中传递变量默认是按照值传递. 简单举个例子: <?php function testArray($arr){// &$arr $arr = array(1,2,3,); } $ar ...

  4. ASP.NET web.config中数据库连接字符串connectionStrings节的配置方法

    ASP.NET web.config中数据库连接字符串connectionStrings节的配置方法 第一种情况,本地开发时,使用本地数据库,如下面的代码 <connectionStrings& ...

  5. 【已解决】在 Visual Studio 中设置 JavaScript/TypeScript 的断点 脚本出现自动中断错误

    运行ASP.NET Core 程序出现错误如下: 已启用 Visual Studio 中的 Chrome 脚本调试 在 Visual Studio 中设置 JavaScript/TypeScript ...

  6. Web系统页面打印技术实现与分析

    1 Web页面打印概述应用WEB化,不论对开发商,还是对用户来说,实在是一种很经济的选择,因为基于WEB的应用,客户端的规则很简单,容易学习,容易维护,容易发布.在WEB系统中,打印的确是个烦人的问题 ...

  7. 《移山之道》Reading Task——by12061154Joy

    最近因为作业的原因所以接触到了这本书,给我最特别的感觉就是很新鲜,主要是因为这本书是以故事展开的,大概是我读的书太少,基本没有看到过专业书的知识体系是用故事串讲起来的,这样帮助读者理解了一些概念并且不 ...

  8. 个人博客作业-Week7

    团队任务中个人感想 我们团队选的题目是爬虫, 采用用AVA平台开发了, 我原来JAVA语言不熟悉了, PM考虑这部分之后分配任务这部分感觉很多谢 团队当中的PM很清楚每个组员的力量, 所以PM跟每个组 ...

  9. Linux内核分析— —扒开系统调用的三层皮(上)

    实验部分 根据系统调用表,选取一个系统调用.我选得是mkdir这个系统调用,其系统调用号为39,即0x27 由于mkdir函数的原型为int mkdir (const char *filename, ...

  10. 原型设计(“留拍”Axure整体操作过程)

    使用 Axure 来设计原型[通过 视频(自己录视频上传到优酷网站) 来介绍 “留拍” 的基本 原型 ,后续再 美化界面 和 补充 详细功能]: 请点击下图的播放按钮来弹出视频(通过URL连接):