需要做一个文件上传进度的效果,结合网上资料和自己的实践后,这里做一个整理
步骤如下:
1.重写、自定义JakartaMultiPartRequest类
package com.hikvision.fileUploadProcess.interceptor;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;
public class MyJakartaMultiPartRequest extends JakartaMultiPartRequest {
@Override
public void parse(HttpServletRequest servletRequest, String saveDir)
throws IOException {
//什么也不做
}
}
原因:
struts2默认的拦截器中有一个FileUploadInterceptor,它会拦截所有的MultipartRequest,并且将得到的File及相关信息传递给action,因此在action被调用之前,文件上传已经被处理完了,不能引入监听文件写入时文件进度;
struts2处理文件上传使用的是commons-fileupload,因此我们可以使用ProgressListener。注意我们需要在解析请求的时候加入我们的监听器,我们首先想到的是替换掉FileUploadInterceptor,不幸的是 FileUploadInterceptor并不执行解析的任务,实际在FileUploadInterceptor被调用之前,MultipartRequest已经被解析了,文件上传的工作已经完成。而实际上对于所有的文件上传请求,struts2会为其生成一个MultiPartRequestWrapper进行包装,而它维护着一个 MultiPartRequest接口的实例。MultiPartRequest的实现类只有一个 JakartaMultiPartRequest,JakartaMultiPartRequest有一个方法parseRequest,此方法负责解析 request并生成FileItem,即对文件进行读写操作,因此我们可以重写此方法,添加ProgressListener。不幸的是,JakartaMultiPartRequest的很多方法都是private的,我们不能继承它然后重写parseRequest方法,JakartaMultiPartRequest实现了MultiPartRequest接口,我们可以编写一个类,实现 MultiPartRequest接口,替代JakartaMultiPartRequest类的代码全都拷贝过来,并修改parseRequest方法,完成文件的写入与进度的监听。
2.配置struts2.xml
3.定义文件上传进度信息的类
package com.hikvision.fileUploadProcess.entity;
/**
* 上传文件进度信息
*
* @author wanglei
* @version 0.1
*/
public class FileUploadProgress {
// 文件总长度(设置至少为1字节防止前台出现/0的情况)
private long length = 1;
// 已上传的文件长度
private long currentLength = 0;
// 上传是否完成
private boolean isComplete = false;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
public long getCurrentLength() {
return currentLength;
}
public void setCurrentLength(long currentLength) {
this.currentLength = currentLength;
}
public boolean isComplete() {
return isComplete;
}
public void setComplete(boolean isComplete) {
this.isComplete = isComplete;
}
public FileUploadProgress() {
super();
}
}
4.实现ProgressListener接口
package com.hikvision.fileUploadProcess.impl;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.ProgressListener;
import com.hikvision.fileUploadProcess.entity.FileUploadProgress;
/**
* 文件上传进度消息
* @author hongchenjin
*
*/
public class FileUploadListener implements ProgressListener {
private HttpSession session;
public FileUploadListener(HttpServletRequest request) {
session = request.getSession();
FileUploadProgress fileUploadProgress = new FileUploadProgress();
fileUploadProgress.setComplete(false);
session.setAttribute("fileUploadProgress", fileUploadProgress);
}
//更新进度情况
@Override
public void update(long readedBytes, long totalBytes, int currentItem) {
//实现文件上传的核心方法
Object attribute = session.getAttribute("fileUploadProgress");
FileUploadProgress fileUploadProgress = null;
if(null == attribute){
fileUploadProgress = new FileUploadProgress();
fileUploadProgress.setComplete(false);
session.setAttribute("fileUploadProgress", fileUploadProgress);
}else{
fileUploadProgress = (FileUploadProgress)attribute;
}
fileUploadProgress.setCurrentLength(readedBytes);
fileUploadProgress.setLength(totalBytes);
if(readedBytes==totalBytes){
fileUploadProgress.setComplete(true);
}else{
fileUploadProgress.setComplete(false);
}
session.setAttribute("progress", fileUploadProgress);
}
}
5.文件上传进度的action
package com.hikvision.modules.guide.action;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.hikvision.fileUploadProcess.entity.FileUploadProgress;
import com.hikvision.frame.entity.OperateResult;
import com.hikvision.modules.guide.entity.NameToLocalFile;
import com.hikvision.modules.guide.service.GuideService;
import com.hikvision.modules.guide.util.GetSharePathXml;
import com.hikvision.util.AjaxUtil;
import com.opensymphony.xwork2.ActionSupport;
public class GuideUploadAction extends ActionSupport {
private GuideService guideService;
public GuideService getGuideService() {
return guideService;
}
public void setGuideService(GuideService guideService) {
this.guideService = guideService;
}
//文件格式不支持
public void typeNotSupport(){
OperateResult result = new OperateResult(false,"");
result.setResult(false);
result.setMsg("上传文件最大不能超过100M;支持的格式为exe,png,jpg,gif,bmp,doc,docx,xls,rar,txt,zip,js,css,msi,pptx");
AjaxUtil.ajaxWrite(result);
}
/**
* 上传文件
*
* @return
*/
public void uploadfile() {
OperateResult result = new OperateResult(false,"");
try {
HttpServletRequest request = ServletActionContext.getRequest();
//获取文件备注
String comments = request.getParameter("comments");
//文件上传
UploadFile.upload(request, ServletActionContext.getResponse());
//将文件名和文件的对应关系存进数据库里
NameToLocalFile nameToLocalFile = new NameToLocalFile();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String time = sdf.format(new Date());
nameToLocalFile.setCreatetime(time);
//保存在服务器上的路径
nameToLocalFile.setLocalpath("/" + request.getParameter("variety") + "/" + request.getParameter("name"));
nameToLocalFile.setName(request.getParameter("name"));
nameToLocalFile.setVariety(request.getParameter("variety"));
nameToLocalFile.setComments(comments);
guideService.saveOrUpdate(nameToLocalFile);
result.setResult(true);
result.setMsg("上传成功");
} catch (IOException e) {
LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());
result.setMsg("上传文件最大不能超过100M;");
result.setResult(false);
}
AjaxUtil.ajaxWrite(result);
}
/**
* 修改文件
*/
public void updateNameToLocalFile(){
OperateResult result = new OperateResult(false,"");
HttpServletRequest request = ServletActionContext.getRequest();
//种类
String variety = request.getParameter("variety");
//名称
String name = request.getParameter("name");
//文件备注
String comments = request.getParameter("comments");
//是否上传了文件
Boolean flag = Boolean.parseBoolean(request.getParameter("flag"));
//id
int id = Integer.parseInt(request.getParameterValues("ids")[0]);
//根据id获取数据库的nameToLocalFileById
NameToLocalFile nameToLocalFileById = guideService.getNameToLocalFileById(id);
//分为两种情况,第一种为用户重新上传了文件,第二种是用户只修改了名字和种类
if(flag){
/**
* 用户重新上传文件的情况
*/
//删除原来文件
String localpath = nameToLocalFileById.getLocalpath();
String realPath = GetSharePathXml.getShareFolderPath() + localpath;
File file = new File(realPath);
//用户上传了文件
try {
if(file.exists()){
//删除原来文件(判断是否存在该文件,存在就删除)
file.delete();
}
//文件上传
UploadFile.upload(request, ServletActionContext.getResponse());
result.setResult(true);
result.setMsg("修改成功");
} catch (Exception e) {
result.setResult(false);
result.setMsg("修改失败");
}
}
//将文件名和文件的对应关系存进数据库里
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String time = sdf.format(new Date());
nameToLocalFileById.setCreatetime(time);
if(flag){
//保存在服务器上的路径
nameToLocalFileById.setLocalpath("/" + variety + "/" + name);
nameToLocalFileById.setName(name);
}
nameToLocalFileById.setVariety(variety);
nameToLocalFileById.setComments(comments);
guideService.saveOrUpdate(nameToLocalFileById);
result.setResult(true);
result.setMsg("修改成功");
AjaxUtil.ajaxWrite(result);
}
/**
* 显示上传文件进度进度
*
* @return page view
*/
public void progress() {
// 新建当前上传文件的进度信息对象
FileUploadProgress p = null;
Object attribute = ServletActionContext.getRequest().getSession().getAttribute("fileUploadProgress");
if(null == attribute){
p = new FileUploadProgress();
// 缓存progress对象
ServletActionContext.getRequest().getSession().setAttribute("fileUploadProgress", p);
}else{
p = (FileUploadProgress)attribute;
}
ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");
ServletActionContext.getResponse().setHeader("pragma", "no-cache");
ServletActionContext.getResponse().setHeader("cache-control", "no-cache");
ServletActionContext.getResponse().setHeader("expires", "0");
//以下方法为输出json(封装,可根据实际情况修改输出的方式)
AjaxUtil.ajaxWriteObject(p);
}
/**
* 清除session
*/
public void clearProgressSession(){
ServletActionContext.getRequest().getSession().setAttribute("fileUploadProgress", null);
}
}
package com.hikvision.modules.guide.action;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;
import com.hikvision.fileUploadProcess.impl.FileUploadListener;
import com.hikvision.modules.guide.util.GetSharePathXml;
/**
* upload file
*
* @author scott.Cgi
*/
public class UploadFile {
private static final Logger LOG = Logger.getLogger(UploadFile.class);
/**
* 上传文件
*
* @param request
* http request
* @param response
* htp response
* @throws IOException
* IOException
*/
@SuppressWarnings("unchecked")
public static void upload(HttpServletRequest request,
HttpServletResponse response) throws IOException {
if (request.getContentType() == null) {
throw new IOException(
"the request doesn't contain a multipart/form-data stream");
}
// 上传临时路径
String path = GetSharePathXml.getShareFolderPath();
// 设置上传工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(path));
// 阀值,超过这个值才会写到临时目录
factory.setSizeThreshold(1024 * 1024 * 10);
ServletFileUpload upload = new ServletFileUpload(factory);
// 最大上传限制
upload.setSizeMax(1024 * 1024 * 1000);
// 设置监听器监听上传进度
upload.setProgressListener(new FileUploadListener(request));
try {
List items = upload.parseRequest(request);
//获取文件类型
String variety = request.getParameter("variety");
for (FileItem item : items) {
// 非表单域
if (!item.isFormField()) {
FileOutputStream fos = new FileOutputStream(path + "/" + variety + "/" + item.getName());
// 文件全在内存中
if (item.isInMemory()) {
fos.write(item.get());
} else {
InputStream is = item.getInputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
is.close();
}
fos.close();
LOG.info("完成上传文件!");
item.delete();
LOG.info("删除临时文件!");
LOG.info("更新progress对象状态为完成状态!");
}
}
} catch (Exception e) {
LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage());
request.getSession().removeAttribute("percent");
}
}
}
前台部分:点击上传,然后循环调用
//进度条显示
var everylisten = function() {
//显示进度条
$("#prosbar").parent("div").css({"display":"block"});
$.ajax({
url : 'http://127.0.0.1/guideUpload!progress.action',
method : 'GET',
timeout : 120000,
contentType : "application/json; charset=utf-8",
dataType : "json",
success : function(result) {
if(null != result) {
if(result.complete) {
//将进度条长度设为0并隐藏
$("#prosbar").css({"width":"0%"});
clearTimeout(everylisten);
//清除session
clearProgressSession();
}else{
var width = result.currentLength * 100 / result.length + "%";
$("#prosbar").css({"width": width});
setTimeout(everylisten, 500);
}
}else{
alert(data.msg);
}
}
});
};
清除进度条session
//清除session
function clearProgressSession(){
$.ajax({
url : hik.guide.getContextPath() + '/guideUpload!clearProgressSession.action',
method : 'GET',
timeout : 120000,
contentType : "application/json; charset=utf-8",
dataType : "json",
success : function(result) {
}
});
}
点击文件上传时的js代码(PS:文件上传时相关参数写在路径里,不然后台接收不到(如果不写在路径里,测试时在浏览器调试发现参数确实传了,但在request里这个参数的值为空),因为请求地址是要经过tomcat的,为防止中文乱码的情况,在tomcat路径conf文件夹下找到server.xml文件,找到以下项,添加红色部分的代码
$("#GuideForm").submit(function(){
everylisten();
return false;
$.ajaxFileUpload
(
{
url:'http://127.0.0.1/guideUpload!uploadfile.action?'
+ $("#GuideForm").serialize(),
secureuri:false,
fileElementId:'upload',
dataType: 'json',
data:{},
success: function (data, status)
{
$(dialogEl).dialog('close');
//上传成功后,提示用户上传成功
if(data.success){
alert("success");
}else{
alert("false");
}
},
error: function (data, status, e)
{
alert("出错了");
}
}
)
});