RequestContextHolder
JShop简介:jshop是一套使用Java语言开发的B2C网店系统,致力于为个人和中小企业提供免费、好用的网店系统。
项目主页:http://git.oschina.net/dinguangx/jshop
在线演示:
- 前台: http://jshop.ofmall.org:81/jshop
- 后台: http://jshop.ofmall.org:81/jshop/manage/user/login (admin/123456)
在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的方法入参,即可以正确获取参数值。
http://dinguangx.iteye.com/blog/2227049
RequestContextHolder的更多相关文章
- Spring中RequestContextHolder以及HandlerInterceptorAdapter的使用
1 . RequestContextHolder 的使用 想要使用RequestContextHolder,要在web.xml中配置RequestContextListener的监听才能使用. //全 ...
- 源码分析之RequestContextHolder
先看源码 /* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, ...
- RequestContextHolder 很方便的获取 request
在 Spring boot web 中我们可以通过 RequestContextHolder 很方便的获取 request. ServletRequestAttributes requestAttri ...
- 通过RequestContextHolder直接获取HttpServletRequest对象
问题 朋友遇到一个问题:他想在Service方法中使用HttpServletRequest的API,但是又不想把HttpServletRequest对象当作这个Service方法的参数传过来,原因是这 ...
- AOP 获取 RequestContextHolder
转载: http://blog.csdn.net/lexang1/article/details/52619215 在使用spring时,经常需要在普通类中获取session,request等对像. ...
- SpringMVC之RequestContextHolder分析
最近遇到的问题是在service获取request和response,正常来说在service层是没有request的,然而直接从controlller传过来的话解决方法太粗暴,后来发现了Spring ...
- 在@Async注解下RequestContextHolder.getRequestAttributes() 获得null的情况
我们有的时候会在service层获取request填充一些诸如用户名和IP地址等信息,这个时候如果不想从Controller层传request,可以在service直接使用 HttpServletRe ...
- RequestContextHolder与RequestContextUtils
org.springframework.web.servlet.support.RequestContextUtils 在spring-webmvc中, 主要用来获取WebApplicationCon ...
- Spring MVC的RequestContextHolder使用误区 good
JShop简介:jshop是一套使用Java语言开发的B2C网店系统,致力于为个人和中小企业提供免费.好用的网店系统. 项目主页:http://git.oschina.net/dinguangx/js ...
- 空指针异常:解决 RequestContextHolder.getRequestAttributes()为空的问题
现象:实现Feign请求拦截器时,执行如下代码,报空指针异常 ServletRequestAttributes attributes = (ServletRequestAttributes) Requ ...
随机推荐
- Linux日常之数据重定向
Linux在启动后,会默认打开3个文件操作符,分别是 (1)标准输入0,standard input (2)正确输出1,standard output (3)错误输出2,standard error ...
- ui自动化之selenium操作(二)定位元素-简单操作
1. 将浏览器最大化 这里拿chrome举例,但是我在执行的时候一直报错,被坑了好久; 解决办法: 这是因为chromedriver是和chrome一一对应的,不兼容的版本就会报错: 所有chrome ...
- crontab定时执行shell脚本
步骤一 首先我们先看一下是否安装了crontab.一般情况下linux系统会自带crontab及crond.如果没有安装,请使用以下指令安装:yum install vixie-cron ...
- Java基本的程序结构设计 基本类型的输入输出
读取输入: java.util.Scanner 一个可以使用正则表达式来分析基本类型和字符串的简单文本扫描器. 了解: Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹 ...
- springboot-mybatis配置(xml)/springboot-jpa配置
#springboot-mybatis配置(xml) spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource. ...
- SpringMVC 中的注解@RequestParam与@PathVariable的区别
@PathVariable绑定URI模板变量值 @PathVariable是用来获得请求url中的动态参数的 @PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上.//配置 ...
- h5页面弹窗时页面固定(弹窗下面的页面不滑动)
页面出现弹窗时,底部页面不能随之滑动怎么解决? 只需将页面的body增加一个样式 overflow:hidden;就能解决 jq: //开启弹窗 $('body').attr('style','ove ...
- 百度地图api的简单应用(一):POI检索
使用之前,需要注册一个百度地图开发者账号,最好申请一个认证以获取更高的使用配额和并发上限. 注册之后,申请一个应用,获得一个ak(密钥),并填写ip地址白名单.(这里我使用0.0.0.0/0,查了自己 ...
- Nginx之概念和简介
Nginx是什么? 代理服务器,处于客户端和服务器端之间的一台服务器,不负责处理请求. 主要作用是什么? 1.负载均衡: 高并发场景下,Nginx代理服务器按一定规则将请求分发,从而使服务器能有条不紊 ...
- AOP 相关包
aop 命名空间,jar 扫路径