`

百度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
分享到:
评论

相关推荐

    百度web uploader java servlet上传示例

    在Web开发中,文件上传是一项常见的功能,而百度Web Uploader是一个强大的JavaScript库,专为实现高效的多文件上传而设计。它支持预览、断点续传、多线程上传等功能,极大地提升了用户体验。本示例将详细介绍如何在...

    百度webuploader自己写的demo,涉及到大文件上传,断电续传,分片等,前后端代码齐全,有需要的可用哪来参考哈

    3. **文件分片**:分片上传是实现断点续传的基础,WebUploader将大文件拆分成多个小块(如2MB或4MB),每个块作为一个单独的请求发送到服务器。这种方式不仅方便了断点续传,还能够实现并行上传,加速整体上传速度。...

    基于minio webuploader实现的分片上传 断点续传

    WebUploader是百度开发的一款JavaScript组件,它允许用户进行大文件的分片上传。分片上传是指将大文件分割成多个小块(片),每个片单独上传,提高了上传速度和成功率。WebUploader还支持断点续传,即如果上传过程...

    vue-simple-uploader for vue3源码

    `vue-simple-uploader` 是一个适用于 Vue3 的轻量级文件上传组件,它允许开发者方便地实现文件上传功能,包括大文件的分片上传。在对源码进行深入分析之前,我们先来理解一下大文件分片上传的基本原理。 大文件分片...

    MinIo最佳性能分片上传、断点续传方案

    在处理大文件上传时,为了实现最佳性能并确保可靠性,通常会采用分片上传和断点续传技术。本文将详细解析这两种技术以及如何在MinIO中实现它们,并提供前后端的示例代码。 分片上传: 1. **分片原理**:当上传大...

    异步上传组件uploader基于kissy

    - **分片上传**:对于大文件,Uploader组件可以将其分割成多个小块进行并发上传,提高上传速度,并在服务器端进行重组。 - **进度条显示**:通过监听上传过程中的事件,展示文件上传进度,提升用户体验。 - **错误...

    php结合web uploader插件实现分片上传文件

    本文介绍如何使用PHP结合Web Uploader插件实现大文件的分片上传功能。重点在于提升上传大文件的效率,通过将大文件分割成多个小块(分片)并发上传,从而克服网络不稳定和超时的问题。本文适用于对Web开发中的文件...

    Web Uploader

    Web Uploader通过JavaScript实现了一套完整的文件上传机制,使得开发者可以自定义上传界面、控制上传流程,甚至实现跨域上传和大文件分片上传。 Web Uploader的主要功能和特点包括: 1. **多文件选择**:允许用户...

    webuploader完整例子\百度切割上传

    在这个"webuploader完整例子\百度切割上传"中,我们主要探讨的是如何实现大文件的分片上传(切割上传)以及后端处理这些分片并合并成原始文件的技术细节。 1. **WebUploader的基本概念** WebUploader的核心理念是...

    springboot集成minio实现的文件服务组件(含Vue前端源码).zip

    总的来说,这个项目涵盖了SpringBoot、MinIO集成、文件服务组件的设计与实现、前端Vue.js的使用以及分片上传等技术,是学习和实践现代Web应用开发的一个良好示例。通过这个项目,开发者不仅可以掌握文件存储服务的...

    Web_Uploader_demo.zip

    5. **上传策略**:Web Uploader支持分片上传和断点续传,这对于处理大文件尤其有用。开发者可以设置每片文件的大小,并在断网或中断后继续未完成的上传。 6. **图片处理**:对于图片上传,Web Uploader还提供了预览...

    chunk-uploader:SpringBoot+Redis 实现大文件分片上传,断点续传,急速秒传。前端使用vue-simpler-uploader实现文件并发上传

    接着,我们引入Redis作为临时存储,实现文件分片上传。文件被分割成多个小块(chunk),每个chunk在上传时被暂时存储在Redis中。这样做的好处在于,Redis是内存数据库,读写速度极快,适合处理大量的小文件操作。每...

    百度上传控件Demo(WebUploader)及API文档

    百度WebUploader是一款强大的前端文件上传组件,它提供了一套完整的解决方案,包括文件选择、文件预览、上传进度显示、多文件上传、断点续传等功能。在本文中,我们将深入探讨WebUploader的核心特性、API用法以及...

    前端webuploader文件上传实现demo

    2. **分片上传**:对于大文件,WebUploader可以将其切割成多个小块进行上传,这样即使在网络不稳定的情况下,也能通过断点续传保证文件完整上传。 3. **进度显示**:在上传过程中,WebUploader可以实时显示每个文件...

    多文件上传,并显示每一个的进度

    在现代Web应用中,用户可能需要一次性上传多个文件,例如图片、文档或视频。这个过程如果能实时显示每个文件的上传进度,将极大地提升用户体验。本文将深入探讨如何实现"多文件上传,并显示每一个的进度"这一功能,...

    Web Uploader文件上传插件使用详解

    1. **分片并发上传**:Web Uploader将大文件分割成多个小分片并行上传,一旦某个分片上传失败,只需重新上传出错的分片,无需重新上传整个文件。这显著提升了上传速度,并且能实时跟踪上传进度。 2. **预览与压缩**...

    Vue2.0结合webuploader实现文件分片上传功能

    Vue2.0结合webuploader实现文件分片上传功能 本文主要介绍了如何使用Vue2.0结合webuploader实现文件分片上传功能,解决大文件上传的问题。下面是相关知识点的详细说明: 文件分片上传的必要性 在上传大文件时,...

    webuploader分片上传的实现代码(前后端分离)

    尤其在处理大文件上传时,WebUploader提供了分片上传的功能,以提高上传效率并降低网络中断的风险。本文将详细讲解如何使用WebUploader实现分片上传,并将其与后端服务进行分离,确保前后端职责明确。 首先,让我们...

Global site tag (gtag.js) - Google Analytics