百度Web Uploader组件实现文件上传之分片上传(一)
当网络问题导致传输错误时,只需要重传出错分片,而不是整个文件。另外分片传输能够更加实时的跟踪上传进度。多的不说了直接怼代码
前端是三个监听:一个是获取md5,一个是分片,最后一个是合并代码
<!DOCTYPE html>
<html ng-app="uploadApp" ng-controller="uploadCtl">
<head>
<title>fileupload.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../themes/reset.css" type="text/css"></link>
<link rel="stylesheet" href="../themes/webuploader.css" type="text/css"></link>
<script type="text/javascript" src="../plugins/jquery-3.2.0.min.js"></script>
<script type="text/javascript" src="../plugins/webuploader.min.js"></script>
<script type="text/javascript">
$(function(){
var fileName;
var fileMd5;
//监听分块上传过程中的三个时间点
WebUploader.Uploader.register({
"before-send-file":"beforeSendFile",
"before-send":"beforeSend",
"after-send-file":"afterSendFile",
},{
//时间点1:所有分块进行上传之前调用此函数
beforeSendFile:function(file){
fileName=file.name;
var deferred = WebUploader.Deferred();
//1、使用md5计算文件的唯一标记,用于断点续传
(new WebUploader.Uploader()).md5File(file,0,10*1024*1024)
.progress(function(percentage){
$('#item1').find("p.state").text("正在读取文件信息...");
})
.then(function(val){
fileMd5=val;
$('#item1').find("p.state").text("成功获取文件信息...");
//获取文件信息后进入下一步
deferred.resolve();
});
//调用deferred.resolve();无效
return deferred.promise();
},
//时间点2:如果有分块上传,则每个分块上传之前调用此函数
beforeSend:function(block,file){
console.log("分块"+fileName.replace(/.+\./, ""));
var deferred = WebUploader.Deferred(); $.ajax({
type:"POST",
url:"/servlet/mergeFile?action=checkChunk",
data:{
//文件唯一标记
fileMd5:fileMd5,
//当前分块下标
chunk:block.chunk,
//当前分块大小
chunkSize:block.end-block.start
},
dataType:"json",
success:function(response){
if(response.ifExist){
//分块存在,跳过
deferred.reject();
}else{
//分块不存在或不完整,重新发送该分块内容
deferred.resolve();
}
}
}); this.owner.options.formData.fileMd5 = fileMd5;
deferred.resolve();
return deferred.promise();
},
//时间点3:所有分块上传成功后调用此函数
afterSendFile:function(){
console.log("合并") ;
//如果分块上传成功,则通知后台合并分块
$.ajax({
type:"POST",
url:"/servlet/mergeFile?action=mergeChunks",
data:{
fileMd5:fileMd5,
},
success:function(response){
alert("上传成功");
var path = "uploads/"+fileMd5+".mp4";
$("#item1").attr("src",path);
}
});
}
}); var uploader = WebUploader.create({
// swf文件路径
swf: '<%=basePath%>scripts/webuploader-0.1.5/Uploader.swf',
// 文件接收服务端。
server: '/servlet/FileUpLoad',
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: {id: '#picker',
//这个id是你要点击上传文件的id,自己设置就好</span>
multiple:true},
// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
resize: true,
auto:true,
//上传并发数
threads:5,
//开启分片上传
chunked: true,
chunkSize:10*1024*1024, /* accept: {
//限制上传文件为MP4
extensions: 'mp4',
mimeTypes: 'video/mp4',
} */
}); // 当有文件被添加进队列的时候
uploader.on( 'fileQueued', function( file ) { $('#item1').empty();
$('#item1').html('<div id="' + file.id + '" class="item">'+
'<a class="upbtn" id="btn" onclick="stop()">[取消上传]</a>'+
'' +
'<p class="state">等待上传...</div>'
);
}); // 文件上传过程中创建进度条实时显示。
uploader.on( 'uploadProgress', function( file, percentage ) {
$('#item1').find('p.state').text(file.name+'上传中 '+Math.round(percentage * 100) + '%');
}); 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();
}); function start(){
uploader.upload();
$('#btn').attr("onclick","stop()");
$('#btn').text("取消上传");
} function stop(){
uploader.stop(true);
$('#btn').attr("onclick","start()");
$('#btn').text("继续上传");
} }); </script>
</head>
<body>
<div id="uploader" class="wu-example">
<!--用来存放文件信息-->
<div id="thelist" class="uploader-list"></div>
<div class="btns">
<div id="picker">选择文件</div>
<button id="ctlBtn" class="btn btn-default">开始上传</button>
</div>
</div>
<div id="item1"></div>
</body>
</html>
后端:一个保持文件servlet,一个判断分片和合并文件servelt
保持文件servlet
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List; import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Path; import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@Path("/fileupload")
public class ZFileCommand extends HttpServlet{
private static final long serialVersionUID = -2720014423604662780L;
// 1.文件上传路径
private static final String UPLOAD_DIRECTORY = "D:/文件上传";
// 2.设置临时存储文件大小,当超过大小时,将先存储超出大小文件在临时目录
private static final int MEMORY_THRESHOLD = 1024 * 1024 * 30;
// 3.设置最大文件上传值
private static final int MAX_FILE_SIZE = 1024 * 1024 * 2000;
// 4.最大请求值
private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 2048; public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获取文件名
String filename=request.getParameter("name");
//防止读取name名乱码
filename=new String(filename.getBytes("iso-8859-1"),"utf-8");
//在控制台打印文件名
System.out.println("文件名:"+filename);
//设置文件MIME类型
response.setContentType(getServletContext().getMimeType(filename));
//设置Content-Disposition
String realName = filename.substring(filename.indexOf("_")+1);
response.setHeader("Content-Disposition", "attachment;filename="+realName); //输入流为项目文件,输出流指向浏览器
InputStream is=new FileInputStream(UPLOAD_DIRECTORY+filename);
ServletOutputStream os =response.getOutputStream();
/*
* 设置缓冲区
* is.read(b)当文件读完时返回-1
*/
int len=-1;
byte[] b=new byte[1024];
while((len=is.read(b))!=-1){
os.write(b,0,len);
}
//关闭流
is.close();
os.close(); } /**
* @摘要 提供文件上传的方法
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
//1.设置字符编码为utf-8
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
// 2.检测是否为多媒体上传
if (!ServletFileUpload.isMultipartContent(request)) {
// 2.1如果不是则停止
PrintWriter writer = response.getWriter();
writer.println("Error: 表单必须包含 enctype=multipart/form-data");
writer.flush();
return ;
}
// 3.配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
//4. 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 5.设置临时存储目录 java.io.tmpdir默认的临时文件路径为服务器的temp目录
factory.setRepository(new File(System.getProperty("java.io.tmpdir"))); ServletFileUpload upload = new ServletFileUpload(factory); // 6.设置最大文件上传值
upload.setFileSizeMax(MAX_FILE_SIZE); // 7.设置最大请求值 (包含文件和表单数据)
upload.setSizeMax(MAX_REQUEST_SIZE); //8. 如果目录不存在则创建
File uploadDir = new File(UPLOAD_DIRECTORY);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
String fileMd5 = null;
String chunk = null;
try {
// 10.解析请求的内容提取文件数据
List<FileItem> formItems = upload.parseRequest(request);
// 10.1迭代表单数据
if (formItems != null && formItems.size() > 0) {
for (FileItem item : formItems) {
if (item.isFormField()) {
String fieldName = item.getFieldName();
if(fieldName.equals("fileMd5")){
fileMd5 = item.getString("utf-8");
}
if(fieldName.equals("chunk")){
chunk = item.getString("utf-8");
} }else{
String nFileName = new File(item.getName()).getName(); File file = new File(UPLOAD_DIRECTORY+"/"+fileMd5); if(!file.exists()){
file.mkdir();
}
nFileName=nFileName.substring(0,nFileName.lastIndexOf(".")) ; item.write(new File(UPLOAD_DIRECTORY+"/"+fileMd5+"/"+chunk)); item.delete();
} }
}
} catch (Exception ex) {
PrintWriter writer=response.getWriter();
writer.print("error");
}
}
}
一个判断分片和合并文件servelt
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
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 mergeFile extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String UPLOAD_DIRECTORY = "D:/文件上传"; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
super.doGet(request, response);
doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String savePath = this.getServletConfig().getServletContext()
.getRealPath("");
String folad = "uploads";
savePath = "D:/文件上传"; String action = request.getParameter("action"); if(action.equals("mergeChunks")){
//合并文件
//需要合并的文件的目录标记
String fileMd5 = request.getParameter("fileMd5"); //读取目录里的所有文件
File f = new File(savePath+"/"+fileMd5);
File[] fileArray = f.listFiles(new FileFilter(){
//排除目录只要文件
public boolean accept(File pathname) {
// TODO Auto-generated method stub
if(pathname.isDirectory()){
return false;
}
return true;
}
}); //转成集合,便于排序
List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));
Collections.sort(fileList,new Comparator<File>() {
public int compare(File o1, File o2) {
// TODO Auto-generated method stub
if(Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())){
return -1;
}
return 1;
}
});
//UUID.randomUUID().toString()-->随机名
File outputFile = new File(savePath+"/"+fileMd5+".mp4");
//创建文件
outputFile.createNewFile();
//输出流
FileChannel outChnnel = new FileOutputStream(outputFile).getChannel();
//合并
FileChannel inChannel;
for(File file : fileList){
inChannel = new FileInputStream(file).getChannel();
inChannel.transferTo(0, inChannel.size(), outChnnel);
inChannel.close();
//删除分片
file.delete();
}
outChnnel.close();
//清除文件夹
File tempFile = new File(savePath+"/"+fileMd5);
if(tempFile.isDirectory() && tempFile.exists()){
tempFile.delete();
}
System.out.println("合并成功");
}else if(action.equals("checkChunk")){
//检查当前分块是否上传成功
String fileMd5 = request.getParameter("fileMd5");
//分块次数
String chunk = request.getParameter("chunk");
//分块大小
String chunkSize = request.getParameter("chunkSize"); File checkFile = new File(savePath+"/"+fileMd5+"/"+chunk); response.setContentType("text/html;charset=utf-8");
//检查文件是否存在,且大小是否一致
if(checkFile.exists() && checkFile.length()==Integer.parseInt(chunkSize)){
//上传过
response.getWriter().write("{\"ifExist\":1}");
}else{
//没有上传过
response.getWriter().write("{\"ifExist\":0}");
}
} }
附件:源码
百度Web Uploader组件实现文件上传之分片上传(一)的更多相关文章
- 百度Web Uploader组件实现文件上传(一)
Web Uploader WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件.在现代的浏览器里面能充分发挥HTML5的优势 ...
- Web Uploader - 功能齐全,完美兼容 IE 的上传组件
文件上传是网站和 Web 应用程序的常用功能,一直没有一款完美的文件上传组件,因此让很多开发人员碰到头疼的浏览器兼容问题. WebUploader 是由 Baidu FEX 团队开发的一款以 HTML ...
- [ IE浏览器兼容问题 ] Web Uploader 在IE、FireFox下点击上传没反应
一.项目源码: > html > js 初始化插件: 事件绑定:avalon > web > 报错: - IE: 脚本缺少对象 - FireFox: js业务逻辑代码部分事件正 ...
- Web应用:当文件超过100KB,无法上传,有种原因你想象不到
今天下午2点多,突然发现凡是文件超过100KB的,在上传的时候都会卡住,但低于100KB的文件可以上传成功. 服务器端使用的是asp无组件上传,为什么突然出现这种问题呢? 我们知道,IIS默认上传限制 ...
- PHP大文件分割上传(分片上传)
服务端为什么不能直接传大文件?跟php.ini里面的几个配置有关 upload_max_filesize = 2M //PHP最大能接受的文件大小 post_max_size = 8M //PHP能收 ...
- input文件上传(上传单个文件/多选文件/文件夹、拖拽上传、分片上传)
//上传单个/多个文件 <input title="点击选择文件" id="h5Input1" multiple="" accept= ...
- PHP实现大文件分割上传与分片上传
转载:http://www.zixuephp.com/phpstudy/phpshilie/20170829_43029.html 服务端为什么不能直接传大文件?跟php.ini里面的几个配置有关 u ...
- 功能强大的文件上传插件带上传进度-WebUploader
WebUploader是由Baidu WebFE(FEX)团队开发的一个以HTML5/FLASH构建的现代文件上传组件.在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用老 ...
- php实现大文件上传分片上传断点续传
前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长, ...
随机推荐
- 更改AVD默认路径
默认情况下,安卓模拟器镜像文件会放到%userprofile%\.android下,例如当前Win7登录用户为administrator 则%userprofile%为 c:\users\admini ...
- 关于transform-style:preserve-3d的些许明了
父元素要添加属性transform-style:preserve-3d;和transform:perspective(800px);还有相对定位 首先设置子元素 具有3D属性,然后再设置视角与3D元素 ...
- spring + ibatis 多数据源事务(分布式事务)管理配置方法(转)
spring + ibatis 多数据源事务(分布式事务)管理配置方法(转) .我先要给大家讲一个概念:spring 的多数据源事务,这是民间的说法.官方的说法是:spring 的分布式事务.明白了这 ...
- oracle主键修改&设置某一字段可以为null
1.oracle主键修改 1.1)首先查看需要修改的表的主键名,默认的情况下,数据库会自动分配 select * from user_cons_columns where table_name='表名 ...
- UISwitch开关控件属性介绍以及获取开关状态并做出响应
(1)UISwitch的大小也是固定的,不随我们frame设置的大小改变:也是裁剪成圆角的,设置背景就露马脚发现背景是矩形. (2)UISwitch的背景图片设置无效,即我们只能设置颜色,不能用图片当 ...
- python爬虫_简单使用百度OCR解析验证码
百度技术文档 首先要注册百度云账号: 在首页,找到图像识别,创建应用,选择相应的功能,创建 安装接口模块: pip install baidu-aip 简单识别一: 简单图形验证码: 图片: from ...
- VisualStudio使用技巧
控制台工程去除黑框 刚学习OpenGL,绘制图形的时候,如果不进行设置,运行的时候会先出现黑窗口再出现Windows窗口.其实要去除控制台窗口非常简单,只需要修改工程设置,把子系统改成Windows, ...
- virualbox问题
出不来64位虚拟系统 bios设置虚拟化可用 2.创建虚拟机 启动不了 提示 不能打开一个... 安装exten 扩张包 3.设备 -- 安装增强功能... 分辨率 设置成功
- Linux中处理字符串
获取字符串长度: ${#字符串变量名} 截取子串: 1. expr substr 字符串 起始位置 截取长度 2. 命令输出 | cut -c 起始位置-结束位置 命令输出 | cut -c &quo ...
- MySQL5.7的安装(CentOS 7 & Ubuntu 16.04)
CentOS 通过 yum 安装MySQL5.7 Yum Repository 下载地址:https://dev.mysql.com/downloads/repo/yum/ 选择相应的版本进行下载:R ...