先说结论:

由于使用多文件上传使用了MultipartFile类来接收前端打包传输的经过FormData()处理过后Form表格,但是在MultipartFile上传之前会经过 org.springframework.web.multipart.commons.CommonsMultipartResolver这个包进行解析,而其中

spring对其设置的默认限制大小为1M,需要更改此设置才能够上传大文件!!!

因此需要在mvc配置中加入以下配置信息:

<!-- 定义文件上传解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设定默认编码 -->
        <property name="defaultEncoding" value="UTF-8"></property>
        <!-- 设定文件上传的最大值为1GB -->
        <property name="maxUploadSize" value="1073741824"></property>
        <!--设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240-->
        <property name="maxInMemorySize" value="40960"></property>
        <!-- 上传文件的临时路径 -->
        <property name="uploadTempDir" value="./upTemp"></property>
        <!--延迟文件解析-->
        <property name="resolveLazily" value="true"/>
    </bean>

ps:会导致该错误的原因还有前端form表单的文件中,只设置了id属性,没有设置name属性

以下是debug的漫长过程:

在网页中,我使用ajax对数据进行传输,前端内容大致如下:

<form id="upload_form" enctype="multipart/form-data">
            <div>
                <div><label for="image_file" style="color: wheat;">请选择投稿视频文件</label></div>
                <div><input type="file" name="files" id="video"/></div>
            </div>
            <!--进度条-->
            <div class="progress">
                <div class="progress-bar" id="progress-bar"></div>
            </div>
            <div>
                <div><label for="image_file" style="color: wheat;">请选择投稿封面壁纸</label></div>
                <div><input type="file" name="files" id="img"/></div>
            </div>
            <div>
                <div><label for="image_file" style="color: wheat;">请输入视频标题</label></div>
                <div><input type="text" name="title" id="biaoti"/></div>
            </div>

            <div>
                <div><label for="image_file" style="color: wheat;">请输入视频描述</label></div>
                <div><textarea rows="13" name="describe" id="miaoshu" cols="70"></textarea></div>
            </div>

            <div>
                <div><label for="image_file" style="color: wheat;">请选择投放区域</label></div>
                <div>
                    <label><input name="vType" type="radio" value="1" checked/>动画 </label>
                    <label><input name="vType" type="radio" value="2"/>MAD </label>
                    <label><input name="vType" type="radio" value="3"/>音乐 </label>
                    <label><input name="vType" type="radio" value="1"/>影视 </label>
                    <label><input name="vType" type="radio" value="2"/>原创 </label>
                </div>
            </div>
            <div>
                <input type="button" value="立即投稿" id="tougao"/> <input type="button" id="fanhui" value="取消返回"/>
            </div>
</form>

js的ajax大致如下:

$("#tougao").click(function () {
            $("#tougao").attr('disabled', true); //将button变成不可点击
            // forData为form的表单
            var formData = new FormData($("#upload_form")[0]);
            $.ajax({
                url: 'ajaxvideoFileTop',
                type: 'POST',
                data: formData,
                async: true,  //设置为同步
                cache: false,
                contentType: false,
                processData: false,
                success: function (returndata) {
                    $("#tougao").attr('disabled',false); //将button变成可点击
                },
                error: function (returndata) {
                    console.log("returndata is :" + returndata)
                    alert(returndata);
                },
                xhr: function () {
                    myXhr = $.ajaxSettings.xhr();
                    if (myXhr.upload) { //检查upload属性是否存在
                        //绑定progress事件的回调函数
                        myXhr.upload.addEventListener('progress', progressHandlingFunction, false);
                    }
                    return myXhr; //xhr对象返回给jQuery使用
                }
            });
            // 上传进度数字显示
            function progressHandlingFunction(event) {
                var loaded = Math.floor(100 * (event.loaded / event.total)); //已经上传的百分比
                $("#progress-bar").html(loaded + "%").css("width", loaded + "%");
            }
        });

后端的controller为:

@RequestMapping(value = "ajaxvideoFileTop", method = RequestMethod.POST)
    public String ajaxVideoup(@RequestParam("files") MultipartFile[] files,
                              @RequestParam String title,
                              @RequestParam String describe,
                              @RequestParam String vType,
                              HttpServletRequest request) {
        ...}

