您的位置:首页 > 其它

AJAX实现基于WEB的文件上传的进度控制

2010-03-22 08:53 731 查看
1.引言
2.实现代码
2.1.服务器端代码
2.1.1. 文件上传状态类(FileUploadStatus)
2.1.2. 文件上传状态侦听类(FileUploadListener)
2.1.3. 后台服务类(BackGroundService)
2.1.4. 文件上传状态控制类(BeanControler)
2.2. 客户端代码
2.2.1. AjaxWrapper.js
2.2.2. fileUpload.html
2.2.3. result.jsp
2.2.4. fileUpload.css
2.3. 配置文件
3. 结语
1. 引言
返回
   基于浏览器的文件上传,特别是对于通过<input type="file">标签来实现上传的情况,
存在着严重的性能问题,因为用户提交了文件之后,在浏览器把文件上传到服务器的过程中,界面看上去
似乎是静止的,如果是小文件还好些,如果不幸需要上传的是几兆、几十兆甚至上百兆的文件,我相信那是
一种非常痛苦的体验,我们中间的很多人应该都有过此种不堪的经历。(一笑)

  现在我就针对这个问题给出一个解决方案,我们将实现一个具有监控能力的WEB上传的程序——它不仅
把文件上传到服务器,而且"实时地"监视文件上传的实际过程。

解决方案的基本思路是这样的:

  在Form提交上传文件同时,使用AJAX周期性地从Servlet轮询上传状态信息
  然后,根据此信息更新进度条和相关文字,及时反映文件传输状态
  如果用户取消上传操作,则进行相应的现场清理工作:删除已经上传的文件,在Form提交页面中显示相关信息
  如果上传完毕,显示已经上传的文件内容(或链接)
在介绍源代码之前,我们先来看看程序运行界面:

2. 实现代码
返回
   实现代码想当然的有服务器端代码和客户端代码(呵呵),我们先从服务器端开始。

2.1. 服务器端代码
2.1.1. 文件上传状态类(FileUploadStatus)
返回
   使用FileUploadStatus这个类记录文件上传状态,并将其作为服务器端与
web客户端之间通信的媒介,通过对这个类对象提供上传状态作为服务器回应发送给web客户端,
web客户端使用JavaScript获得文件上传状态。源代码如下:

/**
* 本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。
*
* 如需要转载,请注明作者。
*
* 作者: 刘作晨
*
*/
package liuzuochen.sample.upload;

import java.util.*;

