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

本文采用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" "http://www.w3.org/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 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;/*** 分片上传文件处理类*/
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 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*/
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 java.util.Comparator;
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/LianYunGangDaShuJuDP20181031-1/App_Uploads" + "/" + guid).mkdirs();// 进行文件合并File newFile = new File("D:/XALC/DP/LianYunGangDaShuJuDP20181031-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下载

链接:https://pan.baidu.com/s/1QsKoX4Xndoa-9dS5GvPy9w     密码:m96u

WebUploader 实现大文件的断点续传功能相关推荐

  1. php - 基于 webuploader 视频大文件分片分段上传,支持断点续传(刷新、关闭页面、重新上传、网络中断等情况)带进度条,前端后端都有示例源码详细教程

    效果图 文件上传前先检测该文件是否已上传,如果已上传提示 "文件已存在",如果未上传则直接上传. 基于 php+webuploader的大文件分片上传,带进度条,支持断点续传(刷新 ...

  2. 利用WebUploader实现大文件上传和视频上传

    文件上传是网站开发必不可少的,常见的有图片上传.但是大文件和视频上传不常见.这里我将自己写的视频上传demo贴出来供大家参考: 利用是最新的WebUploader插件请 下载使用最新版即可 js代码 ...

  3. thinkphp6+webuploader实现大文件(视频)分片上传/本地保存或上传OSS

    thinkPHP6+webuploader分片上传大视频的解决方案: ①能解决视频太大,1G.2G直传服务器压力过大 ②部分追求完美的人不发接受直传,那只能分片上传 ③分片上传是我找到的比较合理的解决 ...

  4. .NetCore+WebUploader实现大文件分片上传

    项目要求通过网站上传大文件,比如视频文件,通过摸索实现了文件分片来上传,然后后台进行合并. 使用了开源的前台上传插件WebUploader(http://fex.baidu.com/webupload ...

  5. webuploader 实现大文件 分片上传

    webuploader 分片上传文件 最近研究了下大文件上传的方法,找到了webuploader js 插件进行大文件上传. 使用 使用webuploader分成简单直选要引入 <!--引入CS ...

  6. python断点续传下载_Python 3 爬虫|第12章:并发下载大文件 支持断点续传

    1. stream 流式下载大文件 1.1 stream=True 和 iter_content() 我们将继续使用 Python 3 爬虫|第3章:同步阻塞下载 所搭建的测试环境,在 Nginx 默 ...

  7. python 下载大文件,断点续传 | Python工具类

    目录 前言 依赖 工具代码 总结 前言 实用python进行大文件下载的时候,一旦出现网络波动问题,导致文件下载到一半.如果将下载不完全的文件删掉,那么又需要从头开始,如果连续网络波动,是不是要头秃了 ...

  8. 不用U盘,电脑之间快速传输大文件,共享功能

    要求:两台电脑在同一个网络中(比如连接了同一个WIFI) step1:将电脑的网络设置为专用网 step2:打开两台电脑的共享 step3:在需要传输的文件上右键,选择"共享",选 ...

  9. chrome java上传文件_springboot+webuploader 实现大文件切片上传,兼容IE8+,chrome等浏览器,可运行...

    [实例简介] https://blog.csdn.net/weifangzjx/article/details/83898265 [实例截图] [核心代码] 上传例子 └── 上传例子 └── fil ...

最新文章

  1. 关于大型网站技术演进的思考(二十)--网站静态化处理—web前端优化—中(12)...
  2. 101每日发现练习大图
  3. python3 sorted排序代码示例
  4. MyBatis创建SqlSession-怎么拿到一个SqlSessionTemplate?
  5. swoole 清除定时器提示no timer
  6. Java - I/O
  7. jzoj3783-[NOIP2014模拟8.19]签到题【结论题】
  8. [渝粤教育] 四川农业大学 宏观经济学 参考 资料
  9. React Canvas:高性能渲染 React 组
  10. RuntimeError: Found 0 files in subfolders of: ./data/image Supported extensions are: .jpg,.jpeg,.png
  11. http://ju.outofmemory.cn/entry/307891---------TICK
  12. linux内核 快速分片,linux内核学习笔记------ip报文的分片
  13. click Parameters
  14. 在Pandas中直接加载MongoDB的数据
  15. cartographer编译过程遇到未定义的dlclose@@GLIBC_2.2.5
  16. Windows ZIP Archive安装和卸载MySQL 8.0
  17. 咚咚咚————【封装驱动】ADS1256驱动程序,分享交流自己编写的程序。
  18. java tapestry_Tapestry简介- 转载 (转自java-cn)
  19. 常见的4种行业应用级条码及开发工具,你都知道吗?
  20. HX711压力传感器学习(STM32)

热门文章

  1. 嵌入式linux驱动工程师面试,嵌入式Linux驱动工程师/BSP开发工程师面试笔试题集锦...
  2. 不知道音频格式转换app有哪些?手机怎么转换音频格式?
  3. 全国计算机等级考试(三级网络)基本概念与名词解释
  4. 嵌入式系统stm32 跑马灯实验
  5. ubuntu16.04安装steam问题解决
  6. CK6855M1蓝牙离线语音识别灯控模组使用说明书
  7. 应急指挥系统在铁路管理体系中的应用现状及方案分析
  8. 99乘法表c语言关于对齐,九九乘法表怎么准确对齐
  9. 解决:idea上传文件到hdfs上有文件无数据问题
  10. 酷家乐 Serverless FaaS 产品落地实践