1,准备工作:
1,运行环境:jdk1.7; tomcat7;eclipse;
2,运用框架:ssm,webuploader,servlet;
2, 前端部分:
1,html:
2,js
var fileMd5,
// 可能有pedding, ready, uploading, confirm, done.
stateVideo = 'pedding',
// 添加的文件数量
fileCountvd = 0,
// 添加的文件总大小
fileSizevd = 0,
// 文件总体选择信息。
$infovd = $(".statusBar01").find('.infovd');
//监听分块上传过程中的三个时间点
WebUploader.Uploader.register({
"before-send-file":"beforeSendFile",
"before-send":"beforeSend",
"after-send-file":"afterSendFile",
},{
//时间点1:所有分块进行上传之前调用此函数
beforeSendFile:function(file){
var deferred = WebUploader.Deferred();
//1、计算文件的唯一标记,用于断点续传
(new WebUploader.Uploader()).md5File(file,0,6*1024*1024)
.progress(function(percentage){
//$('#item1').find("p.state").text("正在读取文件信息...");
})
.then(function(val){
fileMd5=val;
//$('#item1').find("p.state").text("成功获取文件信息,");
//获取文件信息后进入下一步
deferred.resolve();
});
return deferred.promise();
},
//时间点2:如果有分块上传,则每个分块上传之前调用此函数
beforeSend:function(block){
var deferred = WebUploader.Deferred();
$.ajax({
type:"POST",
url:BASE_URL+"/VideoProcess?action=checkChunk",
data:{
//文件唯一标记
fileMd5:fileMd5,
//当前分块下标
chunk:block.chunk,
//当前分块大小
chunkSize:block.end-block.start
},
dataType:"json",
success:function(response){
if(response.ifExist){
//分块存在,跳过
//alert("跳过");
deferred.reject();
}else{
//分块不存在或不完整,重新发送该分块内容
deferred.resolve();
}
}
});
this.owner.options.formData.fileMd5 = fileMd5;
deferred.resolve();
return deferred.promise();
},
//时间点3:所有分块上传成功后调用此函数
afterSendFile:function(file){
//如果分块上传成功,则通知后台合并分块
var chunksTotal = Math.ceil(file.size / (6*1024*1024));
if (chunksTotal > 1) {
$.ajax({
type:"POST",
url:BASE_URL +"/VideoProcess?action=mergeChunks",
data:{
fileMd5:fileMd5,
},
success:function(response){
//alert("上传成功");
/*var path = "uploads/"+fileMd5+".mp4";
$("#item1").attr("src",path);*/
}
});
}
}
});
var uploaderVideo = WebUploader.create({
auto:true,
// swf文件路径
swf: BASE_URL + '/pages/reception/resources/js/Uploader.swf',
// 文件接收服务端。
server: BASE_URL +"/VideoUpload",
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: {
id:'#add_video',
multiple:false,
},
disableGlobalDnd: false,//禁用拖拽功能
//开启分片上传
chunked: true,
chunkSize:6*1024*1024,
// 如果某个分片由于网络问题出错,允许自动重传多少次?
chunkRetry: 3,
prepareNextFile: true,//上传当前分片时预处理下一分片
fileNumLimit: 1,
fileSingleSizeLimit: 1 * 1024 * 1024 * 1024, // 单个文件大小 M
//duplicate:true,//可重复上传
//compress:false,
compress:null,//默认压缩图片,可以按照原始比例上传图片
threads:1,//上传并发数。允许同时最大上传进程数,为了保证文件上传顺序
accept: {
//限制上传文件为MP4
extensions: 'mp4,wmv,rmvb,3gp,mov,amv,dmv',
mimeTypes: '.mp4,.wmv,.rmvb,.3gp,.mov,.amv,.dmv',
}
});
// 当有文件被添加进队列的时候
uploaderVideo.on( 'fileQueued', function( file ) {
$('#item1').empty();
$('#item1').html(''+
'文件名称:' + file.name + '
'+
'文件大小:' + WebUploader.formatSize(file.size) + '
'+
'文件格式:' + file.ext + '
'+
'文件类型:' + file.type + '
'+
''
);
});
// 文件上传过程中创建进度条实时显示。
uploaderVideo.on( 'uploadProgress', function( file, percentage ) {
$(".statusBar01 .progress01").show();
$(".statusBar01 .progress01").find("span.percentage").css('width', Math.round(percentage * 100) + '%');
$(".statusBar01 .progress01").find("span.text").text(+Math.round(percentage * 100) + '%');
//$('#item1').find('p.state').text('上传中 '+Math.round(percentage * 100) + '%');
updateStatusvideo();
});
// 文件上传成功处理。
uploaderVideo.on( 'uploadSuccess', function( file ) {
$infovd.find("span").text("上传成功。");
console.log(file);
console.log("文件名:"+file.name);
console.log("文件大小:"+file.size);
console.log("文件格式:"+file.ext);
console.log("文件类型:"+file.type);
});
uploaderVideo.on( 'uploadError', function( file ) {
$infovd.html('');
$infovd.append('上传出错,请检查网络连接。');
});
// 长传完毕,不管成功失败都会调用该事件,主要用于关闭进度条
uploaderVideo.on( 'uploadComplete', function( file ) {
$(".statusBar01 .progress01").fadeOut();
$('#vdbtn').hide();
});
uploaderVideo.onError = function(code) {
alert('Error: ' + code);
};
function start(){
uploaderVideo.upload();
$('#vdbtn').attr("onclick","stop()");
$('#vdbtn').text("暂停上传");
}
function stop(){
uploaderVideo.stop(true);
$('#vdbtn').attr("onclick","start()");
$('#vdbtn').text("继续上传");
}
uploaderVideo.onFileQueued = function(file) {
fileCountvd++;
fileSizevd += file.size;
setState('ready');
};
uploaderVideo.onFileDequeued = function(file) {
fileCount--;
fileSize -= file.size;
if (!fileCount) {
setState('pedding');
}
updateStatusvideo();
};
uploaderVideo.on('all',function(type) {
var stats;
switch (type) {
case 'uploadFinished':
setState('confirm');
break;
case 'startUpload':
setState('uploading');
break;
case 'stopUpload':
setState('paused');
break;
}
});
function setState(val) {
var file, stats;
if (val === stateVideo) {
return;
}
state = val;
//显示进度条
switch (stateVideo) {
case 'uploading':
$(".statusBar01 .progress01").show();
break;
case 'paused':
$(".statusBar01 .progress01").show();
break;
case 'confirm':
$(".statusBar01 .progress01").hide();
stats = uploaderVideo.getStats();
if (stats.successNum && !stats.uploadFailNum) {
setState('finish');
return;
}
break;
case 'finish':
stats = uploaderVideo.getStats();
if (stats.successNum) {
//alert('上传成功');
} else {
// 没有成功的图片,重设
stateVideo = 'done';
location.reload();
}
break;
}
updateStatusvideo();
}
function updateStatusvideo() {
var text = '',
stats;
if (state === 'ready') {
text = '已选择' + fileCountvd + '个视频,共' + WebUploader.formatSize(fileSizevd) + '。';
} else if (state === 'confirm') {
stats = uploaderVideo.getStats();
if (stats.uploadFailNum) {
text = '已成功上传' + stats.successNum + '个视频至视频库,' + stats.uploadFailNum + '个视频上传失败。'
}
} else {
stats = uploaderVideo.getStats();
text = '已选择' + fileCountvd + '个视频(' + WebUploader.formatSize(fileSizevd) + '),正在上传中...';
if (stats.uploadFailNum) {
text += ',失败' + stats.uploadFailNum + '个';
}
}
$infovd.html(text);
}
3,后端部分:
需要注意:一开始用的ssm框架集成webuploader去实现断点续传,但是过程中发现这个类ServletFileUpload不兼容ssm,获取不到webuploader插件传到后台的数据,因为改用原生servlet兼容ssm去实现上传;
package com.imagelibrary.imagesnews.controller.video;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
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;
import com.imagelibrary.imagesnews.model.SystemConstants;
@SuppressWarnings("serial")
public class VideoUpload extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
super.doGet(req, resp);
doPost(req, resp);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sfu = new ServletFileUpload(factory);
sfu.setHeaderEncoding("utf-8");
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd");
String videoPath = sdf.format(date);
//1. 文件保存路径---本地盘符
//String savePath = "D:\\video" + videoPath;
//2. 文件保存路径---虚拟机本地盘符
String savePath = SystemConstants.SFTP_directory_video + videoPath;
String fileMd5 = null;
String chunk = null;
String fileName = "";
try {
List items = sfu.parseRequest(request);
for(FileItem item:items){
if(item.getFieldName().equals("name")){
fileName = new String(item.getString().getBytes("ISO-8859-1"), "UTF-8");
//System.out.println(fileName);
request.getSession().setAttribute("fileName", fileName);
}
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{
File file = new File(savePath+"/"+fileMd5);
if(!file.exists()){
file.mkdir();
}
File chunkFile = new File(savePath+"/"+fileMd5+"/"+chunk);
FileUtils.copyInputStreamToFile(item.getInputStream(), chunkFile);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
package com.imagelibrary.imagesnews.controller.video;
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.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.imagelibrary.imagesnews.model.SystemConstants;
@SuppressWarnings("serial")
public class VideoProcess extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
super.doGet(request, response);
doPost(request, response);
}
@SuppressWarnings("resource")
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd");
String videoPath = sdf.format(date);
//1. 文件保存路径---本地盘符
//String savePath = "D:\\video" + videoPath;
//2. 文件保存路径---虚拟机本地盘符
String savePath = SystemConstants.SFTP_directory_video + videoPath;
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(){
//排除目录只要文件
@Override
public boolean accept(File pathname) {
if(pathname.isDirectory()){
return false;
}
return true;
}
});
//转成集合,便于排序
List fileList = new ArrayList(Arrays.asList(fileArray));
Collections.sort(fileList,new Comparator() {
@Override
public int compare(File o1, File o2) {
if(Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())){
return -1;
}
return 1;
}
});
//获取视频名称
String fileName = (String) request.getSession().getAttribute("fileName");
//截取文件名的后缀名
//最后一个"."的位置
int pointIndex=fileName.lastIndexOf(".");
//后缀名
String suffix=fileName.substring(pointIndex);
//合并后的文件
//UUID.randomUUID().toString()-->随机名
//File outputFile = new File(savePath+"/"+fileMd5+".mp4");
File outputFile = new File(savePath+"/"+fileMd5+suffix);
//创建文件
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();
}
String newName = outputFile.getName();
//System.out.println(newName);
//System.out.println("合并成功");
//request.setAttribute("videoPath",videoPath1);SystemConstants.SFTP_httpUrl + "/video" + videoPath + newName
//request.getRequestDispatcher("/imagelibrary/webapp/pages/reception/upLoadVideo.jsp").forward(request, response);
request.getSession().setAttribute("videoPath", SystemConstants.SFTP_httpUrl + "/video" + videoPath + "/" + newName);
}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}");
}
}
}
}
4,总结
如需进一步了解,请加:QQ:86466280;