Web环境中大文件上传不能再用form表单一次上传了,这样效率太低;
我在不断尝试SpringMVC环境下分片接受文件,最终失败;原因目测是 SpringMVC、Struts
框架是不支持HTML5方式上传的(这类框架只能支持Form表单方式的文件上传,或者FLash)
那我们可以使用Servlet和SpringMVC结合集成方式实现大文件分片上传;
一、来看看我们的web.xml的配置
很明显两个servlet,上面一个配置的是SpringMVC的入口,下面servlet是视频上传; 他们俩的url-pattern不能冲突;
二、先来看看WebUploader的前端代码
以下是代码:
<%@pagelanguage=\"java\"contentType=\"text/html; charset=UTF-8\"
pageEncoding=\"UTF-8\"%>
Transitional//EN\"\"http://www.w3.org/TR/html4/loose.dtd\">
Hello World!
// swf文件路径 swf : 'webuploader/Uploader.swf', // 文件接收服务端。 server : 'UploadVideoServlet', // 选择文件的按钮。可选。 // 内部根据当前运行是创建,可能是input元素,也可能是flash. pick : '#picker', threads:2, chunked: true, //分片处理 $(\"#btnSync\").on('click', function() { if ($(this).hasClass('disabled')) { } uploader.options.formData.guid = Math.random(); uploader.upload(); returnfalse; uploader.on('uploadComplete', function(file) { $('#' + file.id).find('.progress').fadeOut(); }); uploader.on('uploadError', function(file) { $('#' + file.id).find('p.state').text('上传出错'); function(data){ }, \"json\"); }); }); 三、servlet分片获取 分片就是前段将文件分成多个,每片都是一个post请求,有多少片就请求多少次servlet; 我们以获取的guid为文件名 建立临时文件夹,以chunk(片序号)为文件名来存储文件; 以下为代码: package com.airodlcx; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FileUtils; /** * Servlet implementation class UploadVideo */ public class UploadVideoServlet extends HttpServlet { /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) } throws ServletException, IOException { /** * @see HttpServlet#HttpServlet() */ public UploadVideoServlet() { } super(); // TODO Auto-generated constructor stub private static final long serialVersionUID = 1L; // TODO Auto-generated method stub response.getWriter().append(\"Served at: \").append(request.getContextPath()); /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String path = request.getSession().getServletContext().getRealPath(\"/upload\"); System.out.println(path); DiskFileItemFactory factory = new DiskFileItemFactory(); // 2、创建一个文件上传解析器 ServletFileUpload upload = new ServletFileUpload(factory); // 解决上传文件名的中文乱码 upload.setHeaderEncoding(\"UTF-8\"); // 3、判断提交上来的数据是否是上传表单的数据 if (!ServletFileUpload.isMultipartContent(request)) { } // 4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个 return; List List list = upload.parseRequest(request); } catch (FileUploadException e) { } e.printStackTrace(); HashMap System.out.println(\"-------------------------------------------------------------\"); for (FileItem item : list) { if (item.isFormField()) { /** * 表单数据 */ String name = item.getFieldName(); // 解决普通输入项的数据的中文乱码问题 String value = item.getString(\"UTF-8\"); // value = new String(value.getBytes(\"iso8859-1\"),\"UTF-8\"); System.out.println(name + \"=\" + value); map.put(name, value);// 放入map集合 } else { /** * 文件上传 */ File fileParent = new File(path + \"/\" + map.get(\"guid\"));//以guid创建临时 文件夹 System.out.println(fileParent.getPath()); if (!fileParent.exists()) { } String filename = item.getName(); if (filename == null || filename.trim().equals(\"\")) { } // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来 continue; fileParent.mkdir(); 的文件名是带有路径的,如: //创建文件 File file; // c:\\a\\b\\1.txt,而有些只是单纯的文件名,如:1.txt // 处理获取到的上传文件的文件名的路径部分,只保留文件名部分 filename = filename.substring(filename.lastIndexOf(\"\\\\\") + 1); } } } } if (map.get(\"chunks\") != null) { file = new File(fileParent, map.get(\"chunk\")); } else { } //copy FileUtils.copyInputStreamToFile(item.getInputStream(), file); file = new File(fileParent, \"0\"); 四、前端WebUploader上传完毕触发uploadSuccess事件 uploader.on('uploadSuccess', function(file) { alert(uploader.options.formData.guid); alert(Math.ceil(file.size/(5*1024*1024))); alert(file.name); $('#' + file.id).find('p.state').text('已上传'); $.post(\"UploadSuccessServlet\", { \"guid\": uploader.options.formData.guid,chunks:Math.ceil(file.size/(5*1024*1024)),fileName:file.name}, 请求servlet去合并之前的guid文件夹下的分片文件,post请求中的分片数量可以用来校 function(data){ }, \"json\"); }); 验,获取的分片是否正确,也可以前端传递md5,后台校验; 五、后台获取的log 图:上传的GUID命名的文件夹 图:文件夹下的分片文件 每个分割线包住的地方是一个servlet请求,最后在success请求的servlet是进行文件校验并合并文件即可;代码见下: 六、java文件合并 代码见下: protectedvoid doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println(\"start...!guid=\"+guid+\";chunks=\"+chunks+\";file /** * 进行文件合并 */ File file = new File(path+\"/\"+guid); /** * 判断分片数量是否正确 */ if(file.list().length != chunks){ } return; Name=\"+fileName); String guid = request.getParameter(\"guid\"); intchunks = Integer.parseInt(request.getParameter(\"chunks\")); String fileName = request.getParameter(\"fileName\"); String path = request.getSession().getServletContext().getRealPath(\"/upload\"); new File(\"F://upload\"+\"/\"+guid).mkdir(); /** * 进行文件合并 */ File newFile = new File(\"F://upload\"+\"/\"+guid+\"/\"+fileName); FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加写入 文件夹以guid命名,数据库储存guid的名字,后期数据移动,只需要更改前端显示的路径; 在这里up遇到一个问题,上传报错:IOException:磁盘空间不足;然而我上传的磁盘还有20G;原因是系统盘空间不足;up重装系统就好了; 注: 1、进度条的显示就很容易了 System.out.println(\"success!guid=\"+guid+\";chunks=\"+chunks+\";fileN} ame=\"+fileName); byte[] byt = newbyte[10*1024*1024]; intlen; FileInputStream temp = null;//分片文件 for(inti = 0 ; i outputStream.close(); temp.close(); temp = new FileInputStream(new File(path+\"/\"+guid+\"/\"+i)); while((len = temp.read(byt))!=-1){ } System.out.println(len); outputStream.write(byt, 0, len); 引入bootstrap的进度条
now=\"60\"aria-valuemin=\"0\"aria-valuemax=\"100\"style=\"width: 0%;\">
2.添加uploadProgress事件监听
uploader.on('uploadProgress', function(file,percentage) {
$(\"#progress\").css(\"width\",parseInt(percentage*100)+\"%\"); });
percentage:当前上传的进度,小数,数值为1是上传完毕; 效果如下:
PS:UI简陋还请见谅!
如果使用过程有问题,可以骚然我,QQ:3460094,Email:lcx1995@foxmail.com;
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- xiaozhentang.com 版权所有 湘ICP备2023022495号-4
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务