ebUploader插件上传大文件单文件和多文件JAVA版使用总结

编辑: 点击量: 258
ebUploader插件上传大文件单文件和多文件JAVA版使用总结


.使用webuploader插件的原因说明

被现在做的项目坑了。 
先说一下我的项目架构Spring+struts2+mybatis+mysql 
然后呢。之前说好的按照2G上传就可以了,于是乎,用了ajaxFileUpload插件,因为之前用图片上传也是用这个,所以上传附件的时候就直接拿来用了 
各种码代码,测试也测过了,2G文件上传没问题,坑来了,项目上线后,客户又要求上传4G文件,甚至还有20G以上的。。纳尼,你不早说哦。。。 
在IE11下用ajaxFileUpload.js插件上传超过4G的文件,IE直接抛出异常了。弹出 算术结果超过32位 的消息. 
如下图: 
 
附加说明一下,我的系统是64位,8G内存,google浏览器和IE11浏览器都是32位的。google下用AjaxFileUpload上传8G都问题。都不会报错。 
IE11下超过4G直接报上图这个错了。没办法。换插件。

二.插件选择

1.stream上传插件。stream是解决不同浏览器上传文件插件,是Uploadify的flash版和html5的结合。插件地址http://www.twinkling.cn/ 
功能确实很强大,不过CSS样式固定死了,和我现在项目的进度条样式很不一样。还是放弃了这个插件 
2.Webuploader 插件。WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, android 4+。两套运行时,同样的调用方式,可供用户任意选用。 
采用大文件分片并发上传,极大的提高了文件上传效率。插件地址 http://fex.baidu.com/webuploader/ 
这个插件可以自定义CSS样式啊。功能也很强大,于是乎果断采用这个插件。安利一个webuplolder的作者写的使用webupload的上传优化总结。建议在了解了webuploader之后在看,会有意想不到的收获: 
http://www.sxrczx.com/pages/itindex.net/hmhk1423492392082.html

三.WebUploader 单文件上传

我用的是Webuploader0.1.5版本的,Webuploader主要是把大文件在客户端进行分片,比如按照每5M进行分片发送请求,后台接收到文件进行合并文件。两种方式合并文件,第一种等所有分片都传到后台,然后在合并,这种要保障分片顺序正确,第二种是边分片边合并。项目里我使用的是第二种。使用Web Uploader文件上传需要引入三种资源:JS, CSS, SWF。 
1.引入JS文件

<script type="text/javascript" src="../main/js/webuploader.js"></script>
<script type="text/javascript" src="../main/js/webuploader.min.js"></script>
  • 1
  • 2

2.引入CSS样式

<link href="../main/css/webuploader.css" rel="stylesheet" type="text/css" />
  • 1

3.引入SWF,SWF不直接引用,在webUploader初始化的时候指定SWF的路径就可以了。参考后面的代码。

4.upload3.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta http-equiv="Content-Language"  content="ja" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title>DEMO</title>
<link href="../main/css/stream-v1.css" rel="stylesheet" type="text/css" />
<link href="../main/css/webuploader.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../main/js/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="../main/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="../main/js/jquery-ui.min.js"></script>
<script type="text/javascript" src="../main/js/bootstrap-datepicker.min.js"></script>
<script type="text/javascript" src="../main/js/locales/bootstrap-datepicker.ja.min.js"></script>
<script type="text/javascript" src="../main/js/webuploader.js"></script>
<script type="text/javascript" src="../main/js/webuploader.min.js"></script>
<script type="text/javascript" src="../js/contents/upload3.js"></script>
</head>
<body>
<div id="uploader" class="wu-example">
    <!--用来存放文件信息-->
    <div id="thelist" class="uploader-list"></div>
    <div class="btns">
        <div id="attach"></div>
        <input type="button" value="上传" id="upload"/> 
    </div>
</div>


<div id="uploader1" class="wu-example">
    <!--用来存放文件信息-->
    <div id="thelist1" class="uploader-list"></div>
    <div class="btns">
        <div id="multi"></div>
        <input type="button" value="上传" id="multiUpload"/> 
    </div>
</div>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

画面比较简单,长这个样子 

5.upload3.js 
包含单文件上传,多文件上传,和webuploader多实例,webuploader多实例就是把webuploader初始化多遍,webuploader的官网上的范例就是多实例。

