当前位置:首页 > 开发 > 开源软件 > 正文

[JShop]Spring MVC的RequestContextHolder使用误区

发表于: 2015-07-13   作者:dinguangx   来源:转载   浏览:
摘要:     在spring mvc中,为了随时都能取到当前请求的request对象,可以通过RequestContextHolder的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。         在jshop中,对RequestContextHolder的

    在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对象却是RequestFacfade的实例。 
        原来在商品新增时,由于使用了文件上传,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

[JShop]Spring MVC的RequestContextHolder使用误区

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
原创内容,转载请注明出处 注:以下例子都是建立在第一个例子的基础上修改 1、@ResponseBody 该注解
/** * @Component,@Service,@Controller,@Repository注解的类 * * @Service(逻辑层使用)rt.jar @Rep
使用的uploadify 3.1 和easyUI 效果图 自己写得uploadify.js function getRootPath(){ //获取当前网
用spring mvc有一段时间了,今天有时间对这个框架的一些使用进行一些总结。 官网上面对spring mvc有
function getRootPath(){ //获取当前网址,如: http://localhost:8083/uimcardprj/share/meun.jsp
使用的uploadify 3.1 和easyUI 效果图 自己写得uploadify.js function getRootPath(){ //获取当前网
使用的uploadify 3.1 和easyUI 效果图 自己写得uploadify.js function getRootPath(){ //获取当前网
spring mvc 3开始,提供了对json的直接支持。这部分的支持功能包括把返回信息转化成json和将request
使用的uploadify 3.1 和easyUI 效果图 自己写得uploadify.js function getRootPath(){ //获取当前网
最近有个需求,就是把目前的项目由struts2平滑切换到spring mvc。网上貌似这个资料不是很多,不知道
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号