zoukankan      html  css  js  c++  java
  • 单文件WebUploader做大文件的分块和断点续传

    前言:

    WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, android 4+。两套运行时,同样的调用方式,可供用户任意选用。

    上面的一段话是来自 http://fex.baidu.com/webuploader/  的介绍,现在做的项目需要用到大文件的上传,之前没有做过,现有的jquery的uploadify只用于上传图片什么的小文件,查了网上的资料,这个插件好像对于大文件不是很友好,为了安全起见,使用百度的成熟框架,不论是多文件还是单个的大文件都是很好用的,没有很多的问题,关于webuploader的详细介绍看官网就行:

    我的项目是javaweb,开发环境是MyEclipse,页面使用jsp

    1、先将 webuploader-0.1.5.zip 这个文件下载下来:https://github.com/fex-team/webuploader/releases  

    根据个人的需求放置自己需要的东西就行,全部放到项目里也可以,下面是我自己需要的东西:

    2、代码部分:分为jsp和servlet部分


    1、jsp部分代码:

    [html] view plain copy
     
    1. <script type="text/javascript">  
    2.         var fileMd5;  
    3.         //监听分块上传过程中的三个时间点  
    4.         WebUploader.Uploader.register({  
    5.             "before-send-file":"beforeSendFile",  
    6.             "before-send":"beforeSend",  
    7.             "after-send-file":"afterSendFile",  
    8.         },{  
    9.             //时间点1:所有分块进行上传之前调用此函数  
    10.             beforeSendFile:function(file){  
    11.                 var deferred = WebUploader.Deferred();  
    12.                 //1、计算文件的唯一标记,用于断点续传  
    13.                 (new WebUploader.Uploader()).md5File(file,0,10*1024*1024)  
    14.                     .progress(function(percentage){  
    15.                         $('#item1').find("p.state").text("正在读取文件信息...");  
    16.                     })  
    17.                     .then(function(val){  
    18.                         fileMd5=val;  
    19.                         $('#item1').find("p.state").text("成功获取文件信息...");  
    20.                         //获取文件信息后进入下一步  
    21.                         deferred.resolve();  
    22.                     });  
    23.                 return deferred.promise();  
    24.             },  
    25.             //时间点2:如果有分块上传,则每个分块上传之前调用此函数  
    26.             beforeSend:function(block){  
    27.                 var deferred = WebUploader.Deferred();  
    28.                   
    29.                 $.ajax({  
    30.                     type:"POST",  
    31.                     url:"<%=basePath%>Video?action=checkChunk",  
    32.                     data:{  
    33.                         //文件唯一标记  
    34.                         fileMd5:fileMd5,  
    35.                         //当前分块下标  
    36.                         chunk:block.chunk,  
    37.                         //当前分块大小  
    38.                         chunkSize:block.end-block.start  
    39.                     },  
    40.                     dataType:"json",  
    41.                     success:function(response){  
    42.                         if(response.ifExist){  
    43.                             //分块存在,跳过  
    44.                             deferred.reject();  
    45.                         }else{  
    46.                             //分块不存在或不完整,重新发送该分块内容  
    47.                             deferred.resolve();  
    48.                         }  
    49.                     }  
    50.                 });  
    51.                   
    52.                 this.owner.options.formData.fileMd5 = fileMd5;  
    53.                 deferred.resolve();  
    54.                 return deferred.promise();  
    55.             },  
    56.             //时间点3:所有分块上传成功后调用此函数  
    57.             afterSendFile:function(){  
    58.                 //如果分块上传成功,则通知后台合并分块  
    59.                 $.ajax({  
    60.                     type:"POST",  
    61.                     url:"<%=basePath%>Video?action=mergeChunks",  
    62.                     data:{  
    63.                         fileMd5:fileMd5,  
    64.                     },  
    65.                     success:function(response){  
    66.                         alert("上传成功");  
    67.                         var path = "uploads/"+fileMd5+".mp4";  
    68.                         $("#item1").attr("src",path);  
    69.                     }  
    70.                 });  
    71.             }  
    72.         });  
    73.           
    74.         var uploader = WebUploader.create({  
    75.             // swf文件路径  
    76.             swf: '<%=basePath%>scripts/webuploader-0.1.5/Uploader.swf',  
    77.             // 文件接收服务端。  
    78.             server: '<%=basePath%>UploadVideo',  
    79.             // 选择文件的按钮。可选。  
    80.             // 内部根据当前运行是创建,可能是input元素,也可能是flash.  
    81.             pick: {id: '#add_video',   <span style="background-color:rgb(255,204,0);">//这个id是你要点击上传文件的id,自己设置就好</span>  
    82.             multiple:false},  
    83.             // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!  
    84.             resize: true,  
    85.             auto:true,  
    86.             //开启分片上传  
    87.             chunked: true,  
    88.             chunkSize:10*1024*1024,  
    89.               
    90.             accept: {  
    91.             //限制上传文件为MP4  
    92.                 extensions: 'mp4',  
    93.                 mimeTypes: 'video/mp4',  
    94.             }  
    95.         });  
    96.                   
    97.         // 当有文件被添加进队列的时候  
    98.         uploader.on( 'fileQueued', function( file ) {  
    99.               
    100.             $('#item1').empty();  
    101.             $('#item1').html('<div id="' + file.id + '" class="item">'+  
    102.                 '<class="upbtn" id="btn" onclick="stop()">[取消上传]</a>'+  
    103.                 '<class="info">' + file.name + '</p>' +  
    104.                 '<class="state">等待上传...</p></div>'  
    105.             );  
    106.         });  
    107.           
    108.         // 文件上传过程中创建进度条实时显示。  
    109.         uploader.on( 'uploadProgress', function( file, percentage ) {  
    110.             $('#item1').find('p.state').text('上传中 '+Math.round(percentage * 100) + '%');  
    111.         });  
    112.           
    113.         uploader.on( 'uploadSuccess', function( file ) {  
    114.             $( '#'+file.id ).find('p.state').text('已上传');  
    115.         });  
    116.           
    117.         uploader.on( 'uploadError', function( file ) {  
    118.             $( '#'+file.id ).find('p.state').text('上传出错');  
    119.         });  
    120.           
    121.         uploader.on( 'uploadComplete', function( file ) {  
    122.             $( '#'+file.id ).find('.progress').fadeOut();  
    123.         });  
    124.         
    125.         function start(){  
    126.             uploader.upload();  
    127.             $('#btn').attr("onclick","stop()");  
    128.             $('#btn').text("取消上传");  
    129.         }  
    130.           
    131.         function stop(){  
    132.             uploader.stop(true);  
    133.             $('#btn').attr("onclick","start()");  
    134.             $('#btn').text("继续上传");  
    135.         }  
    136.           
    137.     </script>  

    2、servlet部分代码:


    servlet部分需要两个servlet,一个用于接收分块文件,一个用于合并分块成一个文件:

    1、接收分块servlet代码:

    [java] view plain copy
     
    1. @SuppressWarnings("serial")  
    2. public class UploadVideo extends HttpServlet {  
    3.     @Override  
    4.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
    5.             throws ServletException, IOException {  
    6.         // TODO Auto-generated method stub  
    7.         super.doGet(req, resp);  
    8.         doPost(req, resp);  
    9.     }  
    10.     @SuppressWarnings("unchecked")  
    11.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
    12.             throws ServletException, IOException {  
    13.           
    14.         DiskFileItemFactory factory = new DiskFileItemFactory();  
    15.         ServletFileUpload sfu = new ServletFileUpload(factory);  
    16.         sfu.setHeaderEncoding("utf-8");  
    17.           
    18.         String savePath = this.getServletConfig().getServletContext()  
    19.                 .getRealPath("");  
    20.         String folad = "uploads";  
    21.         savePath = savePath + "\"+folad+"\";  
    22.           
    23.         String fileMd5 = null;  
    24.         String chunk = null;  
    25.           
    26.         try {  
    27.             List<FileItem> items = sfu.parseRequest(request);  
    28.               
    29.             for(FileItem item:items){  
    30.                 if(item.isFormField()){  
    31.                     String fieldName = item.getFieldName();  
    32.                     if(fieldName.equals("fileMd5")){  
    33.                         fileMd5 = item.getString("utf-8");  
    34.                     }  
    35.                     if(fieldName.equals("chunk")){  
    36.                         chunk = item.getString("utf-8");  
    37.                     }  
    38.                 }else{  
    39.                     File file = new File(savePath+"/"+fileMd5);  
    40.                     if(!file.exists()){  
    41.                         file.mkdir();  
    42.                     }  
    43.                     File chunkFile = new File(savePath+"/"+fileMd5+"/"+chunk);  
    44.                     FileUtils.copyInputStreamToFile(item.getInputStream(), chunkFile);  
    45.                       
    46.                 }  
    47.             }  
    48.               
    49.         } catch (FileUploadException e) {  
    50.             // TODO Auto-generated catch block  
    51.             e.printStackTrace();  
    52.         }  
    53.           
    54.     }  
    55. }  

    2、合并分块servlet代码:

    [java] view plain copy
     
    1. @SuppressWarnings("serial")  
    2. public class Video extends HttpServlet {  
    3.   
    4.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
    5.             throws ServletException, IOException {  
    6.         super.doGet(request, response);  
    7.         doPost(request, response);  
    8.           
    9.     }  
    10.   
    11.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
    12.             throws ServletException, IOException {  
    13.         String savePath = this.getServletConfig().getServletContext()  
    14.                 .getRealPath("");  
    15.         String folad = "uploads";  
    16.         savePath = savePath + "\"+folad+"\";  
    17.           
    18.         String action = request.getParameter("action");  
    19.           
    20.         if(action.equals("mergeChunks")){  
    21.             //合并文件  
    22.             //需要合并的文件的目录标记  
    23.             String fileMd5 = request.getParameter("fileMd5");  
    24.               
    25.             //读取目录里的所有文件  
    26.             File f = new File(savePath+"/"+fileMd5);  
    27.             File[] fileArray = f.listFiles(new FileFilter(){  
    28.                 //排除目录只要文件  
    29.                 @Override  
    30.                 public boolean accept(File pathname) {  
    31.                     // TODO Auto-generated method stub  
    32.                     if(pathname.isDirectory()){  
    33.                         return false;  
    34.                     }  
    35.                     return true;  
    36.                 }  
    37.             });  
    38.               
    39.             //转成集合,便于排序  
    40.             List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));  
    41.             Collections.sort(fileList,new Comparator<File>() {  
    42.                 @Override  
    43.                 public int compare(File o1, File o2) {  
    44.                     // TODO Auto-generated method stub  
    45.                     if(Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())){  
    46.                         return -1;  
    47.                     }  
    48.                     return 1;  
    49.                 }  
    50.             });  
    51.             //UUID.randomUUID().toString()-->随机名  
    52.             File outputFile = new File(savePath+"/"+fileMd5+".mp4");  
    53.             //创建文件  
    54.             outputFile.createNewFile();  
    55.             //输出流  
    56.             FileChannel outChnnel = new FileOutputStream(outputFile).getChannel();  
    57.             //合并  
    58.             FileChannel inChannel;  
    59.             for(File file : fileList){  
    60.                 inChannel = new FileInputStream(file).getChannel();  
    61.                 inChannel.transferTo(0, inChannel.size(), outChnnel);  
    62.                 inChannel.close();  
    63.                 //删除分片  
    64.                 file.delete();  
    65.             }  
    66.             outChnnel.close();  
    67.             //清除文件夹  
    68.             File tempFile = new File(savePath+"/"+fileMd5);  
    69.             if(tempFile.isDirectory() && tempFile.exists()){  
    70.                 tempFile.delete();  
    71.             }  
    72.             System.out.println("合并成功");  
    73.         }else if(action.equals("checkChunk")){  
    74.             //检查当前分块是否上传成功  
    75.             String fileMd5 = request.getParameter("fileMd5");  
    76.             String chunk = request.getParameter("chunk");  
    77.             String chunkSize = request.getParameter("chunkSize");  
    78.               
    79.             File checkFile = new File(savePath+"/"+fileMd5+"/"+chunk);  
    80.               
    81.             response.setContentType("text/html;charset=utf-8");  
    82.             //检查文件是否存在,且大小是否一致  
    83.             if(checkFile.exists() && checkFile.length()==Integer.parseInt(chunkSize)){  
    84.                 //上传过  
    85.                 response.getWriter().write("{"ifExist":1}");  
    86.             }else{  
    87.                 //没有上传过  
    88.                 response.getWriter().write("{"ifExist":0}");  
    89.             }  
    90.         }  
    91.           
    92.     }  
    93.   
    94. }  

    至此,大文件上传的分块和断点就ok了,这也只是我自己的项目需求编写的,这个框架还涵盖很多的内容和功能,需要你自己去研究了,不过都不是很难,你也可以去修改它的css和js文件根据自己的需求。

  • 相关阅读:
    springboot集成kafka
    elasticsearch http 搜索 测试
    linux下安装Elasticsearch
    laravel_admin 使用
    laravel 数据操作
    Win10+apache+PHP+Mysql
    laravel 坑(一)
    下载CentOS镜像
    window10 家庭版 添加Hyper-V虚拟机
    Win10 Composer 下载安装
  • 原文地址:https://www.cnblogs.com/yesu/p/8267131.html
Copyright © 2011-2022 走看看