JShop简介:jshop是一套使用Java语言开发的B2C网店系统,致力于为个人和中小企业提供免费、好用的网店系统。

项目主页:http://git.oschina.net/dinguangx/jshop

在线演示:

在spring mvc中,为了随时都能取到当前请求的request对象,可以通过RequestContextHolder的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。 
        在jshop中,对RequestContextHolder的使用进一步封装,简化为RequestHolder类,如下:

public class RequestHolder {
public static HttpServletRequest getRequest(){
HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return req;
} public static HttpServletResponse getResponse(){
HttpServletResponse resp = ((ServletWebRequest)RequestContextHolder.getRequestAttributes()).getResponse();
return resp;
}
}

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

public class RequestFacade implements HttpServletRequest 

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


protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
......
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
......
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
......
} protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
if (request instanceof MultipartHttpServletRequest) {
logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
"this typically results from an additional MultipartFilter in web.xml");
}
else {
return this.multipartResolver.resolveMultipart(request);
}
}
// If not returned before: return original request.
return request;
}

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


protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...... RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); try {
doService(request, response);
}
......
} protected ServletRequestAttributes buildRequestAttributes(
HttpServletRequest request, HttpServletResponse response, RequestAttributes previousAttributes) { if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
return new ServletRequestAttributes(request);
}
else {
return null; // preserve the pre-bound RequestAttributes instance
}
} private void initContextHolders(
HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) { if (localeContext != null) {
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
}
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
}
if (logger.isTraceEnabled()) {
logger.trace("Bound request context to thread: " + request);
}
}

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

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

Jshop简介:http://git.oschina.net/dinguangx/jshop

http://dinguangx.iteye.com/blog/2227049

RequestContextHolder的更多相关文章

  1. Spring中RequestContextHolder以及HandlerInterceptorAdapter的使用

    1 . RequestContextHolder 的使用 想要使用RequestContextHolder,要在web.xml中配置RequestContextListener的监听才能使用. //全 ...

  2. 源码分析之RequestContextHolder

    先看源码 /* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, ...

  3. RequestContextHolder 很方便的获取 request

    在 Spring boot web 中我们可以通过 RequestContextHolder 很方便的获取 request. ServletRequestAttributes requestAttri ...

  4. 通过RequestContextHolder直接获取HttpServletRequest对象

    问题 朋友遇到一个问题:他想在Service方法中使用HttpServletRequest的API,但是又不想把HttpServletRequest对象当作这个Service方法的参数传过来,原因是这 ...

  5. AOP 获取 RequestContextHolder

    转载: http://blog.csdn.net/lexang1/article/details/52619215 在使用spring时,经常需要在普通类中获取session,request等对像. ...

  6. SpringMVC之RequestContextHolder分析

    最近遇到的问题是在service获取request和response,正常来说在service层是没有request的,然而直接从controlller传过来的话解决方法太粗暴,后来发现了Spring ...

  7. 在@Async注解下RequestContextHolder.getRequestAttributes() 获得null的情况

    我们有的时候会在service层获取request填充一些诸如用户名和IP地址等信息,这个时候如果不想从Controller层传request,可以在service直接使用 HttpServletRe ...

  8. RequestContextHolder与RequestContextUtils

    org.springframework.web.servlet.support.RequestContextUtils 在spring-webmvc中, 主要用来获取WebApplicationCon ...

  9. Spring MVC的RequestContextHolder使用误区 good

    JShop简介:jshop是一套使用Java语言开发的B2C网店系统,致力于为个人和中小企业提供免费.好用的网店系统. 项目主页:http://git.oschina.net/dinguangx/js ...

  10. 空指针异常:解决 RequestContextHolder.getRequestAttributes()为空的问题

    现象:实现Feign请求拦截器时,执行如下代码,报空指针异常 ServletRequestAttributes attributes = (ServletRequestAttributes) Requ ...

随机推荐

  1. 配置MySQL服务器使得外网可以连接

    https://blog.csdn.net/bird3014/article/details/78481104

  2. 牛客假日团队赛6 D 迷路的牛 (思维)

    链接:https://ac.nowcoder.com/acm/contest/993/D 来源:牛客网 迷路的牛 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言 ...

  3. Maven工程构建

    Maven 相关术语: 本地资源库:用来存储项目的依赖库,默认的文件夹是 “.m2” 目录 中央存储库: 用来下载所有项目的依赖库的默认位置 Maven pom.xml: 项目对象模型(Project ...

  4. canvas 计算文字宽度(常用于文字换行)

    var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d"); ctx.font= ...

  5. javaIO--File类

    IO:File类 位于java.io包下,用于表示与平台无关的文件和目录File类可以用来操作文件和目录,但是不能用来访问文件的内容. 1.构造方法 File(String pathName)通过将给 ...

  6. 【leetcode】1209. Remove All Adjacent Duplicates in String II

    题目如下: Given a string s, a k duplicate removal consists of choosing k adjacent and equal letters from ...

  7. Redis实战(十五)Redis实现接口调用频率限制

    序言 登录次数 资料

  8. HTML5 大文件断点续传完整思路整理

    需求: 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验: 内网百兆网络上传速度为12MB/S 服务器内存占用低 支持文件夹上传,文件夹中的文件数量达到1万个以上,且包 ...

  9. cpp 面向对象初步探索

    需求 尝试定义一个complex(复数类) 简略实现 headers/complex.h #ifndef __COMPLEX__ #define __COMPLEX__ class complex { ...

  10. YOLO_V2

    YOLOv2:代表着目前业界最先进物体检测的水平,它的速度要快过其他检测系统(FasterR-CNN,ResNet,SSD),使用者可以在它的速度与精确度之间进行权衡. YOLO9000:这一网络结构 ...