(1)精简“带进度条文件上传组件”的设计与实现
XMLHttpRequest第二版为我们提供了便利的progress事件,通过为xhr.upload.onprogress指定处理函数,可以快速制作进度条,JQuery插件参考代码如下:
(function($) {
$.fn.uploader = function(userOptions) {
var options = {
id : "uploader",
url : "uploadAction.action?fileName=",//处理上传文件的服务器url
width : 540,//整个控件div层的宽度
height : 180
//整个控件div层的高度
};
$.extend(options, userOptions);
var createUploader = function(where) {
var uploader = $("<div id='" + options.id + "'></div>").css({
"display" : "block",
"position" : "relative",
"width" : options.width,
"height" : options.height,
"overflow" : "hidden"
});
//创建上传文件控件
var fileUI = $("<input id='file' type='file'>").addClass("");
uploader.append(fileUI);
//创建上传文件按钮,并实现点击事件
var uploadBtn = $("<input id='uploadBtn' type='button' value='上传'>")
.click(
function() {
var fileUI = document.getElementById("file");
if (fileUI.files.length > 0) {
var file = fileUI.files[0];//取出文件blob
var xhr = new XMLHttpRequest();
//指定处理上传进度的函数
xhr.upload.onprogress = updateProgress;
//处理上传
xhr.open("POST", options.url
+ encodeURIComponent(file.name),
true);
xhr.overrideMimeType("application/octet-stream");
xhr.send(file);
//处理响应
xhr.onreadystatechange = function() {
if (xhr.readyState == 4
&& xhr.status == 200) {
console.log(xhr.responseText);
} else {
console.log(xhr.statusText);
}
};
console.log("upload complete");
} else {
alert("请选择上传文件!");
}
});
uploader.append(uploadBtn);
var progressBar = $("<div></div>").addClass("progressBar");
var progress = $("<p></p>");
progressBar.append(progress);
uploader.append(progressBar);
var updateProgress = function(event) {
if (event.lengthComputable) {
var percentage = Math.round((event.loaded * 100)
/ event.total);
console.log("percentage:" + percentage);
if (percentage < 100) {
progress.css("width", (percentage * 2) + "px");
progress.text(percentage + "%");
} else {
progress.css("width", "200px");
progress.text("100%");
}
}
};
where.append(uploader);
}
createUploader(this);
}
}(jQuery));
服务器端可以利用struts2对上传请求进行处理,将其保存到文件系统,参考代码如下:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class FileUploadAction extends ActionSupport {
private static String SEPARATOR = File.separator;
public InputStream inputStream = null;
public InputStream getIn() {
return inputStream;
}
@Override
public String execute() {
BufferedInputStream fileIn = null;
BufferedOutputStream fileOut = null;
String fileName = ServletActionContext.getRequest().getParameter("fileName");
String path = ServletActionContext.getRequest().getSession().getServletContext().getRealPath("/");
try{
fileIn = new BufferedInputStream(
ServletActionContext.getRequest().getInputStream());
File file = new File(path + SEPARATOR + fileName);
byte[] buf = new byte[1024];
fileOut = new BufferedOutputStream(
new FileOutputStream(file, true));
int length = 0;
while ((length = fileIn.read(buf)) != -1) {
fileOut.write(buf, 0, length);
}
} catch(IOException e){
e.printStackTrace();
return ERROR;
} finally {
if(fileIn != null){
try {
fileIn.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(fileOut != null){
try {
fileOut.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
try {
inputStream = new ByteArrayInputStream("upload finished".getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return SUCCESS;
}
}
Struts2配置参考:
<package name="myjson" namespace="" extends="json-default">
<action name="uploadAction" class="FileUploadAction">
<result type="stream">
<param name="contentType">
text/html
</param>
<param name="inputName">
inputStream
</param>
</result>
</action>
</package>
进度条可以简单的利用div进行实现,参考样式如下:
.progressBar {
width: 200px;
height: 20px;
border: 1px solid #000;
-moz-border-radius: 8px;
margin-bottom: 10px;
}
.progressBar p {
margin: 0px;
width: 0px;
height: 20px;
-moz-border-radius: 8px;
background-color: #00FF00;
}
使用插件实现文件上传功能:
(2)改进一下,如何实现暂停和重启
暂停和重启功能,前端需要依赖Blob对象(事实上一个File原型链的上一层就是Blob)的分割(slice)方法,典型的分割函数如下:
var sliceBlob = function(blob, start, end, type) {
var force_saveable_type = 'application/octet-stream';
if (type && type == force_saveable_type) {
var slice = blob.slice || blob.webkitSlice || blob.mozSlice;
blob = slice.call(blob, start, end, type);
}
return blob;
}
通过分割函数我们就可以完成对文件进行分块上传并且控制是否暂停和进度条的显示逻辑,JQuery插件参考代码如下:
(function($){
$.fn.uploader = function(userOptions){
var options = {
id : "uploader",
url: "uploadAction.action?fileName=",
width : 540,//整个控件div层的宽度
height : 180//整个控件div层的高度
};
$.extend(options, userOptions);
var sliceBlob = function(blob, start, end, type) {
var force_saveable_type = 'application/octet-stream';
if (type && type == force_saveable_type) {
var slice = blob.slice || blob.webkitSlice || blob.mozSlice;
blob = slice.call(blob, start, end, type);
}
return blob;
}
va