300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > WebUploader 实现大文件的断点续传功能

WebUploader 实现大文件的断点续传功能

时间:2020-02-28 15:55:47

相关推荐

WebUploader 实现大文件的断点续传功能

断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个片段进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。用户可以节省时间,提高速度。

本文采用WebUploader插件实现对大文件进行唯一标识,并分块进行上传。

1、CheckChumServlet 进行文件唯一标识的判断,是否已经上传过;

2、UploadVideoServlet 文件的分块上传;

3、UploadSuccessServlet 对分块的文件进行合并。

index.jsp

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "/TR/html4/loose.dtd"><html><head><title>视频文件上传</title><basehref="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/"><script type="text/javascript" src="webuploader/jquery-1.7.2.js"></script><script type="text/javascript" src="webuploader/webuploader.min.js"></script><link href="webuploader/webuploader.css" type="css/text" /></head><body><h2 >视频文件上传</h2><div style="margin: 20px 20px 20px 0;"><div id="picker" class="form-control-focus" >选择文件</div></div><div id="thelist" class="uploader-list"></div><button id="btnSync" type="button" class="btn btn-warning">开始上传</button><div class="progress"><div id="progress" class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"><span class="sr-only"></span></div></div><script>_extensions ='3gp,mp4,rmvb,mov,avi,m4v,qlv,wmv';_mimeTypes ='video/*,audio/*,application/*';var fileMd5; //文件唯一标识 /******************下面的参数是自定义的*************************/ var fileId;//文件IDvar fileName;//文件名称 var oldJindu;//如果该文件之前上传过 已经上传的进度是多少 var count=0;//当前正在上传的文件在数组中的下标,一次上传多个文件时使用 var filesArr=new Array();//文件数组:每当有文件被添加进队列的时候 就push到数组中 var map={};//key存储文件id,value存储该文件上传过的进度 //监听分块上传的三种状态WebUploader.Uploader.register({ "before-send-file":"beforeSendFile",//整个文件上传前 "before-send":"beforeSend", //每个分片上传前 "after-send-file":"afterSendFile", //分片上传完毕 }, { //所有分块进行上传之前调用此函数 beforeSendFile:function(file){ //alert('分块上传前调用的函数');var deferred = WebUploader.Deferred(); //1、计算文件的唯一标记fileMd5,用于断点续传 如果.md5File(file)方法里只写一个file参数则计算MD5值会很慢 所以加了后面的参数:5*1024*1024 (new WebUploader.Uploader()).md5File(file,0,5*1024*1024).progress(function(percentage){ $('#'+file.id ).find('p.state').text('正在读取文件信息...'); }) .then(function(val){ $('#'+file.id ).find("p.state").text("正在上传..."); fileMd5=val; fileId=file.id;uploader.options.formData.guid = fileMd5;//获取文件信息后进入下一步 deferred.resolve(); }); fileName=file.name; //为自定义参数文件名赋值 return deferred.promise(); }, //如果有分块上传,则每个分块上传之前调用此函数 ,检验该分片是否上传过 beforeSend:function(block){ //alert('-检验分块是否上传-');var deferred = WebUploader.Deferred(); $.ajax({ type:"POST", url:"CheckChumServlet", //ajax验证每一个分片 data:{ fileName : fileName, fileMd5:fileMd5, //文件唯一标记 chunk:block.chunk, //当前分块下标 chunkSize:block.end-block.start,//当前分块大小 guid: uploader.options.formData.guid}, cache: false, async: false, // 与js同步 timeout: 1000, //todo 超时的话,只能认为该分片未上传过 dataType:"json", success:function(response){ if(response.ifExist){$('#'+fileId).find("p.state").text("正在续传..."); //分块存在,跳过 deferred.reject(); }else{//alert("分块文件不完整或没有上传,重新上传")//分块不存在或不完整,重新发送该分块内容 deferred.resolve(); } } }); this.owner.options.formData.fileMd5 = fileMd5; deferred.resolve();//继续执行分片上传return deferred.promise(); }, //所有分块上传成功后调用此函数,通知后台合并所用分块 afterSendFile:function(){ //alert('-所有分块上传完成后调用该函数-');//如果分块上传成功,则通知后台合并分块 $.ajax({ type:"POST", url:"UploadSuccessServlet", //ajax将所有片段合并成整体 data:{ fileName : fileName, fileMd5:fileMd5, }, success:function(){count++; //每上传完成一个文件 count+1 if(count<=filesArr.length-1){ uploader.upload(filesArr[count].id);//上传文件列表中的下一个文件 } //合并成功之后的操作 } }); } }); var uploader = WebUploader.create({// swf文件路径swf : 'webuploader/Uploader.swf',// 文件接收服务端。server : 'UploadVideoServlet',// 选择文件的按钮。可选。// 内部根据当前运行是创建,可能是input元素,也可能是flash.pick : {id:'#picker',multiple: false},accept: {title: 'Videos',extensions: _extensions,mimeTypes: _mimeTypes},chunked: true, //分片处理chunkSize: 5 * 1024 * 1024, //每片5M threads:1,//上传并发数。允许同时最大上传进程数。// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!resize : false});uploader.on("error", function (type) {if (type == "Q_TYPE_DENIED") {alert("请上传mp4、rmvb、mov、avi、m4v、wmv格式文件");} });// 当有文件被添加进队列的时候uploader.on('fileQueued', function(file) {//alert(123);$("#thelist").append('<div id="' + file.id + '" class="item">'+ '<h4 class="info">' + file.name + '</h4>'+ '<p class="file-pro"></p>'+ '<p class="state">等待上传...</p>' + '</div>');});uploader.on('uploadSuccess', function(file) {$('#' + file.id).find('p.state').text('已上传');});uploader.on('uploadError', function(file) {$('#' + file.id).find('p.state').text('上传出错');});uploader.on('uploadComplete', function(file) {$('#' + file.id).find('.progress').fadeOut();});uploader.on( 'beforeFileQueued', function( file ) {// alert(file.size);}); $("#btnSync").on('click', function() {if ($(this).hasClass('disabled')) {return false;}//显示遮罩层操作//视频上传uploader.upload();});// 文件上传过程中创建进度条实时显示uploader.on( 'uploadProgress', function( file, percentage ) {$("td.file-pro").text("");var $li = $( '#'+file.id ).find('.file-pro'),$percent = $li.find('.file-progress .progress-bar');// 避免重复创建if ( !$percent.length ) {$percent = $('<div class="file-progress progress-striped active">' +'<div class="progress-bar" role="progressbar" style="width: 0%">' +'</div>' +'</div>' + '<br/><div class="per">0%</div>').appendTo( $li ).find('.progress-bar');}$li.siblings('.file-status').text('上传中');$li.find('.per').text((percentage * 100).toFixed(2) + '%');$percent.css( 'width', percentage * 100 + '%' );});// 所有文件上传成功后调用 uploader.on('uploadFinished', function () {//隐藏遮罩层操作}); /*关闭上传框窗口后恢复上传框初始状态*/$('#picker').on('click',function(){// 移除所有并将上传文件移出上传序列for (var i = 0; i < uploader.getFiles().length; i++) {// 将文件从上传序列移除uploader.removeFile(uploader.getFiles()[i]);$("#"+uploader.getFiles()[i].id).remove();}// 重置uploaderuploader.reset();})</script></body></html>

