springmvc接收文件和参数_springmvc接收文件和参数

springmvc接收文件和参数_springmvc接收文件和参数0前言1.项目需要上传文件和大量的文件夹,页面只有一个inputfile标签会很丑,偶然间得知dropzone类库,决定使用

0 前言

1.项目需要上传文件和大量的文件夹,页面只有一个input file标签会很丑,偶然间得知dropzone类库, 决定使用。 2. 项目后端采用springmvc接收,调用minio代码上传至本地文件数据库。 3. 本以为只是美化一下界面,很快就能实现,没想到中间遇到了太多的问题。 4. 经过两天时间,网上查资料和自己摸索,终于实现了我想要的所有功能 5. 功能包括:单个文件上传、多个文件上传、大量文件夹(上千个)上传、文件和表单一起上传等。 6. 代码中用到jquery 

1 dropzone介绍

DropzoneJS是一个提供文件拖拽上传并且提供图片预览的开源类库.
它是轻量级的,不依赖任何其他类库(如JQuery)并且高度可定制.

在这里插入图片描述

简而言之,有个强大的文件拖拽功能和好看的界面,网站链接如下:
中文网站
英文网站
GitHub

2 单文件上传

2.1 问题:文件与表单一同提交

刚开始就遇到了问题,dropzone默认情况下文件拖放到指定区域后就自动进行上传,而不需要点击提交,但是我后台需要将一些表单数据和文件一起提交,于是问题出现了。

2.2 解决:点击提交按钮,将文件和表单一起发送

  1. dropzone有两种穿件文件拖放区域的方式,一种是<form>,一种是<div>,既然要和其他数据一起提交,表单中嵌套表单是不行的,于是采用<div>的形式,下面是页面:
 <form class="form-horizontal" action="" method="post" enctype="multipart/form-data"> <input class="form-control" value="default" type="text" name="folderName" id="folderName"> <textarea class="form-control" rows="5" name="siteDescription" id="siteDescription"></textarea> <!--Start row--> <div id="myDropzone" class="dropzone form-control"></div> <!-- end row --> <button type="submit" class="btn btn-primary" id="submit">Submit</button> </form> 
  1. 监听按钮的点击事件,点击后发送数据
    2.1 首先需要禁用自动查找,采用Dropzone.autoDiscover = false
    2.2 取消自动提交,autoProcessQueue : false,
    2.3 文件的名称设置,相当于input标签的name属性,默认是file,注意名称需要和后台一致
    2.4 关闭多文件上传,uploadMultiple: false否则会拿不到文件,这个下面会解释
    2.5 监听按钮点击事件,阻止默认事件,若区域内有文件,则调用myDropzone.processQueue();方法提交,如下图
    2.6 监听sending方法,当文件发送时,将其他表单数据一起发送,如下图

监听按钮点击事件

 $("#submit").on("click", function (e) { 
    e.preventDefault(); e.stopPropagation(); if (myDropzone.getAcceptedFiles().length !== 0) { 
    myDropzone.processQueue(); } }); 

将其他表单数据一起发送

this.on("sending", function (data, xhr, formData) { 
    formData.append("folderName", $("#folderName").val()); formData.append("siteDescription", $("#siteDescription").val()); }); 

下面是完整的js代码

