zoukankan      html  css  js  c++  java
  • AOP 获取 RequestContextHolder

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

    在使用spring时,经常需要在普通类中获取session,request等对像.
    比如一些AOP拦截器类,在有使用struts2时,因为struts2有一个接口使用org.apache.struts2.ServletActionContext即可很方便的取到session对像.
    用法:

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




    但在单独使用spring时如何在普通类中获取session,reuqest呢?
    首先要在web.xml增加如下代码:

    [html] view plain copy
     
    1. <listener>  
    2.         <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>  
    3.  </listener>  

    使用方法:

      在普通bean中

    [java] view plain copy
     
    1. @Autowired    
    2. private HttpSession session;    
    3.     
    4. @Autowired    
    5. private HttpServletRequest request;    


    在普通类中

    [java] view plain copy
     
    1.     public static HttpServletRequest getRequest(){  
    2.         HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
    3.         return req;  
    4.     }  
    5.   
    6.     public static HttpServletResponse getResponse(){  
    7.         HttpServletResponse resp = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();  
    8.         return resp;  
    9.     }  


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

    [java] view plain copy
     
    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

    [java] view plain copy
     
    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.   
    12.     protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {  
    13.         if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {  
    14.             if (request instanceof MultipartHttpServletRequest) {  
    15.                 logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +  
    16.                         "this typically results from an additional MultipartFilter in web.xml");  
    17.             }  
    18.             else {  
    19.                 return this.multipartResolver.resolveMultipart(request);  
    20.             }  
    21.         }  
    22.         // If not returned before: return original request.  
    23.         return request;  
    24.     }  


    那么,RequestContextHolder中的request又是从哪来的呢? 
    继续翻看DispatcherServlet的源码,从其父类FrameworkServlet中找到的processRequest()以相关方法源码:

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


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

            最便捷的解决办法: 
    直接将HttpServletRequest作为spring mvc的方法入参,即可以正确获取参数值。

  • 相关阅读:
    java object bean 转map
    常用css
    mysql 生成max+1编号
    MySql避免重复插入记录方法(ignore,Replace,ON DUPLICATE KEY UPDATE)
    cookie记住账户密码
    session有效时间
    常用jstl
    高性能MySQL--innodb中事务的隔离级别与锁的关系
    mysql8.0.11的坑早知道
    git进阶--你可能不知道的很好用git功能
  • 原文地址:https://www.cnblogs.com/Jeely/p/10811923.html
Copyright © 2011-2022 走看看