断点续传大文件,视频

1,准备工作:

1,运行环境:jdk1.7; tomcat7;eclipse;

2,运用框架:ssm,webuploader,servlet;

2,   前端部分:

      1,html:

    

选择视频上传
文件大小不可超过1G。
      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;


你可能感兴趣的:(webuploader)