/*********************************WebUpload 单文件上传 begin*****************************************/
$(function(){
    var $list = $("#thelist");
    var  uploader ;// 实例化   
    uploader = WebUploader.create({ 
           auto:false, //是否自动上传
            pick: {
                id: #attach,
                name:"file",  //这个地方 name 没什么用,虽然打开调试器,input的名字确实改过来了。但是提交到后台取不到文件。如果想自定义file的name属性,还是要和fileVal 配合使用。
                label: 点击选择图片,
                multiple:false            //默认为true,true表示可以多选文件,HTML5的属性
            },
            swf: ../../main/js/Uploader.swf,  //在这里必需要引入swf文件,webuploader初始化要用
            //fileVal:multiFile,  //自定义file的name属性,我用的版本是0.1.5 ,打开客户端调试器发现生成的input 的name 没改过来。
                                             //名字还是默认的file,但不是没用哦。虽然客户端名字没改变,但是提交到到后台,是要用multiFile 这个对象来取文件的,用file 是取不到文件的
                                             // 建议作者有时间把这个地方改改啊,搞死人了。。
            server: "Webuploader!ajaxAttachUpload.action",
            duplicate:true,//是否可重复选择同一文件
            resize: false,
            formData: {
                "status":"file",
                "contentsDto.contentsId":"0000004730",
                "uploadNum":"0000004730",
                "existFlg":false
            },  
            compress: null,//图片不压缩
            chunked: true,  //分片处理
            chunkSize: 5 * 1024 * 1024, //每片5M
            chunkRetry:false,//如果失败,则不重试
            threads:1,//上传并发数。允许同时最大上传进程数。
            // runtimeOrder: flash,  
            // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。  
            disableGlobalDnd: true
        });  

        // 当有文件添加进来的时候
       uploader.on( "fileQueued", function( file ) {
           console.log("fileQueued:");
           $list.append( "<div id="+  file.id + " class=item>" +
               "<h4 class=info>" + file.name + "</h4>" +
               "<p class=state>等待上传...</p>" +
           "</div>" );
       });

       //当所有文件上传结束时触发
       uploader.on("uploadFinished",function(){
           console.log("uploadFinished:");
       })

        //当某个文件上传到服务端响应后,会派送此事件来询问服务端响应是否有效。
        uploader.on("uploadAccept",function(object,ret){
            //服务器响应了
            //ret._raw  类似于 data
            var data =JSON.parse(ret._raw);
            if(data.resultCode != "1" && data.resultCode != "3"){
                if(data.resultCode == "9"){
                    uploader.reset();
                    alert("error");
                    return false;
                }
            }else{
                //E05017
                uploader.reset();
                alert("error");
                return false;
            }
           })

       //当文件上传成功时触发。
         uploader.on( "uploadSuccess", function( file ) {
           $( "#"+file.id ).find("p.state").text("已上传");
       });

       uploader.on( "uploadError", function( file ) {
           $( "#"+file.id ).find("p.state").text("上传出错");
           uploader.cancelFile(file);
           uploader.removeFile(file,true);
           uploader.reset();
       });


       $("#upload").on("click", function() {
           uploader.upload();
       })

});
/*********************************WebUpload 单文件上传 end*******************************************/

/************************************webuploader的自带参数提交到后台的参数列表*************************
 * {

//web uploader 的自带参数 
lastModifiedDate=[Wed Apr 27 2016 16:45:01 GMT+0800 (中国标准时间)], 
chunks=[3], chunk=[0], 
type=[audio/wav], uid=[yangl],  id=[WU_FILE_0], 
size=[268620636], name=[3.wav],

//formData的参数
contentsDto.contentsId=[0000004730], existFlg=[false], 
status=[file], uploadNum=[0000004730]
}
*********************************************************************************************/

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104

6.WebuploaderAction.java 
后台的实现为struts2,把分片按照上传顺序合并成一个文件。这里只是给一个实现的参考,可以根据实际项目情况来实现后台。

//属性值,单文件的情况,对应的是upload3.js中的name属性,name属性值为file,此时struts就可以获取到file的文件对象,不需要实例化,struts框架会自动注入对象值,打开调试窗口,看一下就明白了
private File file;
//单文件上传的文件名,spring上传特性,文件名格式为name属性+FileName
private String fileFileName;

//属性值,接收webupload自带的参数
private String chunk; // 当前第几个分片
private String chunks;// 总分片个数
private String size;// 单个文件的总大小

