Spring MVC的RequestContextHolder使用误区 good
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
Spring MVC的RequestContextHolder使用误区 good的更多相关文章
- Spring MVC的RequestContextHolder使用误区
JShop简介:jshop是一套使用Java语言开发的B2C网店系统,致力于为个人和中小企业提供免费.好用的网店系统. 项目主页:http://git.oschina.net/dinguangx/js ...
- Spring MVC 中RequestContextHolder获取request和response
1.最简单方式:处理方法入参 例如: @RequestMapping("/test") @ResponseBody public void saveTest(HttpServlet ...
- spring mvc 异常统一处理方式
springMVC提供的异常处理主要有两种方式: 一种是直接实现自己的HandlerExceptionResolver: 另一种是使用注解的方式实现一个专门用于处理异常的Controller——Exc ...
- spring mvc DispatcherServlet详解之前传---前端控制器架构
前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端.前端控制器既可以使用Filter实现 ...
- Spring MVC中各个filter的用法
转载:http://blog.csdn.net/qyp1314/article/details/42023725 Spring MVC中各个filter的用法 2014-12-19 09:08 105 ...
- spring、spring mvc、mybatis框架整合基本知识
学习了一个多月的框架知识了,这两天很想将它整合一下.网上看了很多整合案例,基本都是基于Eclipse的,但现在外面公司基本都在用Intellij IDEA了,所以结合所学知识,自己做了个总结,有不足之 ...
- Spring MVC 中获取session的几种方法
Spring MVC 中使用session是一种常见的操作,但是大家上网搜索一下可以看到获取session的方式方法五花八门,最近,自己终结了一下,将获取session的方法记录下来,以便大家共同学习 ...
- Spring MVC 后端获取前端提交的json格式字符串并直接转换成control方法对应的参数对象
场景: 在web应用开发中,spring mvc凭借出现的性能和良好的可扩展性,导致使用日渐增多,成为事实标准,在日常的开发过程中,有一个很常见的场景:即前端通过ajax提交方式,提交参数为一个jso ...
- Servlet的生命周期以及在Spring MVC中调用流程
接触Web时间比较久,虽然知道Servlet的生命周期但是理解却还是不够,今天刚好debug代码涉及这块就利用余下时间研究了一下. Servlet的生命周期以及处理浏览器请求的过程.Servlet接口 ...
随机推荐
- Spring Boot Shiro 权限管理
Spring Boot Shiro 权限管理 标签: springshiro 2016-01-14 23:44 94587人阅读 评论(60) 收藏 举报 .embody{ padding:10px ...
- 51NOD——N 1107 斜率小于0的连线数量
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1107 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 ...
- bootstrap 时间控件带(时分秒)选择器(需要修改才能显示,请按照参数说明后面的步骤进行修改)
1.控件下载地址:http://www.bootcss.com/p/bootstrap-datetimepicker/index.htm,参数设置说明也在这个链接下面: 2.具体参数说明(复制原链接) ...
- C语言深度剖析-----函数与指针分析
阅读代码的重要技巧 函数类型 函数指针 回调函数 使用示例 指针阅读技巧解析 例
- 【Codeforces Round #437 (Div. 2) B】Save the problem!
[链接]h在这里写链接 [题意] 给你一个金额N,和硬币的类型总数M; (完全背包),然后问你组成N的方案数. 使得,用这些硬币组成价值为N的金额的方案数为A; 现在A ...
- 常用MVC框架
J2EE开常用的SSH或SSI框架,对应解决表示层.业务逻辑层.持久化层的问题,其中对表示层的解决方案最多,常见的有Struts1/2,Spring MVC等,实际上都是在最底层的Servlet规范中 ...
- FATFS在SD卡里,写入多行数据出的问题
串口接收的数据存入数组,然后把数组截取有效部分,存入SD卡里的一行没有问题 但是从SD卡读出这一行之后,重新写入SD卡就有了问题,经过调试发现,错误在于 \n 一直是这一串数据,为什么会出错呢??? ...
- [Jade] Use Mixins in Pug
Mixin works as a function. extends layout include mixins/storeForm block content .inner h2 #{title} ...
- [MobX] MobX fundamentals: deriving computed values and managing side effects with reactions
Derivations form the backbone of MobX and come in two flavors: computed values are values that can b ...
- Avro基础 分类: C_OHTERS 2015-02-14 19:56 310人阅读 评论(0) 收藏
一.Avro的基本功能 1.定义了数据模式文件的语法,一般使用json文件.以及一些数据基本类型与复杂类型. 2.定义了数据序列化到文件后的数据格式,此格式可供各种语言进行读取. 3.为部分语言定义了 ...