public class FileUploadStatus {
//上传用户地址
private String uploadAddr;
//上传总量
private long uploadTotalSize = 0;
//读取上传总量
private long readTotalSize = 0;
//当前上传文件号
private int currentUploadFileNum = 0;
//成功读取上传文件数
private int successUploadFileCount = 0;
//状态
private String status = "";
//处理起始时间
private long processStartTime = 0l;
//处理终止时间
private long processEndTime = 0l;
//处理执行时间
private long processRunningTime = 0l;
//上传文件URL列表
private List uploadFileUrlList = new ArrayList();
//取消上传
private boolean cancel = false;
//上传base目录
private String baseDir = "";

public FileUploadStatus() {

}

public String getBaseDir() {
return baseDir;
}

public void setBaseDir(String baseDir) {
this.baseDir = baseDir;
}

public boolean getCancel() {
return cancel;
}

public void setCancel(boolean cancel) {
this.cancel = cancel;
}

public List getUploadFileUrlList() {
return uploadFileUrlList;
}

public void setUploadFileUrlList(List uploadFileUrlList) {
this.uploadFileUrlList = uploadFileUrlList;
}

public long getProcessRunningTime() {
return processRunningTime;
}

public void setProcessRunningTime(long processRunningTime) {
this.processRunningTime = processRunningTime;
}

public long getProcessEndTime() {
return processEndTime;
}

public void setProcessEndTime(long processEndTime) {
this.processEndTime = processEndTime;
}

public long getProcessStartTime() {
return processStartTime;
}

public void setProcessStartTime(long processStartTime) {
this.processStartTime = processStartTime;
}

public long getReadTotalSize() {
return readTotalSize;
}

public void setReadTotalSize(long readTotalSize) {
this.readTotalSize = readTotalSize;
}

public int getSuccessUploadFileCount() {
return successUploadFileCount;
}

public void setSuccessUploadFileCount(int successUploadFileCount) {
this.successUploadFileCount = successUploadFileCount;
}

public int getCurrentUploadFileNum() {
return currentUploadFileNum;
}

public void setCurrentUploadFileNum(int currentUploadFileNum) {
this.currentUploadFileNum = currentUploadFileNum;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public long getUploadTotalSize() {
return uploadTotalSize;
}

public String getUploadAddr() {
return uploadAddr;
}

public void setUploadTotalSize(long uploadTotalSize) {
this.uploadTotalSize = uploadTotalSize;
}

public void setUploadAddr(String uploadAddr) {
this.uploadAddr = uploadAddr;
}

public String toJSon() {
StringBuffer strJSon = new StringBuffer();
strJSon.append("{UploadTotalSize:").append(getUploadTotalSize()).append(
",")
.append("ReadTotalSize:").append(getReadTotalSize()).append(",")
.append("CurrentUploadFileNum:").append(getCurrentUploadFileNum()).
append(",")
.append("SuccessUploadFileCount:").append(
getSuccessUploadFileCount()).append(",")
.append("Status:'").append(getStatus()).append("',")
.append("ProcessStartTime:").append(getProcessStartTime()).
append(",")
.append("ProcessEndTime:").append(getProcessEndTime()).append(
",")
.append("ProcessRunningTime:").append(getProcessRunningTime()).
append(",")
.append("Cancel:").append(getCancel()).append("}");
return strJSon.toString();

}

}

2.1.2. 文件上传状态侦听类(FileUploadListener)
返回
   使用Common-FileUpload 1.2版本(20070103)。此版本提供了能够监视文件上传情况的
ProcessListener接口,使开发者通过FileUploadBase类对象的setProcessListener方法植
入自己的Listener。 FileUploadListener类实现了ProcessListener,在整个文件上传过程
中,它对上传进度进行监控,并且根据上传 情况实时的更新上传状态Bean。源代码如下:

/**
* 本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。
*
* 如需要转载,请注明作者。
*
* 作者: 刘作晨
*
*/
package liuzuochen.sample.upload;

import org.apache.commons.fileupload.ProgressListener;
import javax.servlet.http.HttpServletRequest;

public class FileUploadListener implements ProgressListener{
private HttpServletRequest request=null;

public FileUploadListener(HttpServletRequest request){
this.request=request;
}

/**
* 更新状态
*/
public void update(long pBytesRead, long pContentLength, int pItems){
FileUploadStatus statusBean= BackGroundService.getStatusBean(request);
statusBean.setUploadTotalSize(pContentLength);
//读取完成
if (pContentLength == -1) {
statusBean.setStatus("完成对" + pItems +"个文件的读取:读取了 " + pBytesRead + " bytes.");
statusBean.setReadTotalSize(pBytesRead);
statusBean.setSuccessUploadFileCount(pItems);
statusBean.setProcessEndTime(System.currentTimeMillis());
statusBean.setProcessRunningTime(statusBean.getProcessEndTime());
//读取中
} else {
statusBean.setStatus("当前正在处理第" + pItems +"个文件:已经读取了 " + pBytesRead + " / " + pContentLength+ " bytes.");
statusBean.setReadTotalSize(pBytesRead);
statusBean.setCurrentUploadFileNum(pItems);
statusBean.setProcessRunningTime(System.currentTimeMillis());
}
BackGroundService.saveStatusBean(request,statusBean);
}
}

2.1.3. 后台服务类(BackGroundService)
返回
   BackGroundService这个Servlet类负责接收Form Post数据、回应状态轮询请求、处理取
消文件上传的请求。 尽管可以把这些功能相互分离开来,但为了简单明了,还是将它们放到
Servlet中,只是由不同的方法进行分割。 源代码如下:

/**
* 本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。
*
* 如需要转载,请注明作者。
*
* 作者: 刘作晨
*
*/
package liuzuochen.sample.upload;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.*;

public class BackGroundService extends javax.servlet.http.HttpServlet implements
javax.servlet.Servlet {

public static final String UPLOAD_DIR = "/upload";
public static final String DEFAULT_UPLOAD_FAILURE_URL = "./result.jsp";

public BackGroundService() {
super();
}

protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
doPost(request, response);
}

/**
* 从文件路径中取出文件名
*/
private String takeOutFileName(String filePath) {
int pos = filePath.lastIndexOf(File.separator);
if (pos > 0) {
return filePath.substring(pos + 1);
} else {
return filePath;
}
}

/**
* 从request中取出FileUploadStatus Bean
*/
public static FileUploadStatus getStatusBean(
HttpServletRequest request) {
BeanControler beanCtrl = BeanControler.getInstance();
return beanCtrl.getUploadStatus(request.getRemoteAddr());
}

/**
* 把FileUploadStatus Bean保存到类控制器BeanControler
*/
public static void saveStatusBean(
HttpServletRequest request,
FileUploadStatus statusBean) {
statusBean.setUploadAddr(request.getRemoteAddr());
BeanControler beanCtrl = BeanControler.getInstance();
beanCtrl.setUploadStatus(statusBean);
}

/**
* 删除已经上传的文件
*/
private void deleteUploadedFile(HttpServletRequest request) {
FileUploadStatus satusBean = getStatusBean(request);
for (int i = 0; i < satusBean.getUploadFileUrlList().size(); i++) {
File uploadedFile = new File(request.getRealPath(UPLOAD_DIR) +
File.separator +
satusBean.getUploadFileUrlList().
get(i));
uploadedFile.delete();
}
satusBean.getUploadFileUrlList().clear();
satusBean.setStatus("删除已上传的文件");
saveStatusBean(request, satusBean);
}

/**
* 上传过程中出错处理
*/
private void uploadExceptionHandle(
HttpServletRequest request,
String errMsg) throws ServletException, IOException {
//首先删除已经上传的文件
deleteUploadedFile(request);
FileUploadStatus satusBean = getStatusBean(request);
satusBean.setStatus(errMsg);
saveStatusBean(request, satusBean);
}

/**
* 初始化文件上传状态Bean
*/
private FileUploadStatus initStatusBean(HttpServletRequest
request) {
FileUploadStatus satusBean = new FileUploadStatus();
satusBean.setStatus("正在准备处理");
satusBean.setUploadTotalSize(request.getContentLength());
satusBean.setProcessStartTime(System.currentTimeMillis());
satusBean.setBaseDir(request.getContextPath() + UPLOAD_DIR);
return satusBean;
}

/**
* 处理文件上传
*/
private void processFileUpload(HttpServletRequest request,
HttpServletResponse response) throws
ServletException, IOException {
DiskFileItemFactory factory = new DiskFileItemFactory();
//设置内存缓冲区,超过后写入临时文件
factory.setSizeThreshold(10240000);
//设置临时文件存储位置
factory.setRepository(new File(request.getRealPath("/upload/temp")));
ServletFileUpload upload = new ServletFileUpload(factory);
//设置单个文件的最大上传值
upload.setFileSizeMax(102400000);
//设置整个request的最大值
upload.setSizeMax(102400000);
upload.setProgressListener(new FileUploadListener(request));
//保存初始化后的FileUploadStatus Bean
saveStatusBean(request, initStatusBean(request));

String forwardURL = "";
try {
List items = upload.parseRequest(request);
//获得返回url
for (int i = 0; i < items.size(); i++) {
FileItem item = (FileItem) items.get(i);
if (item.isFormField()) {
forwardURL = item.getString();
break;
}
}
//处理文件上传
for (int i = 0; i < items.size(); i++) {
FileItem item = (FileItem) items.get(i);

//取消上传
if (getStatusBean(request).getCancel()) {
deleteUploadedFile(request);
break;
}
//保存文件
else if (!item.isFormField() && item.getName().length() > 0) {
String fileName = takeOutFileName(item.getName());
File uploadedFile = new File(request.getRealPath(UPLOAD_DIR) +
File.separator + fileName);
item.write(uploadedFile);
//更新上传文件列表
FileUploadStatus satusBean =
getStatusBean(request);
satusBean.getUploadFileUrlList().add(fileName);
saveStatusBean(request, satusBean);
Thread.sleep(500);
}
}

} catch (FileUploadException e) {
uploadExceptionHandle(request, "上传文件时发生错误:" + e.getMessage());
} catch (Exception e) {
uploadExceptionHandle(request, "保存上传文件时发生错误:" + e.getMessage());
}
if (forwardURL.length() == 0) {
forwardURL = DEFAULT_UPLOAD_FAILURE_URL;
}
request.getRequestDispatcher(forwardURL).forward(request, response);
}

/**
* 回应上传状态查询
*/
private void responseStatusQuery(HttpServletRequest request,
HttpServletResponse response) throws
IOException {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.setHeader("Cache-Control", "no-cache");
FileUploadStatus satusBean = getStatusBean(request);
response.getWriter().write(satusBean.toJSon());
}

/**
* 处理取消文件上传
*/
private void processCancelFileUpload(HttpServletRequest request,
HttpServletResponse response) throws
IOException {
FileUploadStatus satusBean = getStatusBean(request);
satusBean.setCancel(true);
saveStatusBean(request, satusBean);
responseStatusQuery(request, response);
}

protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
processFileUpload(request, response);
} else {
request.setCharacterEncoding("UTF-8");

if (request.getParameter("uploadStatus") != null) {
responseStatusQuery(request, response);
}
if (request.getParameter("cancelUpload") != null) {
processCancelFileUpload(request, response);
}

}
}
}

