Java中使⽤WebUploader插件上传⼤⽂件单⽂件和多⽂件的⽅法
⼩结
⼀.使⽤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直接报上图这个错了。没办法。换插件。
⼆.插件选择
功能确实很强⼤,不过CSS样式固定死了,和我现在项⽬的进度条样式很不⼀样。还是放弃了这个插件
2.Webuploader 插件。WebUploader是由Baidu WebFE(FEX)团队开发的⼀个简单的以HTML5为主,FLASH为辅的现代⽂件上传组件。在现代的浏览器⾥⾯能充分发挥HTML5的优势,同时⼜不摒弃主流
IE浏览器,沿⽤原来的FLASH运⾏时,兼容IE6+,iOS 6+, Android 4+。两套运⾏时,同样的调⽤⽅式,可供⽤户任意选⽤。
三.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>
2.引⼊CSS样式
<link href="../main/css/webuploader.css" rel="stylesheet" type="text/css" />
3.引⼊SWF,SWF不直接引⽤,在webUploader初始化的时候指定SWF的路径就可以了。
4.upload3.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/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>
画⾯⽐较简单,长这个样⼦
5.upload3.js
包含单⽂件上传,多⽂件上传,和webuploader多实例
/*********************************WebUpload 单⽂件上传 begin*****************************************/
$(function(){
var $list = $("#thelist");
var uploader ;// 实例化
uploader = ate({
auto:false, //是否⾃动上传
pick: {
id: '#attach',
name:"file", //这个地⽅ name 没什么⽤,虽然打开调试器,input的名字确实改过来了。但是提交到后台取不到⽂件。如果想⾃定义file的name属性,还是要和fileVal 配合使⽤。label: '点击选择图⽚',
multiple:false //默认为true,就是可以多选
},
swf: '../../main/js/Uploader.swf',
//fileVal:'multiFile', //⾃定义file的name属性,我⽤的版本是0.1.5 ,打开客户端调试器发现⽣成的input 的name 没改过来。
//名字还是默认的file,但不是没⽤哦。虽然客户端名字没改变,但是提交到到后台,是要⽤multiFile 这个对象来取⽂件的,⽤file 是取不到⽂件的
// 建议作者有时间把这个地⽅改改啊,搞死⼈了。。
server: "ContentsDetail!ajaxAttachUpload.action",
duplicate:true,//是否可重复选择同⼀⽂件
resize: false,
formData: {
"status":"file",
"tsId":"0000004730",
"uploadNum":"0000004730",
"existFlg":'false'
},
compress: null,//图⽚不压缩
chunked: true, //分⽚处理
chunkSize: 5 * 1024 * 1024, //每⽚5M
chunkRetry:false,//如果失败,则不重试
threads:1,//上传并发数。允许同时最⼤上传进程数。
// runtimeOrder: 'flash',
/
/ 禁掉全局的拖拽功能。这样不会出现图⽚拖进页⾯的时候,把图⽚打开。
disableGlobalDnd: true
});
// 当有⽂件添加进来的时候
<( "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>" );
});
/
/当所有⽂件上传结束时触发
<("uploadFinished",function(){
console.log("uploadFinished:");
})
//当某个⽂件上传到服务端响应后,会派送此事件来询问服务端响应是否有效。
<("uploadAccept",function(object,ret){
//服务器响应了
//ret._raw 类似于 data
var data =JSON.parse(ret._raw);
sultCode != "1" && sultCode != "3"){
sultCode == "9"){
alert("error");
return false;
}
}else{
//E05017
alert("error");
return false;
}
})
/
/当⽂件上传成功时触发。
<( "uploadSuccess", function( file ) {
$( "#"+file.id ).find("p.state").text("已上传");
});
<( "uploadError", function( file ) {
$( "#"+file.id ).find("p.state").text("上传出错");
uploader.cancelFile(file);
});
$("#upload").on("click", function() {
uploader.upload();
})
});
/*********************************WebUpload 单⽂件上传 end*******************************************/
/*********************************WebUpload 多⽂件上传 begin*****************************************/
$(function(){
var $list = $("#thelist1");
var fileSize = 0; //总⽂件⼤⼩
var fileName = []; //⽂件名列表
var fileSizeOneByOne =[];//每个⽂件⼤⼩
var uploader ;// 实例化
uploader = ate({
auto:false, //是否⾃动上传
pick: {
id: '#multi',
label: '点击选择⽂件',
name:"multiFile"
},
swf: '../../main/js/Uploader.swf',
server: "ContentsDetail!multiUpload.action",
duplicate:true, //同⼀⽂件是否可重复选择
resize: false,
formData: {
"status":"multi",
"tsId":"0000004730",
"uploadNum":"0000004730",
"existFlg":'false'
},
compress: null,//图⽚不压缩
chunked: true, //分⽚
chunkSize: 5 * 1024 * 1024, //每⽚5M
chunkRetry:false,//如果失败,则不重试
threads:1,//上传并发数。允许同时最⼤上传进程数。
/
/fileNumLimit:50,//验证⽂件总数量, 超出则不允许加⼊队列
// runtimeOrder: 'flash',
// 禁掉全局的拖拽功能。这样不会出现图⽚拖进页⾯的时候,把图⽚打开。
disableGlobalDnd: true
});
// 当有⽂件添加进来的时候
<( "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>" );
});
// 当开始上传流程时触发
<( "startUpload", function() {
console.log("startUpload");
//添加额外的表单参数
$.extend( true, uploader.options.formData, {"fileSize":fileSize,"multiFileName":fileName.join(","),"fileSizeOneByOne":fileSizeOneByOne.join(",")}); });
//当某个⽂件上传到服务端响应后,会派送此事件来询问服务端响应是否有效。
<("uploadAccept",function(object,ret){
//服务器响应了
//ret._raw 类似于 data
console.log("uploadAccept");
console.log(ret);
大文件发送var data =JSON.parse(ret._raw);
sultCode!="1" && sultCode !="3"){
sultCode == "9"){
alert("error");
return;
}
}else{
alert("error");
}
})
<( "uploadSuccess", function( file ) {
$( "#"+file.id ).find("p.state").text("已上传");
});
<( "uploadError", function( file,reason ) {
$( "#"+file.id ).find("p.state").text("上传出错");
console.log("uploadError");
console.log(file);
console.log(reason);
//多个⽂件
var fileArray = Files();
for(var i = 0 ;i<fileArray.length;i++){
uploader.cancelFile(fileArray[i]);
}
fileSize = 0;
fileName = [];
fileSizeOneByOne=[];
});
//当validate不通过时,会以派送错误事件的形式通知调⽤者
<("error",function(){
console.log("error");
fileSize = 0;
fileName = [];
fileSizeOneByOne=[];
alert("error");
})
//如果是在模态框⾥的上传按钮,点击file的时候不会触发控件
/
/修复model内部点击不会触发选择⽂件的BUG
/* $("#multi .webuploader-pick").click(function () {
fileSize = 0;
fileName = [];
fileSizeOneByOne=[];
$("#multi :file").click();//关键代码
});*/
//选择⽂件之后执⾏上传
$(document).on("change","input[name='multiFile']", function() {
var fileArray1 = Files();
for(var i = 0 ;i<fileArray1.length;i++){
//后台⽤
fileSize +=fileArray1[i].size;
fileSizeOneByOne.push(fileArray1[i].size);
fileName.push(fileArray1[i].name);
}
console.log(fileSize);
console.log(fileSizeOneByOne);
console.log(fileName);
})
/**
* 多⽂件上传
*/
$("input[name='multiUpload']").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的参数
status=[file], uploadNum=[0000004730]
}
*********************************************************************************************/
6.ContentsDetail.action
//单⽂件上传后台代码
public void ajaxAttachUpload() {
String path = "d:\\test\\"+fileFileName;
try {
File file = File();
FileUtil.randomAccessFile(path, file);
//如果⽂件⼩与5M的话,分⽚参数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 = ad(buf)) != -1) {
raFile.write(buf, 0, length);
}
}catch(Exception e){
throw new Message());
}finally{
try {
if (inputStream != null) {
inputStream.close();
}
if (raFile != null) {
raFile.close();
}
}catch(Exception e){
throw new Message());
}
}
}
7.效果图