• SpringBoot使用webxml后上传文件异常multipart-form is disabled


    SpringBoot使用webxml后上传文件异常multipart-form is disabled

    今天遇到了上传文件的一个问题,项目环境是Springboot+JSP。因为使用了公司内部的框架,所以也需要使用web.xml。

    一、表单+后台处理代码

    <form method="post" action="<c:url value="/student/commit"/>" enctype="multipart/form-data">
        <input type="text" name="name"/>
        <input type="file" name="file"/>
        <input type="submit"/>
    </form>
    
    @RequestMapping(value = "/commit", method = RequestMethod.POST)
    public String commit(@RequestParam("name") String name,
                         @RequestParam("file") MultipartFile file) {
    
        logger.info(name);
        try {
            logger.info(file.getInputStream().toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        return "/student/commit";
    }
    

    一个非常简单的文件上传,错误里的 no multi-part configuration has been provided 是什么意思,未提供文件上传的配置?

    可我分明在 spring-web.xml 里加入了相应的配置。

    我再仔细看,Could not parse multipart servlet request,没有 servlet 的配置?

    异常堆栈:

    2019-08-20 15:56:44.084 ERROR 5104 --- [esin-port-80-48] o.s.b.w.servlet.support.ErrorPageFilter  : Forwarding to error page from request [/admin/student/import.do] due to exception [Failed to parse multipart servlet request; nested exception is javax.servlet.ServletException: multipart-form is disabled; check @MultipartConfig annotation on 'geli-springboot'.]
    
    org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is javax.servlet.ServletException: multipart-form is disabled; check @MultipartConfig annotation on 'geli-springboot'.
    	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.handleParseFailure(StandardMultipartHttpServletRequest.java:123) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:114) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:87) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:87) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1176) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1011) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:159) ~[javaee-16.jar:na]
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:97) ~[javaee-16.jar:na]
    	at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:109) ~[resin.jar:4.0.62]
    	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.22.jar:9.0.22]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at org.gelivable.web.EnvFilter.doFilter(EnvFilter.java:83) [geli-spring-boot-3.0.1.jar:na]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:128) [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
    	at org.springframework.boot.web.servlet.support.ErrorPageFilter.access$000(ErrorPageFilter.java:66) [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
    	at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:103) [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:121) [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at org.gelivable.web.AbstractAuthFilter.doFilter(AbstractAuthFilter.java:56) [geli-spring-boot-3.0.1.jar:na]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at org.gelivable.web.EnvFilter.doFilter(EnvFilter.java:83) [geli-spring-boot-3.0.1.jar:na]
    	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89) [resin.jar:4.0.62]
    	at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:156) [resin.jar:4.0.62]
    	at com.caucho.server.webapp.AccessLogFilterChain.doFilter(AccessLogFilterChain.java:95) [resin.jar:4.0.62]
    	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:314) [resin.jar:4.0.62]
    	at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:843) [resin.jar:4.0.62]
    	at com.caucho.network.listen.TcpSocketLink.dispatchRequest(TcpSocketLink.java:1393) [resin.jar:4.0.62]
    	at com.caucho.network.listen.TcpSocketLink.handleRequest(TcpSocketLink.java:1349) [resin.jar:4.0.62]
    	at com.caucho.network.listen.TcpSocketLink.handleRequestsImpl(TcpSocketLink.java:1333) [resin.jar:4.0.62]
    	at com.caucho.network.listen.TcpSocketLink.handleRequests(TcpSocketLink.java:1241) [resin.jar:4.0.62]
    	at com.caucho.network.listen.TcpSocketLink.handleAcceptTaskImpl(TcpSocketLink.java:1037) [resin.jar:4.0.62]
    	at com.caucho.network.listen.ConnectionTask.runThread(ConnectionTask.java:117) [resin.jar:4.0.62]
    	at com.caucho.network.listen.ConnectionTask.run(ConnectionTask.java:93) [resin.jar:4.0.62]
    	at com.caucho.network.listen.SocketLinkThreadLauncher.handleTasks(SocketLinkThreadLauncher.java:175) [resin.jar:4.0.62]
    	at com.caucho.network.listen.TcpSocketAcceptThread.run(TcpSocketAcceptThread.java:61) [resin.jar:4.0.62]
    	at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:173) [resin.jar:4.0.62]
    	at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118) [resin.jar:4.0.62]
    Caused by: javax.servlet.ServletException: multipart-form is disabled; check @MultipartConfig annotation on 'geli-springboot'.
    	at com.caucho.server.http.AbstractCauchoRequest.getParts(AbstractCauchoRequest.java:246) ~[resin.jar:4.0.62]
    	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:94) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    	... 52 common frames omitted
    
    

    二、谜题之解

    我这才意识到,SpringMVC 是依赖 Servlet 的,虽然 SpringMVC 能识别 Servlet,但它底层的 Servlet 也许还不能识别文件上传。

    SpringMVC 官网的 refference 去看文档,果然,我发现了一些猫腻:

    Once Servlet 3.0 multipart parsing has been enabled in one of the above mentioned ways you can add the StandardServletMultipartResolver to your Spring configuration

    在配置 SpringMVC 的 StandardServletMultipartResolver 之前必须先配置 Servlet,官网提供的方案有:

    • 1.mark the DispatcherServlet with a “multipart-config” section in web.xml(在 web.xml 文件中的 DispatcherServlet 元素里,加上一个 multipart-config)
    • 2.with a javax.servlet.MultipartConfigElement in programmatic Servlet registration
    • 3.in case of a custom Servlet class possibly with a javax.servlet.annotation.MultipartConfig annotation on your Servlet class

    我选择了第一种方案,打开 webapp/WEB-INFO 目录下的 web.xml,往 DispatcherServlet 里加了一行

    <multipart-config/>
    

    再运行项目,就可以正常地上传文件了。

    web.xml 全部内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app
            version="3.0"
            xmlns="http://java.sun.com/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    		http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    
        <display-name>geli-springboot</display-name>
    
        <servlet>
            <servlet-name>geli-springboot</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:application-servlet.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
            <!--让Servlet支持文件上传-->
            <multipart-config/>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>geli-springboot</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
            <welcome-file>/admin/login.jsp</welcome-file>
        </welcome-file-list>
    
    </web-app>
    
    

    参考文档:

    https://www.iloveqyc.com/2016/06/03/springmvc-upload-file-fail-servlet/

    https://juejin.im/post/5a730f895188257a6d634f0a#heading-6

    Spring揭秘--寻找遗失的web.xml

    https://www.cnkirito.moe/servlet-explore/

    -------------已经触及底线 感谢您的阅读-------------
  • 相关阅读:
    borderInterpolate()函数
    cvtColor(src, src_gray, CV_BGR2GRAY)报错
    用OpenCV读取摄像头
    OpenCV的视频输入和相似度测量
    C++ main函数中参数argc和argv含义及用法
    OpenCV的视频读取
    MySql与Oracle的几个主要区别
    OLTP与OLAP的介绍(理论知识)
    IDEA激活
    short i =1; i=i+1与short i=1; i+=1的区别
  • 原文地址:https://www.cnblogs.com/cnsyear/p/12777888.html
Copyright © 2020-2023  润新知