最近在做一个文件上传的问题,其中遇到不少问题,Struts2实现了上传框架处理上传文件,使大伙方便安全地实现文件上传,但是许多功能的实现,只是用Struts2封装的上传框架是远远不够的,比如带进度条的文件上传,本人是找不到在运用struts的上传框架的基础上都不怎么实现,希望博友们能提供好的实现方法。于是我只能利用开源的commons-fileupload-XX.XX.jar实现所需功能。
但是其中出现了如下问题:如果在Struts2的Action里完成业务功能,拿到的文件上传请求已由Struts2的Action管理处理,你就会发现upload.parseRequest(request).getSize()拿到的大小为0。
于是我用Servlet来完成,希望文件请求直接交由Servlet来处理,一开始时Struts会出现找不到此Action的错误,原因是我在web.xml配置Struts2过滤路径的时候用<url-pattern>/*</url-pattern>,因此Servlet会交由Struts管理,并当成Action处理,结果就会报找不到Action的错误。
其中一种解决方法:对<url-pattern>进行重新定义,不再用/*,而是匹配到具体的应用。如用:/xx/*
(有关Tomcat中Filter的<url-pattern>匹配规则,请查看上一篇博文:
http://blog.sina.com.cn/s/blog_7d0b04e70101mclr.html)
另外一种解决方法:重新定义Struts的Filter
:
package com.struts.core.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
public class PBLStrutsPrepareAndExecuteFilter extends
StrutsPrepareAndExecuteFilter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String requestURI = ((HttpServletRequest) request).getRequestURI();
/*过滤指定URI,使其Servlet不进入Sturts中*/
if(requestURI != null && requestURI.contains("Servlet"))
chain.doFilter(request, response);
else
super.doFilter(request, response, chain); //交由Struts管理
}
}
当然啦,有的人会把上传进度状态存在session里面,进行会话,但是我个人觉得有点不妥!
先贴一下效果如何
1)
2)
下面是部份源码:
文件上传进度状态(FileUploadStatus.java)
package com.frozenwind.upload.util;
/**
* 一个用户上传文件由一个FileUploadStatus管理
* 其中通过上传用户地址uploadAddr标志该FileUploadStatus的唯一性
* 每个FileUploadStatus由单例FileUploadStatusManager管理
* @author Frozenwind
*
*/
public class FileUploadStatus {
public final static String SUCCESS="success";
public final static String FAIL="fail";
public final static String CANCEL="cancel";
public final static String UPLOADING="uploading";
public final static String ERROR="error";
// 上传总量
private long uploadTotalSize = 0;
// 读取上传总量
private long readTotalSize = 0;
// 状态
private String status = "";
// 处理起始时间
private long processStartTime = 0l;
private String filename=null;
public FileUploadStatus() {
}
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 String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public long getUploadTotalSize() {
return uploadTotalSize;
}
public void setUploadTotalSize(long uploadTotalSize) {
this.uploadTotalSize = uploadTotalSize;
}
public String toJSon() {
StringBuffer strJson=new StringBuffer();
strJson.append("{");
strJson.append("\"uploadTotalSize\":"+uploadTotalSize/1024);
strJson.append(",\"readTotalSize\":"+readTotalSize/1024);
strJson.append(",\"status\":\""+status+"\"");
strJson.append(",\"processStartTime\":"+ processStartTime);
strJson.append(",\"filename\":\""+filename+"\"");
strJson.append("}");
return strJson.toString();
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
}
进度管理器(FilUploadStatusManger.java)
package com.frozenwind.upload.util;
import java.util.HashMap;
import java.util.Map;
/**
* FileUploadStatus的Bean管理器,用单例模式
* @author Frozenwind
*
*/
public class FileUploadStatusManager {
private static FileUploadStatusManager fileUploadStatusManager = new FileUploadStatusManager();
private Map<String, FileUploadStatus> beans = new HashMap<String, FileUploadStatus>();
private FileUploadStatusManager() {
}
public static synchronized FileUploadStatusManager getInstance() {
return fileUploadStatusManager;
}
/**
* 创建FileUploadStatus类对象
*
* @param uploadAddr通过request
* .getRomotAddr获取
* @return
*/
public synchronized FileUploadStatus createFileUploadStatus(String uploadAddr) {
System.out.println("creat:"+uploadAddr+"("+beans.size()+")");
FileUploadStatus fus = new FileUploadStatus();
fus.setProcessStartTime(System.currentTimeMillis());
beans.put(uploadAddr, fus);
return fus;
}
/**
* 取得相应FileUploadStatus类对象
*
* @param uploadAddr通过request
* .getRomotAddr获取
* @return
*/
public synchronized FileUploadStatus getUploadStatus(String uploadAddr) {
System.out.println("get:"+uploadAddr+"("+beans.size()+")");
return beans.get(uploadAddr);
}
/**
* 删除FileUploadStatus类对象
*
* @param uploadAddr通过request
* .getRomotAddr获取
*/
public synchronized void removeFileUploadStatus(String uploadAddr) {
beans.remove(uploadAddr);
}
/**
* 更新FileUploadStatus类对象
*
* @param uploadAddr通过request
* .getRomotAddr获取
* @param fileUploadStatus
*/
public synchronized void setFileUploadStatus(String uploadAddr,
FileUploadStatus fileUploadStatus) {
System.out.println("set:"+uploadAddr+"("+beans.size()+")");
beans.put(uploadAddr, fileUploadStatus);
}
}
文件上传监听器(FileUploadListener.java)
package com.frozenwind.upload.util;
import org.apache.commons.fileupload.ProgressListener;
public class FileUploadListener implements ProgressListener{
private static FileUploadStatusManager fileUploadStatusManager=FileUploadStatusManager.getInstance();
private String remoteAddr=null;
public FileUploadListener(String remoteAddr){
this.remoteAddr=remoteAddr;
}
/**
* 更新状态
*/
public void update(long pBytesRead, long pContentLength, int pItems){
FileUploadStatus statusBean=fileUploadStatusManager .getUploadStatus(remoteAddr);
statusBean.setUploadTotalSize(pContentLength);
statusBean.setReadTotalSize(pBytesRead);
if(statusBean.getStatus()!=null&&statusBean.getStatus().equals(FileUploadStatus.CANCEL))
return;
//读取完成
if (pContentLength == pBytesRead) {
statusBean.setStatus(FileUploadStatus.SUCCESS);
//读取中
} else if(pContentLength >pBytesRead){
statusBean.setStatus(FileUploadStatus.UPLOADING);
}
fileUploadStatusManager.setFileUploadStatus(remoteAddr, statusBean);
}
}
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>上传文件</title>
<script src="js/jquery-1.8.2.js"></script>
<script type="text/javascript" src="js/jquery.form.js"></script>
<style type="text/css">
#totalProgressBarBox {
width: 200px;
height: 5px;
border: 1px inset;
background: #eee;
-webkit-border-radius: 4px;
border-radius: 4px;
}
#totalProgressStatus {
height: 5px;
-webkit-border-radius: 4px;
border-radius: 4px;
background-color: #23C278;
}
</style>
<script>
$(document).ready(function(e) {
var refreshTiming = null; //刷新柄
$("#uploadfileInput").change(
function() {
var options = {
dataType : 'json',
success : function(data) {
if (data.status == null|| data.status == "") {
alert("网络有问题,请检查你的网络再上传...");
} else if (data.status == 'success') {
console.info("上传成功...");
} else if (data.satus == "error") {
alert("服务器出现异常!");
}
}
};
$("#fileUploadForm").ajaxSubmit(options); //源于juery.form
startProgress();//上传文件处理
});
//上传处理
function startProgress() {
$("#progressBar").show("fast");
$("#fileName").html($("#uploadfileInput").val());
$("#progressStatusText").html('0%');
//定时刷新
refreshTiming = setInterval(refreshUploadStatus,
100);
return true;
};
//刷新上传状态
function refreshUploadStatus() {
$.get("UploadFileServlet",
{
"op" : "refresh"
},
function(uploadInfo) {
console.info(uploadInfo.status);
if (uploadInfo.status == null
|| uploadInfo.status == "error") {
alert("服务器出现在异常!");
} else {
var progressPercent = Math.ceil((uploadInfo.readTotalSize)/ uploadInfo.uploadTotalSize* 100);
$("#progressStatusText").html(progressPercent+ '%');
$("#totalProgressStatus").css("width",progressPercent+ '%');
if (uploadInfo.status == null|| uploadInfo.status == ""|| uploadInfo.status == "success") {
clearInterval(refreshTiming);
refreshTiming = null;
//请求更新数据库,并隐藏进度条,显示上传文见
/* $.get("StudentSharedFile_updateDB",
uploadInfo,
function() {
$("#uploading").hide("slow");
window.location.reload();
}); */
}
}
}, 'json');
}
});
</script>
</head>
<body>
<div id="wrapper">
<div >
<form id="fileUploadForm" action="UploadFileServlet?op=upload"
method="post" enctype="multipart/form-data">
<input type="file" id="uploadfileInput" value=""
name="uploadfileInput">
</form>
</div>
<div id="progressBar" style="display: none;" >
<div id="theMeter" style="color: #333; font-size: 12px;">
<div id="fileName">准备上传...</div>
<div id="totalProgressBarBox" style="display: inline-block">
<div id="totalProgressStatus" style="width: 0%;"></div>
</div>
<span id="progressStatusText">0%</span>
</div>
</div>
</div>
</body>
</html>
package com.frozenwind.upload.servlet;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.frozenwind.upload.util.FileUploadListener;
import com.frozenwind.upload.util.FileUploadStatus;
import com.frozenwind.upload.util.FileUploadStatusManager;
/**
* Servlet implementation class UploadFileServlet
*/
@WebServlet("/UploadFileServlet")
public class UploadFileServlet extends HttpServlet {
//private BaseDao baseDao = null;
/*@Override
public void init() throws ServletException {
ServletContext servletContext = this.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
baseDao = (BaseDao) ctx.getBean("baseDao");
super.init();
}*/
private static FileUploadStatusManager fileUploadStatusManger = FileUploadStatusManager
.getInstance();
private static final long serialVersionUID = 1L;
private static String tempFilePath = "/upload/temp"; // 设置临时文件存储位置
private static long fileSizeMax = 1024000000; // 设置单个文件的最大上传值
private static long sizeMax = 1024000000; // 设置整个request的最大值
private static String uploadPath = "/upload";
private HttpServletRequest request = null;
private HttpServletResponse response = null;
private String encode="utf-8";
String remoteAddr = null;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
this.remoteAddr = request.getRemoteAddr();
this.request = request;
this.response = response;
String op = request.getParameter("op");
if (op == null & op.equals("")) {
return;
}
if (op.equals("upload")) {
this.processFileUpload();
} else if (op.equals("refresh")) {
this.responseStatusQuery();
} else if (op.equals("cancel")) {
this.processCancelFileUpload();
} else
System.out.println("No Action");
}
/**
* 上传文件处理
*
* @return
* @throws IOException
*/
public String processFileUpload() {
// 是否文件上传
boolean isMultipart = ServletFileUpload
.isMultipartContent(request);
if (!isMultipart) {
return null;
}
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存缓冲区,超过后写入临时文件
factory.setSizeThreshold(4960); // 40KB
// factory.setSizeThreshold(10240000);
// 设置临时文件存储位置
File tempfile = new File(getServletContext().getRealPath(
tempFilePath));
if (!tempfile.isDirectory())
tempfile.mkdir();
factory.setRepository(tempfile);
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置单个文件的最大上传值
upload.setFileSizeMax(fileSizeMax);
// 设置整个request的最大值
upload.setSizeMax(sizeMax);
upload.setProgressListener(new FileUploadListener(remoteAddr));
// 保存初始化后的FileUploadStatus Bean
// TODO 有待完善
FileUploadStatus statusBean = fileUploadStatusManger
.createFileUploadStatus(remoteAddr);
try {
List items = upload.parseRequest(request);
// 获得返回url
for (int i = 0; i < items.size(); i++) {
FileItem item = (FileItem) items.get(i);
if (item.isFormField()) {// 如果不是文件上传框,而是普通表单
// TODO 一般参数处理
} else if (item.getName().length() > 0) { // 处理文件上传
String fileName = takeOutFileName(item
.getName());
File uploadedFile = new File(
getServletContext()
.getRealPath(uploadPath)
+ File.separator
+ fileName);
FileUploadStatus satusBean = fileUploadStatusManger
.getUploadStatus(remoteAddr);
satusBean.setFilename(fileName);
fileUploadStatusManger
.setFileUploadStatus(
remoteAddr,
satusBean);
item.write(uploadedFile);
// 更新上传文件列表
}
}
} catch (Exception e) {
try {
deleteUploadedFile();
response.getWriter().print(
"{\"status\":\"error\"}");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// uploadExceptionHandle("保存上传文件时发生错误:" +
// e.getMessage());
e.printStackTrace();
}
try {
response.getWriter().print("{\"status\":\"success\"}");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 回应上传状态查询
*
* @return
*/
public String responseStatusQuery() {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.setCharacterEncoding(encode);
FileUploadStatus satusBean = fileUploadStatusManger
.getUploadStatus(remoteAddr);
if (satusBean == null)
return null;
try {
//响应客户端
response.getWriter().write(satusBean.toJSon());
if (satusBean.getStatus().equals(
FileUploadStatus.SUCCESS)) {
fileUploadStatusManger.removeFileUploadStatus(remoteAddr);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
void updateIntoDB(){
}
/**
* 处理取消文件上传
*
* @return
*/
@Deprecated
public String processCancelFileUpload() {
FileUploadStatus satusBean = fileUploadStatusManger
.getUploadStatus(request.getRemoteAddr());
satusBean.setStatus(FileUploadStatus.CANCEL);
fileUploadStatusManger.getUploadStatus(request.getRemoteAddr());
try {
response.getWriter().write(satusBean.toJSon());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private void deleteUploadedFile() {
FileUploadStatus satusBean = fileUploadStatusManger
.getUploadStatus(remoteAddr);
String fileName = satusBean.getFilename();
if (fileName != null) {
File uploadedFile = new File(getServletContext()
.getRealPath(uploadPath)
+ File.separator
+ satusBean.getFilename());
uploadedFile.delete();
}
fileUploadStatusManger.removeFileUploadStatus(remoteAddr);
}
/**
* 从文件路径中取出文件名
*/
private String takeOutFileName(String filePath) {
int pos = filePath.lastIndexOf(File.separator);
if (pos > 0) {
return filePath.substring(pos + 1);
} else {
return filePath;
}
}
}
完整上传文件项目请查看下载:
http://download.youkuaiyun.com/detail/brozenwind/5903663