CheckChumServlet

package com.uploader;import java.io.File;import java.io.FileOutputStream;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 mons.fileupload.FileItem;import mons.fileupload.FileUploadException;import mons.fileupload.disk.DiskFileItemFactory;import mons.fileupload.servlet.ServletFileUpload;import mons.io.FileUtils;/*** 分片上传文件处理类*/public class CheckChumServlet extends HttpServlet {private static final long serialVersionUID = 1L;public CheckChumServlet() {super();}protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getWriter().append("Served at: ").append(request.getContextPath());}protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取分块传文件的相关信息String chunk = request.getParameter("chunk");String chunkSize = request.getParameter("chunkSize");String guid = request.getParameter("guid");//String fileName = request.getParameter("fileName");//String fileMd5 = request.getParameter("fileMd5");// 获取分块文件临时存储的路径并新建该分块文件String path = request.getSession().getServletContext().getRealPath("/upload");File checkFile = new File(path + "/" + guid + "/" + chunk);// 设置响应编码为utf-8response.setContentType("text/html;charset=utf-8");// 检查文件是否存在,且大小是否一致if (checkFile.exists() && checkFile.length() == Integer.parseInt(chunkSize)) {// 上传过 将结果返回给前段处理try {response.getWriter().write("{\"ifExist\":1}");// System.out.println("分块文件已经存在");} catch (IOException e) {e.printStackTrace();}} else {// 没有上传过 返回给前段做处理try {response.getWriter().write("{\"ifExist\":0}");} catch (IOException e) {e.printStackTrace();}}}}

UploadVideoServlet

