Web大文件分片上传Web环境中大文件上传不能再用form表单一次上传了,这样效率太低;我在不断尝试SpringMVC环境下分片接受文件,最终失败;原因目测是SpringMVC、Struts 框架是不支持HTML5方式上传的(这类框架只能支持Form表单方式的文件上传,或者FLash)那我们可以使用Servlet和SpringMVC结合集成方式实现大文件分片上传;一、来看看我们的web.xml的配置很明显两个servlet,上面一个配置的是SpringMVC的入口,下面servlet是视频上传;他们俩的url-pattern不能冲突;二、先来看看WebUploader的前端代码以下是代码:<%@page language="java"contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC"-//W3C//DTD HTML 4.01Transitional//EN""/TR/html4/loose.dtd"><html><head><basehref="${pageContext.request.scheme}://${pageContext.request.serve rName}:${pageContext.request.serverPort}${pageContext.request.context Path}/"><script type="text/javascript"src="webuploader/jquery-1.7.2.js"></scri pt><script type="text/javascript"src="webuploader/webuploader.min.js"></s cript><link href="webuploader/webuploader.css"type="css/text"/></head><body><h2>Hello World!</h2><div id="thelist"class="uploader-list"></div><div style="margin: 20px 20px 20px 0;"><div id="picker"class="form-control-focus">选择文件</div> </div><button id="btnSync"type="button"class="btn btn-warning">开始同步</button><script>var uploader = WebUploader.create({// swf文件路径swf : 'webuploader/Uploader.swf',// 文件接收服务端。
server : 'UploadVideoServlet',// 选择文件的按钮。
可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.pick : '#picker',threads:2,chunked: true, //分片处理chunkSize: 5 * 1024 * 1024, //每片5Mthreads:1,//上传并发数。
允许同时最大上传进程数。
// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!resize : false});// 当有文件被添加进队列的时候uploader.on('fileQueued', function(file) {//alert(123);$("#thelist").append('<div id="' + file.id + '" class="item">'+ '<h4 class="info">' + + '</h4>'+ '<p class="state">等待上传...</p>' +'</div>');});uploader.on('uploadSuccess', function(file) {alert(uploader.options.formData.guid);alert(Math.ceil(file.size/(5*1024*1024)));alert();$('#' + file.id).find('p.state').text('已上传');$.post("UploadSuccessServlet", { "guid":uploader.options.formData.guid,chunks:Math.ceil(file.size/(5*1024*102 4)),fileName:},function(data){}, "json");});uploader.on('uploadError', function(file) {$('#' + file.id).find('p.state').text('上传出错');});uploader.on('uploadComplete', function(file) {$('#' + file.id).find('.progress').fadeOut();});$("#btnSync").on('click', function() {if ($(this).hasClass('disabled')) {returnfalse;}uploader.options.formData.guid = Math.random();uploader.upload();});</script></body></html>三、servlet分片获取分片就是前段将文件分成多个,每片都是一个post请求,有多少片就请求多少次servlet;我们以获取的guid为文件名建立临时文件夹,以chunk(片序号)为文件名来存储文件;以下为代码:package com.airodlcx;import java.io.File;import java.io.IOException;import ng.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 mons.beanutils.BeanUtils;import mons.fileupload.FileItem;import mons.fileupload.FileUploadException; import mons.fileupload.disk.DiskFileItemFactory; import mons.fileupload.servlet.ServletFileUpload; import mons.io.FileUtils;/*** Servlet implementation class UploadVideo*/public class UploadVideoServlet extends HttpServlet {private static final long serialVersionUID = 1L;/*** @see HttpServlet#HttpServlet()*/public UploadVideoServlet() {super();// TODO Auto-generated constructor stub}/*** @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse* response)*/protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// TODO Auto-generated method stubresponse.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)) {return;}// 4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项List<FileItem> list = null;try {list = upload.parseRequest(request);} catch (FileUploadException e) {e.printStackTrace();}HashMap<String, String> map = new HashMap<String, String>();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()) {fileParent.mkdir();}String filename = item.getName();if (filename == null || filename.trim().equals("")) {continue;}// 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:// c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt// 处理获取到的上传文件的文件名的路径部分,只保留文件名部分filename = filename.substring(stIndexOf("\\") + 1);//创建文件File file;if (map.get("chunks") != null) {file = new File(fileParent, map.get("chunk"));} else {file = new File(fileParent, "0");}//copyFileUtils.copyInputStreamToFile(item.getInputStream(), file);}}}}四、前端WebUploader上传完毕触发uploadSuccess事件uploader.on('uploadSuccess', function(file) {alert(uploader.options.formData.guid);alert(Math.ceil(file.size/(5*1024*1024)));alert();$('#' + file.id).find('p.state').text('已上传');$.post("UploadSuccessServlet", { "guid":uploader.options.formData.guid,chunks:Math.ceil(file.size/(5*1024*102 4)),fileName:},function(data){}, "json");});请求servlet去合并之前的guid文件夹下的分片文件,post请求中的分片数量可以用来校验,获取的分片是否正确,也可以前端传递md5,后台校验;五、后台获取的log图:上传的GUID命名的文件夹图:文件夹下的分片文件每个分割线包住的地方是一个servlet请求,最后在success请求的servlet是进行文件校验并合并文件即可;代码见下:六、java文件合并代码见下:protectedvoid doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String path =request.getSession().getServletContext().getRealPath("/upload");String guid = request.getParameter("guid");int chunks = Integer.parseInt(request.getParameter("chunks"));String fileName = request.getParameter("fileName");System.out.println("start...!guid="+guid+";chunks="+chunks+";file Name="+fileName);/*** 进行文件合并*/File file = new File(path+"/"+guid);/*** 判断分片数量是否正确*/if(file.list().length != chunks){return;}new File("F://upload"+"/"+guid).mkdir();/*** 进行文件合并*/File newFile = new File("F://upload"+"/"+guid+"/"+fileName);FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加写入byte[] byt = newbyte[10*1024*1024];int len;FileInputStream temp = null;//分片文件for(int i = 0 ; i<chunks ; i++){temp = new FileInputStream(new File(path+"/"+guid+"/"+i));while((len = temp.read(byt))!=-1){System.out.println(len);outputStream.write(byt, 0, len);}}/*** 当所有追加写入都写完才可以关闭流*/outputStream.close();temp.close();System.out.println("success!guid="+guid+";chunks="+chunks+";fileN ame="+fileName);}文件夹以guid命名,数据库储存guid的名字,后期数据移动,只需要更改前端显示的路径;在这里up遇到一个问题,上传报错:IOException:磁盘空间不足;然而我上传的磁盘还有20G;原因是系统盘空间不足;up重装系统就好了;注:1、进度条的显示就很容易了引入bootstrap的进度条<div class="progress"><div id="progress"class="progress-bar"role="progressbar"aria-value now="60"aria-valuemin="0"aria-valuemax="100"style="width: 0%;"> <span class="sr-only">60% Complete</span></div></div>2.添加uploadProgress事件监听uploader.on('uploadProgress', function(file,percentage) { $("#progress").css("width",parseInt(percentage*100)+"%");});percentage:当前上传的进度,小数,数值为1是上传完毕;效果如下:PS:UI简陋还请见谅!如果使用过程有问题,可以骚然我,QQ:346640094,Email:lcx1995@;。