解决SpirngMVC使用RESTFUL时,HiddenHttpMethodFilter无法解析enctype=“multipart/form-data类型表单隐藏的请求方法

当使用RESTFUL风格,表达的方法为非GET以及POST时,需要使用HiddenHttpMethodFilter来对隐藏的方法进行解析。通常就是直接调用getParameter方法解析出隐藏域来值,然后传给Controller就行了。

但是,当表单中有文件上传时,表单实际上变为了一个输入流,需要进过特殊处理(解析)后,才能被HiddenHttpMethodFilter所识别,然后确定方法类型。而解析输入流的东西,就是CommonsMultipartResolver。

使用SpringMVC时,通常在配置文件中配置CommonsMultipartResolver为一个Bean,然后它完成对Form的解析,解析出普通的上传域以及MultipartFile类型的上传域(也就是file),自动绑定到相应的类中。

如果在Form中,隐藏了name="_method" value="PUT/DELETE/..."这个域,我们原本希望HiddenHttpMethodFilter来解析为指定的方法,但是,此时必须先经过CommonsMultipartResolver解析出相应的域后,HiddeHttpMethodFilter才能找到name="_method"这个隐藏域,进行处理。

SpringMVC的执行流程中,过滤器起作用,比如HiddenHttpMethodFilter过滤器配置的拦截路径为所有的请求,那么它会在请求发送到DispatcherServlet的时候,就进行解析。但是没有经过CommonsMultipartResolver的解析(它是在DisptacherServlet通过HandlerAdapter来调用相应Handler的过程中,进行参数的解析绑定时才起作用的),此时HidedenHttpMethodFilter解析不出来什么鸟东西,请求的方法还是为post方法,就会找不到相应的Handler。这就像是死锁。。。

怎么办呢?我们可以在HiddenHttpMethodFilter之前,再配置一个Filter,先把参数解析了不就好了嘛。

于是乎就配置一个MultipartFilter这个过滤器,指定一个初始化参数:multipartResolverBeanName,它的值为我们在spirng配置文件中配置好的CommonsMultipartResolver这个Bean的id就好了。

然而并非如此。因为在MultipartFilter进行过滤的时候,调用的Bean,是在Spring的根容器中配置的Bean。我们配置的普通的Spirng配置文件,只是DispatcherServlet的配置文件,并不是根容器的配置文件。(其实DispatcherServlet只是一个普通Servlet,我们可以简单的认为它也有一个自己的上下文环境,起着Spring容器的作用)。

这里简单说一下,上下文环境(context),有ServletContext、DispatcherServlet的上下文、以及spring根上下文webApplicationContext。在web项目中,ServletContext包含着webApplicationContext以及Dispatcher的Context,同时,web Application Context也是Dispatcher的context的父容器。

spring在执行ApplicationContext的个体Bean时,如果在自己的context上下文中找不到Bean,就会到父容器中去找。但是父容器不会找子容器。

所以,我们需要把CommonsMultipartResolver配置在WebApplicationContext中。单独写一个配置文件:root-context.xml:


 
 
  1. <!--配置文件上传解析器-->
  2. <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  3. <!--指定文件上传的总大小不超过20M-->
  4. <property name="maxUploadSize" value="20000000"/>
  5. <property name="defaultEncoding" value="utf-8"/>
  6. </bean>

在web.xml中,配置ServletContext的初始化参数:contextConfigLocation,仔配置一个监听器:ContextLoadLinstener。


 
 
  1. <context-param>
  2. <param-name>contextConfigLocation </param-name>
  3. <param-value>classpath:spring/root-context.xml </param-value>
  4. </context-param>
  5. <listener>
  6. <listener-class>org.springframework.web.context.ContextLoaderListener </listener-class>
  7. </listener>
  8. <filter>
  9. <filter-name>MultipartFilter </filter-name>
  10. <filter-class>org.springframework.web.multipart.support.MultipartFilter </filter-class>
  11. <init-param>
  12. <param-name>multipartResolverBeanName </param-name>
  13. <param-value>multipartResolver </param-value>
  14. </init-param>
  15. </filter>
  16. <filter-mapping>
  17. <filter-name>MultipartFilter </filter-name>
  18. <url-pattern>/* </url-pattern>
  19. </filter-mapping>
  20. <filter>
  21. <filter-name>hiddenHttpMethodFilter </filter-name>
  22. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter </filter-class>
  23. </filter>
  24. <filter-mapping>
  25. <filter-name>hiddenHttpMethodFilter </filter-name>
  26. <url-pattern>/* </url-pattern>
  27. </filter-mapping>
  28. <servlet>
  29. <servlet-name>springMVC </servlet-name>
  30. <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class>
  31. <init-param>
  32. <param-name>contextConfigLocation </param-name>
  33. <param-value>classpath:spring/applicationContext.xml </param-value>
  34. </init-param>
  35. </servlet>
  36. <servlet-mapping>
  37. <servlet-name>springMVC </servlet-name>
  38. <url-pattern>/ </url-pattern>
  39. </servlet-mapping>

当Servlet容器加载的时候,容器会读web.xml中的listener元素以及context-param元素。

紧接着,容器创建ServletContext,整个web项目通用。然后容器根据读取的listener以及初始化参数,进行相应的处理。

如此,就解决了问题。

  •                     <li class="tool-item tool-active is-like  tool-clicked"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">1</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/WARGON">
                    <img src="https://profile.csdnimg.cn/C/A/D/3_wargon" class="avatar_pic" username="WARGON">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/1x/2.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/WARGON" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">WARGON</a></span>
                                            </div>
                    <div class="text"><span>发布了120 篇原创文章</span> · <span>获赞 16</span> · <span>访问量 7万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=WARGON" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    
                   转载地址:https://blog.csdn.net/wargon/article/details/81811520
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值