2.1.4. 文件上传状态控制类(BeanControler)
返回
   这是一个单例类,它的功能是为客户端保存文件上传状态,这里我没有使用Session来存储
文件上传状态,因为对于AJAX这种异步调用,服务器会开启不同的Session,所以无法通过Session
保存文件上传状态。 我并不认为这种方法最好,如果有更好的方法,欢迎大家一起讨论。 源代码如下:

/**
* 本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。
*
* 如需要转载,请注明作者。
*
* 作者: 刘作晨
*
*/
package liuzuochen.sample.upload;

import java.util.Vector;

public class BeanControler {
private static BeanControler beanControler = new BeanControler();
private Vector vector = new Vector();
private BeanControler() {
}

public static BeanControler getInstance() {
return beanControler;
}

/**
* 取得相应FileUploadStatus类对象的存储位置
*/
private int indexOf(String strID) {
int nReturn = -1;
for (int i = 0; i < vector.size(); i++) {
FileUploadStatus status = (FileUploadStatus) vector.elementAt(i);
if (status.getUploadAddr().equals(strID)) {
nReturn = i;
break;
}
}
return nReturn;
}
/**
* 取得相应FileUploadStatus类对象
*/
public FileUploadStatus getUploadStatus(String strID) {
return (FileUploadStatus) vector.elementAt(indexOf(strID));
}
/**
* 存储FileUploadStatus类对象
*/
public void setUploadStatus(FileUploadStatus status) {
int nIndex = indexOf(status.getUploadAddr());
if ( -1 == nIndex) {
vector.add(status);
} else {
vector.insertElementAt(status, nIndex);
vector.removeElementAt(nIndex + 1);
}
}
/**
* 删除FileUploadStatus类对象
*/
public void removeUploadStatus(String strID){
int nIndex = indexOf(strID);
if(-1!=nIndex)
vector.removeElementAt(nIndex);
}
}