Dropzone.autoDiscover = false; //取消自动提交 var myDropzone = new Dropzone("#myDropzone", { 
    url: "/file/upload", //需要上传的后台接口地址 method:"post", dictDefaultMessage: '拖动文件至此或者点击上传', // 设置默认的提示语句 paramName: "siteFile", // 传到后台的参数名称 autoProcessQueue: false, //关闭自动上传功能,默认会true会自动上传,也就是添加一张图片向服务器发送一次请求 uploadMultiple: false, parallelUploads: 5, maxFiles: 5, maxFilesize: 1, addRemoveLinks: true, dictFallbackMessage: '不好意思,您的浏览器不支持!', //如果浏览器不支持,默认消息将被替换为这个文本。默认为 “Your browser does not support drag'n'drop file uploads.”。 dictInvalidFileType: '该文件不允许上传', //如果文件类型不匹配时显示的错误消息。 dictResponseError: '上传失败,请稍后重试', //如果服务器响应是无效的时候显示的错误消息。 { 
   {statusCode}} ` 将被 替换为服务器端返回的状态码。 init: function () { 
    var submitButton = $("#submit") myDropzone = this; // closure //为上传按钮添加点击事件 submitButton.on("click", function (e) { 
    e.preventDefault(); e.stopPropagation(); if (myDropzone.getAcceptedFiles().length !== 0) { 
    myDropzone.processQueue(); } }); this.on("sending", function (data, xhr, formData) { 
    formData.append("folderName", $("#folderName").val()); formData.append("siteDescription", $("#siteDescription").val()); }); this.on("success", function (file, data) { 
    // 上传成功触发的事件 //弹窗提示 swal("上传成功!", file.name,"success") }); } }); 

这个问题在GitHub上有例子,这也是后来才知道的,具体链接见
文件和表单一起提交(GitHub)

3 多文件上传

问题:多文件上传时文件参数获取不到

3.1 多文件上传时,有几个参数需要提前了解下

 paramName: "siteFile", // 传到后台的参数名称 uploadMultiple: true, //开启多文件上传 parallelUploads: 5, //并行上传文件数量,最大为8 maxFiles: 5, //最大提交文件数量,为null时,则全部提交 maxFilesize: 3, //文件大小,以MB为单位 

3.2 springmvc接受参数配置:

@RequestParam(name = "siteFile") MultipartFile file, 

3.3 提交后,springmvc无法接收到相同文件名的文件,导致文件上传失败,如下图
在这里插入图片描述

解决:详细过程如下

3.4 提示请求错误,然后去找请求的问题,后面发现请求头的Form Data是这样的:
在这里插入图片描述
可以看到,多文件上上传时附带的是两个文件,而且是数组的形式,所以springmvc找不到到名为siteFile的文件,于是报错了

3.5 网上找了一种解决办法,将siteFile改成siteFile[],验证之后,发现还是无法接收到参数

3.6 后来通过修改源代码的形式进行解决,将siteFile[0] siteFile[1]...全改为siteFile,这样后台自然就能接收了,修改如下

return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : ""); 改为 return "" + this.options.paramName + (this.options.uploadMultiple ? "" : ""); 

文件成功上传!
在这里插入图片描述
在这里插入图片描述

这个问题困扰我很久,现在也算是圆满解决了! 

4 文件夹上传

问题:项目要使用文件夹上传功能,dropzone默认是文件上传

解决:如下

4.1 要用到filewebkitdirectory功能(有局限,对部分浏览器如谷歌,兼容)
4.2 在dropzone的init()函数中添加如下代码,开启文件夹选择

 init: function () { 
    this.hiddenFileInput.setAttribute("webkitdirectory", true); } 

4.3 将文件夹中的所有文件上传,需要开启上述的多文件上传功能uploadMultiple: true,同时修改源代码
4.4 后台接收

@RequestParam("siteFiles") List<MultipartFile> files 

5 文件夹上传时路径问题

问题:需要保留原来的目录结构

采用dropzone上传时,获取的文件名不带相对路径,如file/a/b.txt,只能获取到b.txt,无法获取前面的路径。

但是我需要保留原有的文件结构

解决:如下

5.1 第一种方法:当文件发送时,将文件的相对路径一起通过参数的形式,通过formData.append()方法绑定到表单上。
文件的相对路径在File对象的webkitRelativePath中,如下
在这里插入图片描述
将路径存储到数组上:

 init: function () { 
    let webkitdirectorys = [] //定义一个相对路径的数组 this.on("addedfile",function(file){ 
    //每当添加文件时,就给该数组添加路径 webkitdirectorys.push(file.webkitRelativePath) }); this.on("sending", function (data, xhr, formData) { 
    //发送表单时,将路径添加进去 formData.append("webkitdirectorys ", webkitdirectorys ); }); } 

最后,文件路径也保留了,文件也上传成功了。

但是有个缺陷,就是webkitdirectorys中的路径和文件无法一一对应,可能会出问题,同时,文件数量非常多时,表单参数会非常多,可能会降低传输效率?

有强迫症的我不想看到表单传一大堆数据到后台!!! 

5.2 第二种方法,修改源代码

目前网上没有看到类似的处理方式,希望对大家有帮助!

  1. 通过debug可以看到,后台的文件只有两个属性,有一个是name,对应的是前端File对象的name属性,我需要将namewebkitRelativePath替代
  2. dropzone文件上传函数入口processQueue(),进去
myDropzone.processQueue(); 
  1. 找到处理多文件的函数,进去
return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength)); 
  1. 找到提交文件的函数,进去
return this.uploadFiles(files); 
  1. 找到文件发送逻辑
for (i = _m = 0, _ref5 = files.length - 1; 0 <= _ref5 ? _m <= _ref5 : _m >= _ref5; i = 0 <= _ref5 ? ++_m : --_m) { 
    formData.append(this._getParamName(i), files[i], files[i].name); } return xhr.send(formData); 
  1. 发现文件名是通过formData.append()方法进行追加的,修改它的文件名
 for (i = _m = 0, _ref5 = files.length - 1; 0 <= _ref5 ? _m <= _ref5 : _m >= _ref5; i = 0 <= _ref5 ? ++_m : --_m) { 
    //by xinlei //将name用webkitRelativePath替换 let name = files[i].name files[i].webkitRelativePath ? name = files[i].webkitRelativePath: true formData.append(this._getParamName(i), files[i], name); // formData.append(this._getParamName(i), files[i], files[i].name); } return xhr.send(formData); 
  1. 之后通过getOriginalFilename()方法获取的文件名,就是webkitRelativePath了,如file/a/b.txt,之后在进行处理即可!

6 上千个文件上传

问题:dropzone多文件上传最多同时能上传8个文件

注意:当maxFiles:null时,可以上传该文件夹下的所有文件!

若文件超过8个,就无法一次性上传,而需要再次点击提交按钮,才会继续上传剩下的文件。
如果我需要上传大量的文件,不可能每次点击提交按钮!

解决:事件监听

监听success事件,当文件上传成功后,就会调用该事件,
每当有文件上传成功后,就继续调用方法上传队列中的文件,直到队列中的文件为空,如下

 this.on("success", function (file,data){ 
    if (myDropzone.getQueuedFiles().length !== 0) { 
    myDropzone.processQueue(); }else { 
    swal("上传成功!", file.name, "success") } }) 

测试时成功的!

7 多文件删除

选择了文件夹下的所有文件,不可能一个个删除,现需要一个按钮来将区域内的文件全部清除,如下

//为删除按钮添加事件 removeButton.on("click", function(){ 
    myDropzone.getAcceptedFiles().forEach(element => { 
    myDropzone.removeFile(element) }) myDropzone.hiddenFileInput.setAttribute("webkitdirectory", true); }); 

注意当文件清除完成后,控件中的webkitdirectory属性会消失,需要重新添加!

8 总结

1. 本来以为能够轻松解决的问题,却花费了我两天的时间,还是值得纪念一下的 2. 当然也收获很多,最大的收获就是问题解决后的开心 3. 同时也明白了太多地方的不足,以及面对问题缺乏冷静的思考能力 4. 加油 

9 最后

贴一下公众号吧!欢迎关注! 

你好

今天的文章
springmvc接收文件和参数_springmvc接收文件和参数分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/80131.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注