单文件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部分代码:

<script type="text/javascript">  
        var fileMd5;  
        //监听分块上传过程中的三个时间点  
        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,10*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:"<%=basePath%>Video?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(){  
                //如果分块上传成功,则通知后台合并分块  
                $.ajax({  
                    type:"POST",  
                    url:"<%=basePath%>Video?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: '<%=basePath%>UploadVideo',  
            // 选择文件的按钮。可选。  
            // 内部根据当前运行是创建,可能是input元素,也可能是flash.  
            pick: {id: '#add_video',   <span style="background-color:rgb(255,204,0);">//这个id是你要点击上传文件的id,自己设置就好</span>  
            multiple:false},  
            // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!  
            resize: true,  
            auto:true,  
            //开启分片上传  
            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="info">' + file.name + '</p>' +  
                '<p class="state">等待上传...</p></div>'  
            );  
        });  
          
        // 文件上传过程中创建进度条实时显示。  
        uploader.on( 'uploadProgress', function( file, percentage ) {  
            $('#item1').find('p.state').text('上传中 '+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>  

2、servlet部分代码:

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

1、接收分块servlet代码:

@SuppressWarnings("serial")  
public class UploadVideo extends HttpServlet {  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
            throws ServletException, IOException {  
        // TODO Auto-generated method stub  
        super.doGet(req, resp);  
        doPost(req, resp);  
    }  
    @SuppressWarnings("unchecked")  
    public void doPost(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
          
        DiskFileItemFactory factory = new DiskFileItemFactory();  
        ServletFileUpload sfu = new ServletFileUpload(factory);  
        sfu.setHeaderEncoding("utf-8");  
          
        String savePath = this.getServletConfig().getServletContext()  
                .getRealPath("");  
        String folad = "uploads";  
        savePath = savePath + "\\"+folad+"\\";  
          
        String fileMd5 = null;  
        String chunk = null;  
          
        try {  
            List<FileItem> items = sfu.parseRequest(request);  
              
            for(FileItem item:items){  
                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) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
          
    }  
}  

2、合并分块servlet代码:

@SuppressWarnings("serial")  
public class Video extends HttpServlet {  
  
    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 = savePath + "\\"+folad+"\\";  
          
        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) {  
                    // 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>() {  
                @Override  
                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}");  
            }  
        }  
          
    }  
  
}  

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

参考文章:http://blog.ncmem.com/wordpress/2023/11/17/%e5%8d%95%e6%96%87%e4%bb%b6webuploader%e5%81%9a%e5%a4%a7%e6%96%87%e4%bb%b6%e7%9a%84%e5%88%86%e5%9d%97%e5%92%8c%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0/
欢迎入群一起讨论

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值