//单文件上传后台代码
public void ajaxAttachUpload() {
        String path =  "d:\test\"+fileFileName;
        try {
            //拿到文件对象
            File file = this.getFile();
            //第一个参数是目标文件的完整路径
            //第二参数是webupload分片传过来的文件
            //FileUtil的这个方法是把目标文件的指针,移到文件末尾,然后把分片文件追加进去,实现文件合并。简单说。就是每次最新的分片合到一个文件里面去。
            FileUtil.randomAccessFile(path, file);
            //如果文件小与5M的话,分片参数chunk的值是null
            //5M的这个阈值是在upload3.js中的chunkSize属性决定的,超过chunkSize设置的大小才会进行分片,否则就不分片,不分片的话,webupload传到后台的chunk参数值就是null
            if(StringUtils.isEmpty(chunk)){
                //不分片的情况
                outJson("0", "success", "");
            }else{
            //分片的情况
            //chunk 分片索引,下标从0开始
            //chunks 总分片数
                if (Integer.valueOf(chunk) == (Integer.valueOf(chunks) - 1)) {
                    outJson("0", "上传成功", "");
                } else {
                    outJson("2", "上传中" + fileFileName + " chunk:" + chunk, "");
                }
            }
        } catch (Exception e) {
            outJson("3", "上传失败", "");
        }
    }

FileUtil.java
每次把指针移到文件末尾,追加写入文件