2.2. 客户端代码
   客户端我们采用Prototype框架。

2.2.1. AjaxWrapper.js
返回
   AjaxWrapper.js对Prototype进行了封装。 源代码如下:

//类工具
var ClassUtils=Class.create();
ClassUtils.prototype={
_ClassUtilsName:'ClassUtils',
initialize:function(){
},
/**
* 给类的每个方法注册一个对类对象的自我引用
* @param reference 对类对象的引用
*/
registerFuncSelfLink:function(reference){
for (var n in reference) {
var item = reference
;
if (item instanceof Function)
item.$ = reference;
}
}
}
//Ajax操作封装类:
//由于调用AjaxRequest类进行XMLHTTPRequest操作时,this引用(指向当前的对象)会出现了call stack问题,从而指向当前的对象。
//所以,对putRequest、callBackHandler、以及callback方法都要使用arguments.callee.$来获得正确的类对象引用
var AjaxWrapper=Class.create();
AjaxWrapper.prototype={
debug_flag:false,
xml_source:'',
/**
* 初始化
* @param isDebug 是否显示调试信息
*/
initialize:function(isDebug){
new ClassUtils().registerFuncSelfLink(this);
this.debug_flag=isDebug;
},
/**
* 以get的方式向server发送request
* @param url
* @param params
* @param callBackFunction 发送成功后回调的函数或者函数名
*/
putRequest:function(url,params,callBackFunction){
var funcHolder=arguments.callee.$;
var xmlHttp = new Ajax.Request(url,
{
method: 'get',
parameters: params,
requestHeaders:['my-header-encoding','utf-8'],
onFailure: function(){
alert('对不起,网络通讯失败,请重新刷新!');
},
onSuccess: function(transport){
},
onComplete: function(transport){
funcHolder.callBackHandler.apply(funcHolder,[transport,callBackFunction]);
}
});
},
/**
* 以post的方式向server发送xml请求
* @param url
* @param postDataBody
* @param callBackFunction 发送成功后回调的函数或者函数名
*/
pushRequest:function(url,postDataBody,callBackFunction){
var funcHolder=arguments.callee.$;
var options={
method: 'post',
parameters:'',
requestHeaders:['my-header-encoding','utf-8'],
postBody: postDataBody,
onFailure: function(transport){
alert('对不起,网络通讯失败,请重新发送!');
},
onComplete: function(transport){
funcHolder.callBackHandler.apply(funcHolder,[transport,callBackFunction]);
}
};
var xmlHttp = new Ajax.Request(url,options);
},
/**
* 远程调用的回调处理
* @param transport xmlhttp的transport
* @param callBackFunction 回调时call的方法,可以是函数也可以是函数名
*/
callBackHandler:function(transport,callBackFunction){
var funcHolder=arguments.callee.$;
if(transport.status!=200){
alert("获得回应失败,请求状态:"+transport.status);
}
else{
funcHolder.xml_source=transport.responseText;
if (funcHolder.debug_flag)
alert('call callback function');
if (typeof(callBackFunction)=='function'){
if (funcHolder.debug_flag){
alert('invoke callbackFunc');
}
callBackFunction(transport.responseText);
}
else{
if (funcHolder.debug_flag){
alert('evalFunc callbackFunc');
}
new execute().evalFunc(callBackFunction,transport.responseText);
}
if (funcHolder.debug_flag)
alert('end callback function');
}
},
//显示xml信息
showXMLResponse:function(){
var funcHolder=arguments.callee.$;
alert(funcHolder.xml_source);
}
}
var XMLDomForAjax=Class.create();
XMLDomForAjax.prototype={
isDebug:false,
//dom节点类型常量
ELEMENT_NODE:1,
ATTRIBUTE_NODE:2,
TEXT_NODE:3,
CDATA_SECTION_NODE:4,
ENTITY_REFERENCE_NODE:5,
ENTITY_NODE:6,
PROCESSING_INSTRUCTION_NODE:7,
COMMENT_NODE:8,
DOCUMENT_NODE:9,
DOCUMENT_TYPE_NODE:10,
DOCUMENT_FRAGMENT_NODE:11,
NOTATION_NODE:12,
initialize:function(isDebug){
new ClassUtils().registerFuncSelfLink(this);
this.isDebug=isDebug;
},
/**
* 建立跨平台的dom解析器
* @param xml xml字符串
* @return dom解析器
*/
createDomParser:function(xml){
// code for IE
if (window.ActiveXObject){
var doc=new ActiveXObject("Microsoft.XMLDOM");
doc.async="false";
doc.loadXML(xml);
}
// code for Mozilla, Firefox, Opera, etc.
else{
var parser=new DOMParser();
var doc=parser.parseFromString(xml,"text/xml");
}
return doc;
},
/**
* 反向序列化xml到javascript Bean
* @param xml xml字符串
* @return javascript Bean
*/
deserializedBeanFromXML:function (xml){
var funcHolder=arguments.callee.$;
var doc=funcHolder.createDomParser(xml);
// documentElement总表示文档的root
var objDomTree=doc.documentElement;
var obj=new Object();
for (var i=0; i<objDomTree.childNodes.length; i++) {
//获得节点
var node=objDomTree.childNodes[i];
//取出其中的field元素进行处理
if ((node.nodeType==funcHolder.ELEMENT_NODE) && (node.tagName == 'field')) {
var nodeText=funcHolder.getNodeText(node);
if (funcHolder.isDebug){
alert(node.getAttribute('name')+' type:'+node.getAttribute('type')+' text:'+nodeText);
}
var objFieldValue=null;
//如果为列表
if (node.getAttribute('type')=='java.util.List'){
if (objFieldValue && typeof(objFieldValue)=='Array'){
if (nodeText.length>0){
objFieldValue[objFieldValue.length]=nodeText;
}
}
else{
objFieldValue=new Array();
}
}
else if (node.getAttribute('type')=='long'
|| node.getAttribute('type')=='java.lang.Long'
|| node.getAttribute('type')=='int'
|| node.getAttribute('type')=='java.lang.Integer'){
objFieldValue=parseInt(nodeText);
}
else if (node.getAttribute('type')=='double'
|| node.getAttribute('type')=='float'
|| node.getAttribute('type')=='java.lang.Double'
|| node.getAttribute('type')=='java.lang.Float'){
objFieldValue=parseFloat(nodeText);
}
else if (node.getAttribute('type')=='java.lang.String'){
objFieldValue=nodeText;
}
else{
objFieldValue=nodeText;
}
//赋值给对象
obj[node.getAttribute('name')]=objFieldValue;
if (funcHolder.isDebug){
alert(eval('obj.'+node.getAttribute('name')));
}
}
else if (node.nodeType == funcHolder.TEXT_NODE){
if (funcHolder.isDebug){
//alert('TEXT_NODE');
}
}
else if (node.nodeType == funcHolder.CDATA_SECTION_NODE){
if (funcHolder.isDebug){
//alert('CDATA_SECTION_NODE');
}
}
}
return obj;
},
/**
* 获得dom节点的text
*/
getNodeText:function (node) {
var funcHolder=arguments.callee.$;
// is this a text or CDATA node?
if (node.nodeType == funcHolder.TEXT_NODE || node.nodeType == funcHolder.CDATA_SECTION_NODE) {
return node.data;
}
var i;
var returnValue = [];
for (i = 0; i < node.childNodes.length; i++) {
//采用递归算法
returnValue.push(funcHolder.getNodeText(node.childNodes[i]));
}
return returnValue.join('');
}
}
//委托者类
var Dispatcher=Class.create();
Dispatcher.prototype={
name:'Dispatcher',
//对class中的每个function都赋值一个值为this的$属性
initialize:function(){
new ClassUtils().registerFuncSelfLink(this);
},
/**
* 委托调用
* @param caller 调用者,func的拥有者
* @param func 如果是function对象,则使用Dispatcher对象自己的name作为参数;否则直接调用func
*/
dispatch:function(caller,func){
if (func instanceof Function){
var funcArguments=new Array();
funcArguments[0]=arguments.callee.$.name;
func.apply(caller,funcArguments);
}
else{
eval(func);
}
}
}
//祈祷者类
var Invoker=Class.create();
Invoker.prototype={
name:'Invoker',
initialize:function(){
},
invoke:function(showMsg){
alert(showMsg+"——this.name="+this.name);
}
}

