`

百度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}");  
	            }  
	        }  
	          
	    }  

附件:源码
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics