断点续传大文件,视频

1,准备工作:

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

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

2,   前端部分:

      1,html:

<script type="text/javascript" src="<%=request.getContextPath()%>/pages/reception/resources/js/jquery1.8.3.js"></script>
	<script type="text/javascript" src="<%=request.getContextPath()%>/pages/reception/resources/js/webuploader.js"></script>
    <script type="text/javascript" src="<%=request.getContextPath()%>/pages/reception/resources/js/js.js"></script>
    <script src="<%=request.getContextPath()%>/pages/reception/resources/js/jquery-ui.1.12.1.js"></script>
<script type="text/javascript" src="<%=request.getContextPath()%>/pages/reception/resources/js/upLoadVideo.js"></script>

<div class="upvideo">
                <div class="top clearfix">
                   	 <span class="msg1"><i></i>选择视频上传</span>
                     <a class="upbtn" id="add_video"></a>
                     <div class="statusBar01">
				        <div class="progress01"  style="display:none;">
				            <span class="text">0%</span>
				            <span class="percentage"></span>
				        </div><div class="infovd"><span style="color:red;font-size:12px;">文件大小不可超过1G。</span></div>
			    	 </div>
                 </div>
                 <div id="item1"></div>
            </div>	
      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('<div id="' + file.id + '" class="item">'+
	    	'<p class="filename">文件名称:<span>' + file.name + '</span></p>'+
	    	'<p class="filesize">文件大小:<span>' + WebUploader.formatSize(file.size) + '</span></p>'+
	    	'<p class="fileext">文件格式:<span>' + file.ext + '</span></p>'+
	    	'<p class="filetype">文件类型:<span>' + file.type + '</span></p>'+
	    	'<button type="button" id="vdbtn" οnclick="stop()">暂停上传</button>'
	    );
	});
	
	// 文件上传过程中创建进度条实时显示。
	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('<span style="color:red;">上传出错,请检查网络连接。</span>');
	});
	// 长传完毕,不管成功失败都会调用该事件,主要用于关闭进度条
	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) + '),<span>正在上传中...</span>';

            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<FileItem> 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<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));
			Collections.sort(fileList,new Comparator<File>() {
				@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;


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值