2.2.2. fileUpload.html
返回
   fileUpload.html是文件上传界面。 源代码如下:

<html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<script type="text/javascript" src="./javascript/prototype.js"></script>
<script type="text/javascript" src="./javascript/AjaxWrapper.js"></script>
<link href="./css/fileUpload.css" type="text/css" rel="stylesheet"/>
<title>文件上传</title>
</head>
<body>
<div id="controlPanel">
<div id="readme">测试说明: 最大上传量:100M,单个文件最大长度:100M</div>
<div id="uploadFileUrl"></div>
<form id="fileUploadForm" name="fileUploadForm" action="./BackGroundService.action"
enctype="multipart/form-data" method="post">
<input type="file" name="file" id="file" size="40"/><br>
<input type="file" name="file" id="file" size="40"/><br>
<input type="file" name="file" id="file" size="40"/><br>
<input type="submit" name="uploadButton" id="uploadButton" value="开始上传"/>
<input type="button" name="cancelUploadButton" id="cancelUploadButton" value="取消上传"/><br>
</form>
<div id="progressBar">
<div id="theMeter">
<div id="progressBarText"></div>
<div id="totalProgressBarBox">
<div id="totalProgressBarBoxContent"></div>
</div>
</div>
<div id="progressStatusText"></div>
</div>
</div>
<script>
Element.hide('progressBar');
Event.observe('fileUploadForm','submit',startProgress,false);
Event.observe('cancelUploadButton','click',cancelProgress,false);