package com.uploader;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.List;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import mons.fileupload.FileItem;import mons.fileupload.FileUploadException;import mons.fileupload.disk.DiskFileItemFactory;import mons.fileupload.servlet.ServletFileUpload;import mons.io.FileUtils;/*** 接受上传文件的servlet*/public class UploadVideoServlet extends HttpServlet {private static final long serialVersionUID = 1L;/*** 该类的无参构造方法*/public UploadVideoServlet() {super();}protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getWriter().append("Served at: ").append(request.getContextPath());}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.setFileSizeMax(15 * 1024 * 1024L);// 设置整个request的最大内存upload.setSizeMax(15 * 1024 * 1024L);// 解决上传文件名的中文乱码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>();for (FileItem item : list) {if (item.isFormField()) {String name = item.getFieldName();// 解决输入项的数据的中文乱码问题String value = item.getString("UTF-8");map.put(name, value);// 放入map集合} else {File fileParent = new File(path + "/" + map.get("guid"));// 以guid创建临时文件夹if (!fileParent.exists()) {fileParent.mkdirs();}String filename = item.getName();if (filename == null || filename.trim().equals("")) {continue;}// 处理获取到的上传文件的文件名的路径部分,只保留文件名部分filename = filename.substring(filename.lastIndexOf("\\") + 1);// 创建文件File file;// 以chunks分块文件的下标作为上传文件的名字if (map.get("chunks") != null) {file = new File(fileParent, map.get("chunk"));} else {file = new File(fileParent, "0");}// 将分块文件写入到该文件中InputStream in = null;FileOutputStream out = null;byte[] byt = new byte[5 * 1024 * 1024];try {in = item.getInputStream();out = new FileOutputStream(file);int len;while ((len = in.read(byt)) != -1) {out.write(byt, 0, len);}} catch (Exception e) {throw new RuntimeException("写入失败");} finally {try {in.close();} catch (Exception e2) {throw new RuntimeException("关闭流失败");}try {out.close();} catch (Exception e2) {throw new RuntimeException("关闭流失败");}}}}}}

UploadSuccessServlet

package com.uploader;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.util.Arrays;import java.util.Collections;import parator;import java.util.List;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;//文件合并类public class UploadSuccessServlet extends HttpServlet {private static final long serialVersionUID = 1L;/*** 该类的无参构造方法*/public UploadSuccessServlet() {super();}protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getWriter().append("Served at: ").append(request.getContextPath());}/*** 上传成功后的业务处理*/protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取上传路径String path = request.getSession().getServletContext().getRealPath("/upload");// 获取guid参数String guid = request.getParameter("fileMd5");// 获取文件名字String fileName = request.getParameter("fileName");// System.out.println("开始合并。。。文件唯一表示符="+guid+";文件名字="+fileName);// 创建保存文件的文件夹new File("D:/XALC/DP/LianYunGangDaShuJuDP1031-1/App_Uploads" + "/" + guid).mkdirs();// 进行文件合并File newFile = new File("D:/XALC/DP/LianYunGangDaShuJuDP1031-1/App_Uploads" + "/" + guid + "/" + fileName);FileInputStream temp = null;FileOutputStream outputStream = null;List<File> files = null;File dir = null;dir = new File(path + "/" + guid);File[] childs = dir.listFiles();files = Arrays.asList(childs);Collections.sort(files, new Comparator<File>() {@Overridepublic int compare(File o1, File o2) {int o1Num = Integer.parseInt(o1.getName());int o2Num = Integer.parseInt(o2.getName());return o1Num - o2Num;}});try {int len;byte[] byt = new byte[5 * 1024 * 1024];outputStream = new FileOutputStream(newFile, true);// 文件追加写入for (int i = 0; i < files.size(); i++) {temp = new FileInputStream(files.get(i));while ((len = temp.read(byt)) != -1) {outputStream.write(byt, 0, len);}temp.close();temp = null;}} catch (IOException e) {throw new RuntimeException("合并文件失败");} finally {if (temp != null) {temp.close();}outputStream.close();}for (int i = 0; i < files.size(); i++) {//删除临时文件files.get(i).delete();}//删除临时文件夹dir.delete();}}

web.xml中注册servlet:

<servlet><description></description><display-name>UploadVideoServlet</display-name><servlet-name>UploadVideoServlet</servlet-name><servlet-class>com.uploader.UploadVideoServlet</servlet-class></servlet><servlet-mapping><servlet-name>UploadVideoServlet</servlet-name><url-pattern>/UploadVideoServlet</url-pattern></servlet-mapping><servlet><description></description><display-name>UploadSuccessServlet</display-name><servlet-name>UploadSuccessServlet</servlet-name><servlet-class>com.uploader.UploadSuccessServlet</servlet-class></servlet><servlet-mapping><servlet-name>UploadSuccessServlet</servlet-name><url-pattern>/UploadSuccessServlet</url-pattern></servlet-mapping><servlet><description></description><display-name>CheckChumServlet</display-name><servlet-name>CheckChumServlet</servlet-name><servlet-class>com.uploader.CheckChumServlet</servlet-class></servlet><servlet-mapping><servlet-name>CheckChumServlet</servlet-name><url-pattern>/CheckChumServlet</url-pattern></servlet-mapping>

WebUploader前端资源以及lib下载

链接:/s/1QsKoX4Xndoa-9dS5GvPy9w 密码:m96u

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。