前端的摸查

初次触发ajxa的提交后报错误400 合理怀疑前端页面数据打包格式不正确,于是调出 new FormData($("#upload_form")[0])的值进行查看:

看起来数据打包没什么问题,上传的两个文件都在,还是找不到原因。

查看tomcat后台也无任何报错或者空指针,于是推测是tomcat接收不了,但是在网上查询后发现,由于我使用的是IDEA中设置的tomcat,所以应该是没有限制上传文件大小的......

实在想不明白,尝试使用fiddle抓取网页的request

传输的表单文件完好,name属性也设置正确这里开始排除前端的原因了

后端的摸查

由于后端没有任何反应,我怀疑是在 @RequestMapping这就匹配不上了,在网上重新回忆了下mvc的执行流程大致如下:

  • DispatcherServlet

    • doService

      • doDispatch

        • mappedHandler 这里会反射控制器方法
  • handle

    • HandlerAdapter ha 控制器的方法是在这里调用的

.....

查看mappedHandle中的handler发现其实是找到控制器方法的了

继续往下

查询spring API document

到此为止,也不是mappedHandler的问题,那就只剩下param匹配的问题了,但是我反复对比也没能发现与spring文档中的说明有任何的出入

于是开始死马当活马医,在 org.springframework.web.multipart包下查看 org.springframework.web.multipart.MultipartFile的加载过程

知道我注意到同包下有这些的存在:

抓住Resolver这个字眼 查看是什么类实现了这个MultipartResolver接口查看里面有没有声明什么方法,抓到了一点线索:

可见这里的报错中存在一个超出文件大小限制的说法

因此我猜测在某个实现类中应该会存在这个大小限制的变量,于是我开始查找MultipartResolver接口

  • 虽然JAVA8以后能在接口中写入一些静态常量,但是这些老接口应该是不会这样做的,所以这里我要找它的实现类

先随便进入一个实现类查看,该类的说明:

这个说明可以通过用它设置bean来设置文件上传的最大大小,总算是给我逮到了,继续看它的父类

可以大致得知这是设置上传File文件的一些基础参数用的,用size作为关键字眼继续搜寻,结果找到了对应的get set方法,这里就是可以给bean设置的依据

这些应该bingo了??

再返回MultipartResolver接口查看另外一个实现类

可知该类也可以实现设置上传文件大小,只需要在web.xml中设置MultipartConfig的参数就可以了

综上相当于这两个类给了我们两种方法去设置文件上传的最大体积,最后给出导致我一直400的罪魁祸首 maxFileSize

这是利用注解声明最大上传体积的方法

至此找到罪魁祸首,我这里就直接利用spring的bean给上述的注入CommonsMultipartResolver:

<!-- 定义文件上传解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设定默认编码 -->
        <property name="defaultEncoding" value="UTF-8"></property>
        <!-- 设定文件上传的最大值为1GB -->
        <property name="maxUploadSize" value="1073741824"></property>
        <!--设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240-->
        <property name="maxInMemorySize" value="40960"></property>
        <!-- 上传文件的临时路径 -->
        <property name="uploadTempDir" value="./upTemp"></property>
        <!--延迟文件解析-->
        <property name="resolveLazily" value="true"/>
    </bean>

通过postman打包post数据和ajax上传,全部都没问题了,总算解决了

总结

还是对spring了解的不够透彻,文档属于还是没看明白,想到文件上传限制,想到了tomcat却没想到是spring的问题,这次debug查阅了大量资料和浪费了大量时间,希望以后能记得这种流程,下次应该就不会这么折磨了?(大概把)

补充:

关于org.apache.commons.fileuploadorg.springframework.web.multipart.commons.CommonsMultiFile会产生冲突的问题

本质都是使用fileupload进行配置的,如果使用了CommonsMultiFile的配置后会覆盖掉一部分fileupload的配置,导致request不能被解析。

因此如果在bean中配置了org.springframework.web.multipart.commons.CommonsMultipartResolver,则request中的多文件上传格式会被改变,不能通过ServletFileUpload的.parseRequest去解析request了,它已经被装载成MultipartFile格式可以被直接读取了

如果对你有帮助就太好了)))