//刷新上传状态
function refreshUploadStatus(){
var ajaxW = new AjaxWrapper(false);
ajaxW.putRequest(
'./BackGroundService.action',
'uploadStatus=',
function(responseText){
eval("uploadInfo = " + responseText);
var progressPercent = Math.ceil(
(uploadInfo.ReadTotalSize) / uploadInfo.UploadTotalSize * 100);

$('progressBarText').innerHTML = ' 上传处理进度: '+progressPercent+'% ['+
(uploadInfo.ReadTotalSize)+'/'+uploadInfo.UploadTotalSize + ' bytes]'+
' 正在处理第'+uploadInfo.CurrentUploadFileNum+'个文件'+
' 耗时: '+(uploadInfo.ProcessRunningTime-uploadInfo.ProcessStartTime)+' ms';
$('progressStatusText').innerHTML=' 反馈状态: '+uploadInfo.Status;
$('totalProgressBarBoxContent').style.width = parseInt(progressPercent * 3.5) + 'px';
}
);
}
//上传处理
function startProgress(){
Element.show('progressBar');
$('progressBarText').innerHTML = ' 上传处理进度: 0%';
$('progressStatusText').innerHTML=' 反馈状态:';
$('uploadButton').disabled = true;
var periodicalExe=new PeriodicalExecuter(refreshUploadStatus,0.5);
return true;
}
//取消上传处理
function cancelProgress(){
$('cancelUploadButton').disabled = true;
var ajaxW = new AjaxWrapper(false);
ajaxW.putRequest(
'./BackGroundService.action',
'cancelUpload=true',
//因为form的提交,这可能不会执行
function(responseText){
eval("uploadInfo = " + responseText);
$('progressStatusText').innerHTML=' 反馈状态: '+uploadInfo.status;
if (msgInfo.cancel=='true'){
alert('删除成功!');
window.location.reload();
};
}
);
}
</script>
</body>
</html>