/**
     * 指定位置开始写入文件
     * @param tempFile  输入文件
     * @param outPath  输出文件的路径(路径+文件名)
     * @throws IOException
     */
    public static void randomAccessFile( String outPath,File tempFile) throws IOException{
        RandomAccessFile  raFile = null;
        BufferedInputStream inputStream=null;
        try{
            File dirFile = new File(outPath);
            //以读写的方式打开目标文件
            raFile = new RandomAccessFile(dirFile, "rw"); 
            raFile.seek(raFile.length());
            inputStream = new BufferedInputStream(new FileInputStream(tempFile));
            byte[] buf = new byte[1024];
            int length = 0;
            while ((length = inputStream.read(buf)) != -1) {
                raFile.write(buf, 0, length);
            }
        }catch(Exception e){
            throw new IOException(e.getMessage());
        }finally{
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (raFile != null) {
                    raFile.close();
                }
            }catch(Exception e){
                throw new IOException(e.getMessage());
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

7.单文件上传效果图 
 

8.多文件上传 
多文件上传webuploader是用队列控制的,文件一个一个上传。文件1在上传中的话,文件2就在排队,等文件1传完了在传文件2。这里要注意name属性和fileVal属性的结合使用,否则后台是取不到mulitFile对象的

upload3.js

/*********************************WebUpload 多文件上传 begin*****************************************/
$(function(){
  var $list = $("#thelist1");
  var fileSize = 0;  //总文件大小
  var fileName = []; //文件名列表
  var fileSizeOneByOne =[];//每个文件大小
  var  uploader ;// 实例化   
  uploader = WebUploader.create({ 
         auto:false, //是否自动上传
         pick: {
              id: #multi,
              label: 点击选择文件,
              name:"multiFile"
          },
          swf: ../../main/js/Uploader.swf,  
          fileVal:multiFile,              //和name属性配合使用
          server: "Webuploader!ajaxAttachUpload2.action",  
          duplicate:true, //同一文件是否可重复选择
          resize: false,
          formData: {
              "status":"multi",
              "contentsDto.contentsId":"0000004730",
              "uploadNum":"0000004730",
              "existFlg":false
          },  
          compress: null,//图片不压缩
          chunked: true,  //分片
          chunkSize: 5 * 1024 * 1024,   //每片5M
          chunkRetry:false,//如果失败,则不重试
          threads:1,//上传并发数。允许同时最大上传进程数。
          //fileNumLimit:50,//验证文件总数量, 超出则不允许加入队列
          // runtimeOrder: flash,  
          // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。  
          disableGlobalDnd: true
      });  

     // 当有文件添加进来的时候
     uploader.on( "fileQueued", function( file ) {
       console.log("fileQueued:");
         $list.append( "<div id="+  file.id + " class=item>" +
             "<h4 class=info>" + file.name + "</h4>" +
             "<p class=state>等待上传...</p>" +
         "</div>" );
     });

     // 当开始上传流程时触发
     uploader.on( "startUpload", function() {
       console.log("startUpload");
       //添加额外的表单参数
         $.extend( true, uploader.options.formData, {"fileSize":fileSize,"multiFileName":fileName,"fileSizeOneByOne":fileSizeOneByOne}); 
     });

     //当某个文件上传到服务端响应后,会派送此事件来询问服务端响应是否有效。
     uploader.on("uploadAccept",function(object,ret){
         //服务器响应了
         //ret._raw  类似于 data
      console.log("uploadAccept");
         console.log(ret);
         var data =JSON.parse(ret._raw);
         if(data.resultCode!="1" && data.resultCode !="3"){
        if(data.resultCode == "9"){
          alert("error");
          uploader.reset();
          return;
        }
      }else{
        uploader.reset();
        alert("error");
      }
    })

     uploader.on( "uploadSuccess", function( file ) {
         $( "#"+file.id ).find("p.state").text("已上传");
     });

     //出错之后要把文件从队列中remove调,否则,文件还在队里中,还是会上传到后台去
     uploader.on( "uploadError", function( file,reason  ) {
       $( "#"+file.id ).find("p.state").text("上传出错");
       console.log("uploadError");
       console.log(file);
       console.log(reason);
         //多个文件
         var fileArray = uploader.getFiles();
         for(var i = 0 ;i<fileArray.length;i++){
             //取消文件上传
              uploader.cancelFile(fileArray[i]);
              //从队列中移除掉
              uploader.removeFile(fileArray[i],true);
        }
         //发生错误重置webupload,初始化变量
         uploader.reset();
         fileSize = 0;
         fileName = [];
         fileSizeOneByOne=[];
     });

   //当validate不通过时,会以派送错误事件的形式通知调用者
     uploader.on("error",function(){
       console.log("error");
       uploader.reset();
       fileSize = 0;
         fileName = [];
         fileSizeOneByOne=[];
        alert("error");
     })


     //如果是在模态框里的上传按钮,点击file的时候不会触发控件
     //修复model内部点击不会触发选择文件的BUG
     /*    $("#multi .webuploader-pick").click(function () {
            uploader.reset();
            fileSize = 0;
            fileName = [];
            fileSizeOneByOne=[];
                $("#multi :file").click();
            });*/

     /**
     * 多文件上传
     */
    $("#multiUpload").on("click",function(){
      uploader.upload();
    })

   /**
    *取得每个文件的文件名和文件大小
   */
    //选择文件之后执行上传  
    $(document).on("change","input[name=multiFile]", function() {
          //multiFileName
          var fileArray1 = uploader.getFiles();
          var fileNames = [];
           for(var i = 0 ;i<fileArray1.length;i++){
              fileNames.push(fileArray1[i].name); //input 框用
              //后台用
              fileSize +=fileArray1[i].size;
               fileSizeOneByOne.push(fileArray1[i].size);
               fileName.push(fileArray1[i].name);
            }
           console.log(fileSize);
           console.log(fileSizeOneByOne);
           console.log(fileName);
    })

});
/*********************************WebUpload 多文件上传 end*****************************************/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146

9.多文件后台代码,WebuploaderAction.java

    //多文件上传的文件对象,多文件是一个一个文件上传,所以multiFile是当前正在上传的文件对象
    private File multiFile;
    //多文件上传文件对象的文名,当前正在上传的文件名
    private String multiFileFileName;

    //属性值,接收webupload自带的参数
    private String chunk; // 当前第几个分片
    private String chunks;// 总分片个数
    private String size;// 单个文件的总大小

    //自定义属性值
    private String fileSize;//所有文件的总大小
    private String[] multiFileName  ;// 文件名列表
    private String[] fileSizeOneByOne;//每个文件大小
    private String status;

    /***
     * 多文件上传的核心是,前端的文件队列里面,文件一个一个排着队,等第一个文件上传完了,在上传第二个文件,
     * 前端反复多次调用这个方法,mulitiFIleFileName为当前正在上传的文件名
     */
    public void ajaxAttachUpload2() {
            String path =  "d:\test\"+multiFileFileName;
            /**
             * TODO:可添加自己的业务逻辑实现
             * fileSize;//所有文件的总大小
             * multiFileName  ;// 文件名列表
             * fileSizeOneByOne;//每个文件大小
             * 
             * 后台已经可以拿到这些属性,可以根据每个文件的大小,和总大小计算出  上传的进度百分比等。
             * 或者可以 判断文件上传的大小是否正确。是否丢字节。
             */
             try {
                //拿到当前正在上传的文件对象
                File file = this.getMultiFile();
                FileUtil.randomAccessFile(path, file);
                if(StringUtils.isEmpty(chunk)){
                    //不分片的情况
                    outJson("0", "success", "");
                }else{
                //分片的情况
                //chunk 分片索引,下标从0开始
                //chunks 总分片数
                    if (Integer.valueOf(chunk) == (Integer.valueOf(chunks) - 1)) {
                        outJson("0", "上传成功", "");
                    } else {
                        outJson("2", "上传中" + fileFileName + " chunk:" + chunk, "");
                    }
                }
            } catch (Exception e) {
                outJson("3", "上传失败", "");
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

内容的评论 3


王皓

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat

王皓

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat

王皓

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat

发表评论

提交评论