spring boot:单文件上传/多文件上传/表单中多个文件域上传(spring boot 2.3.2)
一,表单中有多个文件域时如何实现说明和文件的对应?
1,说明和文件对应
文件上传页面中,如果有多个文件域又有多个相对应的文件说明时,
文件和说明如何对应?
我们在表单中给对应的file变量和text变量加上相同的数字即可
在演示项目中使用了一个动态添加文件说明和文件域的页面,
供大家参考
2,spring boot的文件上传要注意的地方:
需要修改spring boot的配置文件,
指定允许上传的文件大小,
指定连接的超时时间,避免文件太大时上传超时
如果接入层使用了nginx,则nginx也要做相应配置
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/24/springboot-dan-wen-jian-shang-chuan-duo-wen-jian-shang-chuan-biao-dan-zhong-duo-ge-wen-jian-yu/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,演示项目相关信息
1,项目地址:
https://github.com/liuhongdi/fileupload
2,功能说明:
分别演示了:单文件上传,
多文件上传
同一个表单中有多个文件域时的上传
3,项目结构:如图:
三,配置文件说明
1,application.properties
#thymeleaf spring.thymeleaf.cache=false spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.mode=HTML spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html #upload spring.servlet.multipart.maxFileSize=10MB spring.servlet.multipart.maxRequestSize=30MB #tomcat, server.tomcat.connection-timeout=20000 server.tomcat.max-http-form-post-size=30MB #error server.error.include-stacktrace=always #errorlog logging.level.org.springframework.web=trace
说明:
spring.servlet.multipart.maxFileSize=10MB //单个文件最大的size
spring.servlet.multipart.maxRequestSize=30MB //整个表单中上传文件一共最大的size
#tomcat,
server.tomcat.connection-timeout=20000 //tomcat的连接超时时间,注意不能太短,我们在这里使用20秒
server.tomcat.max-http-form-post-size=30MB //tomcat的表单最大post的文件大小
四,java文件说明
1,FileController.java
@Controller @RequestMapping("/file") public class FileController { //文件的保存路径 private final static String FILE_BASE_PATH = "/data/file/html"; //多文件域上传页面 @GetMapping("/uploadadd") public String uploadAdd(ModelMap modelMap) { return "image/uploadadd"; } //处理多个文件域的表单上传 @PostMapping("/uploadadded") @ResponseBody public RestResult uploadadded(@RequestParam Map<String,String> params,HttpServletRequest request) { RestResult res = new RestResult(); int num = Integer.parseInt(params.get("num")); //打印文件域的名字,供调试用 Iterator<String> it = ((MultipartHttpServletRequest)request).getFileNames(); while (it.hasNext()) { String uploadFile = it.next(); System.out.println("filename:"+uploadFile); } //根据表单中文件元素的数量遍历 for (int i=1;i<=num;i++) { //text String curText = params.get("text"+i); System.out.println("text:"+curText); //file MultipartFile curFile = ((MultipartHttpServletRequest)request).getFile("file"+i); if (curFile.isEmpty()) { continue; } //System.out.println("text:"+curText); String fileName = curFile.getOriginalFilename(); System.out.println("文件名: " + fileName); // 文件后缀 int lastDot = fileName.lastIndexOf("."); lastDot++; String fileType = fileName.substring(lastDot); // 重新生成唯一文件名,用于存储数据库 String fileSn = UUID.randomUUID().toString(); Map<String, String> map2 = new HashMap<String, String>(); String destFilePath = FILE_BASE_PATH+"/"+fileSn+"."+fileType; File dest = new File(destFilePath); try { curFile.transferTo(dest); } catch (IOException e) { System.out.println("save ioexception"); e.printStackTrace(); } } return res.success(0,"上传成功"); } //单文件/多文件上传页面 @GetMapping("/upload") public String upload(ModelMap modelMap) { return "image/upload"; } //处理单文件/多文件上传 @PostMapping("/uploaded") @ResponseBody public RestResult uploaded(HttpServletRequest request) { RestResult res = new RestResult(); List<MultipartFile> list = ((MultipartHttpServletRequest)request).getFiles("files"); for (MultipartFile multipartFile : list) { if (list.isEmpty()) { continue; } // 文件名 String fileName = multipartFile.getOriginalFilename(); System.out.println("文件名: " + fileName); // 文件后缀 int lastDot = fileName.lastIndexOf("."); lastDot++; String fileType = fileName.substring(lastDot); // 重新生成唯一文件名,用于存储数据库 String fileSn = UUID.randomUUID().toString(); Map<String, String> map2 = new HashMap<String, String>(); String destFilePath = FILE_BASE_PATH+"/"+fileSn+"."+fileType; File dest = new File(destFilePath); try { multipartFile.transferTo(dest); } catch (IOException e) { System.out.println("save ioexception"); e.printStackTrace(); return res.error(0,"上传失败"); } } return res.success(0,"上传成功"); } }
说明:多个文件域上传时,主要是把file变量和text变量做对应
2,RestResult.java
//api通用返回数据 public class RestResult<T> { //uuid,用作唯一标识符,供序列化和反序列化时检测是否一致 private static final long serialVersionUID = 7498483649536881777L; //标识代码,0表示成功,非0表示出错 private Integer code; //提示信息,通常供报错时使用 private String msg; //正常返回时返回的数据 private T data; //constructor public RestResult() { } //constructor public RestResult(Integer status, String msg, T data) { this.code = status; this.msg = msg; this.data = data; } //返回成功数据 public RestResult success(T data) { return new RestResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMsg(), data); } public static RestResult success(Integer code,String msg) { return new RestResult(code, msg, null); } //返回出错数据 public static RestResult error(ResponseCode code) { return new RestResult(code.getCode(), code.getMsg(), null); } public static RestResult error(Integer code,String msg) { return new RestResult(code, msg, null); } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
五,html文件说明
1,upload.html
<html lang="en"> <head> <script type="text/javascript" language="JavaScript" src="/js/jquery-1.6.2.min.js"></script> </head> <body> <div style="width:100%;height:20px;background:#ffffff;font-size: 16px;" ></div> <div id="content" style="width:800px;"> <div style="width:800px;float:left;"> <!--====================main begin=====================--> <div style="width:260px;height:200px;float:left;background: #eeeeee;padding-left: 10px;padding-top: 10px;"> 单文件上传<br/> 说明:不能多选<br/> <input id="fileone" type="file" name="fileone" /><br/><br/> <input type="button" name="go" value="单文件上传" onclick="go_single_add()" /> </div> <div style="width:380px;height:200px;float:left;margin-left:20px;background: #eeeeee;padding-left: 10px;padding-top: 10px;"> 多文件上传<br/> 说明:可以多选<br/> <input id="files" type="file" name="files" multiple /><br/><br/> <input type="button" name="go" value="多文件上传" onclick="go_multi_add()" /> </div> <!--====================main end=====================--> </div> </div> <script> //单文件上传 function go_single_add(){ //把表单中选中的文件添加到postdata var postdata=new FormData(); if ($("#fileone")[0]==null || $("#fileone")[0].files.length<1){ alert("未选中图片") return false } for (var i=0;i<$("#fileone")[0].files.length;i++){ postdata.append("files",$("#fileone")[0].files[i]) } $.ajax({ type:"POST", url:"/file/uploaded", data:postdata, //返回数据的格式 datatype: "json",//"xml", "html", "script", "json", "jsonp", "text". processData: false, contentType: false, //成功返回之后调用的函数 success:function(data){ if (data.code == 0) { alert('上传成功:'+data.msg); //window.location.href="/image/imagelist"; } else { alert("上传失败:"+data.msg); } }, //调用执行后调用的函数 complete: function(XMLHttpRequest, textStatus){ }, //调用出错执行的函数 error: function(XMLHttpRequest, textStatus, errorThrown){ alert(XMLHttpRequest.readyState + XMLHttpRequest.status + XMLHttpRequest.responseText); } }); } //多文件上传 function go_multi_add(){ //把表单中选中的文件添加到postdata var postdata=new FormData(); if ($("#files")[0]==null || $("#files")[0].files.length<1){ alert("未选中图片") return false } for (var i=0;i<$("#files")[0].files.length;i++){ postdata.append("files",$("#files")[0].files[i]) } $.ajax({ type:"POST", url:"/file/uploaded", data:postdata, //返回数据的格式 datatype: "json",//"xml", "html", "script", "json", "jsonp", "text". processData: false, contentType: false, //成功返回之后调用的函数 success:function(data){ if (data.code == 0) { alert('上传成功:'+data.msg); //window.location.href="/image/imagelist"; } else { alert("上传失败:"+data.msg); } }, //调用执行后调用的函数 complete: function(XMLHttpRequest, textStatus){ }, //调用出错执行的函数 error: function(XMLHttpRequest, textStatus, errorThrown){ alert(XMLHttpRequest.readyState + XMLHttpRequest.status + XMLHttpRequest.responseText); } }); } </script> </body> </html>
这个页面上同时展示了单文件上传和多文件上传
2,uploadadd.html
<html lang="en"> <head> <script type="text/javascript" language="JavaScript" src="/js/jquery-1.6.2.min.js"></script> </head> <body> <div style="width:100%;height:20px;background:#ffffff;font-size: 16px;" ></div> <div id="content" style="width:800px;"> <div style="width:800px;float:left;"> <!--====================main begin=====================--> <div style="width:280px;float:left;background: #eeeeee;padding-left: 10px;padding-top: 10px;"> 单文件上传<br/> 说明:不能多选<br/> <form id="form_add" method="POST" action="" enctype="multipart/form-data"> <div id="filelist" style="width: 260px;"> <div style="width:260px;height:50px;background: #ffff00;padding:2px 5px;"> <input type="text" style="width:200px;" name="text1" placeholder="文件说明"/><br/> <input id="file1" type="file" name="file1" /> </div> </div> </form> <input type="button" name="gofile" value="追加文件" onclick="go_add()" /><br/><br/> <input type="button" name="goupload" value="提交" onclick="go_commit()" /> </div> <!--====================main end=====================--> </div> </div> <script> //最大上传文件数量 var global_file_max = 10; //当前表单中的file数量 var global_file_num = 1; //提交动态生成元素的表单 function go_commit() { var postdata = new FormData($("#form_add")[0]); //附加上文件表单元素的数量 postdata.append("num",global_file_num); $.ajax({ type:"POST", url:"/file/uploadadded", data:postdata, //返回数据的格式 datatype: "json",//"xml", "html", "script", "json", "jsonp", "text". processData: false, contentType: false, //成功返回之后调用的函数 success:function(data){ if (data.code == 0) { alert("success:"+data.msg); } else { alert("failed:"+data.msg); } }, //调用执行后调用的函数 complete: function(XMLHttpRequest, textStatus){ }, //调用出错执行的函数 error: function(XMLHttpRequest, textStatus, errorThrown){ alert(XMLHttpRequest.readyState + XMLHttpRequest.status + XMLHttpRequest.responseText); } }); } //添加一个文件表单元素 function go_add() { var divcss = { "background-color": "#ff0000", "width":"260px", "height":"50px", "padding":"2px 5px" }; if (global_file_num>=global_file_max) { alert('已超过上传文件的数量限制'); return false; } global_file_num++; var parentdiv=$('<div></div>'); //创建一个div parentdiv.attr('id','filediv'+global_file_num); parentdiv.css(divcss); //添加css样式 var divhtml = '<input type="text" style="width:200px;" name="text'+global_file_num+'" placeholder="文件说明"/><br/>' + '<input id="file'+global_file_num+'" type="file" name="file'+global_file_num+'" />'; parentdiv.html(divhtml); $("#filelist").append(parentdiv); } </script> </body> </html>
演示了用jquery动态添加file元素和text元素
六,测试效果
1,访问:
http://127.0.0.1:8080/file/upload
分别测试单文件上传和多文件上传:
在文件管理器中查看已上传的文件:
2,测试表单中包含多个文件域的上传:
访问:
http://127.0.0.1:8080/file/uploadadd
点击 追加文件,添加两个file
测试提交后,查看控制台:
filename:file1
filename:file2
filename:file3
text:aaaa
文件名: qtz.jpg
text:bbbb
文件名: qtz2.jpeg
text:ccc
文件名: yellowbee.jpeg
文件名和text说明的对应没有问题
七,查看spring boot的版本
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.2.RELEASE)