2.2.3. result.jsp
返回
   result.jsp是文件上传结果显示界面。 源代码如下:

<%@ page language="java"
contentType="text/html; charset=GBK"
pageEncoding="GBK"%>
<%@ page import="liuzuochen.sample.upload.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<link href="./css/fileUpload.css" type="text/css" rel="stylesheet"/>
<title>文件上传结果</title>
</head>
<body>
<div id="resultPanel">
<div><span>上传文件列表:</span></div>
<%
FileUploadStatus fUploadStatus=BackGroundService.getStatusBean(request);
for(int i=0;i<fUploadStatus.getUploadFileUrlList().size();i++){
String fileName=(String)fUploadStatus.getUploadFileUrlList().get(i);
String url=fUploadStatus.getBaseDir()+"/"+fileName;
%>
<div><a href="<%=url%>" _fcksavedurl="<%=url%>" _fcksavedurl="<%=url%>"
_fcksavedurl="<%=url%>"><%=fileName%></a></div>
<%
}
if (fUploadStatus.getStatus().indexOf("错误")>=0){
%>
<div id='errorArea'><span>错误信息:<%=fUploadStatus.getStatus() %></span></div>
<%
}
else if (fUploadStatus.getCancel()){
%>
<div id='normalMessageArea'><span>由于用户取消上传,所以已经上传的文件均被删除</span></div>
<%
}
BeanControler.getInstance().removeUploadStatus(request.getRemoteAddr());
%>
</div>
</body>
</html>
2.2.4. fileUpload.css
返回
   fileUpload.css是样式文件。 源代码如下:

body {
color:#000;
background-color:white;
font:15px Georgia, "Lucida Grande", Arial, sans-serif;
letter-spacing:0.01em;
margin:15px;
}
#controlPanel,#resultPanel{
width:700px;
margin:20px auto;
padding:25px;
border:3px solid gray;
-moz-border-radius:10px;
background:#f8f8f8;
}
#errorArea{
width:400px;
margin:20px auto;
padding:25px;
border:3px solid gray;
-moz-border-radius:10px;
background:red;
}
#normalMessageArea{
width:400px;
margin:20px auto;
padding:25px;
border:3px solid gray;
-moz-border-radius:10px;
background:yellow;
}
#progressBar { padding-top: 5px; }
#totalProgressBarBox {
width: 350px;
height: 20px;
border: 1px inset;
background: #eee;
}
#totalProgressBarBoxContent {
width: 0;
height: 20px;
border-right: 1px solid #444;
background: #9ACB34;
}
2.3. 配置文件
返回
   把如下代码加入web.xml中完成Servlet的配置。

<servlet>
<br><description>
<br></description>
<br><display-name>
<br>BackGroundService</display-name>
<br><servlet-name>BackGroundService</servlet-name>
<br><servlet-class>
<br>liuzuochen.sample.upload.BackGroundService</servlet-class>
<br></servlet>
<br><servlet-mapping>
<servlet-name>BackGroundService</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
3. 结语
返回
   整个程序到这里就介绍完了,希望它多少能为您的工作或学习带来点儿帮助。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: