Struts2和common的fileupload实现文件上传并显示实时进度
参考连接http://blog.csdn.net/z69183787/article/details/52536255
基于AJAX的文件上传显示进度条实现参考连接
form表单设置为enctype=”multipart/form-data”,提交表单时:
后端获取参数就不能通过request.getParameter(“name”)来获取,而是通过 以下几种方式:
(1)request.getInputStream()来获取参数,但是这种方式如果有多个文件不太好处理;
(2)可以通过struts2框架的自动封装参数来获取,或者通过fileupload来获取;
1.前端页面代码:页面表单提交不跳转页面是通过隐藏iframe实现的
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>基于Ajax的上传文件显示进度条</title>
<style>
.prog-border {
height: 15px;
width: 205px;
background: #fff;
border: 1px solid #000;
margin: 0;
padding: 0;
}
.prog-bar {
height: 11px;
margin: 2px;
padding: 0px;
background: #178399;
font-size: 10pt;
}
body{
font-family: Arial, Helvetica, sans-serif;
font-size: 10pt;
}
</style>
<script type="text/javascript">
//创建跨浏览器的XMLHttpRequest对象
var timer;
function startListener(){
var xmlhttp;
try{
//IE 5.0
xmlhttp = new ActiveXObject('Msxm12.XMLHTTP');
}catch(e){
try{
//IE 5.5 及更高版本
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}catch(e){
try{
//其他浏览器
xmlhttp = new XMLHttpRequest();
}catch(e){}
}
}
var progressStatusText = document.getElementById("progressBar");
//获取上传的状态
xmlhttp.open("get","<%=basePath%>upload/getUploadStatus.action",true);
//此处Header设置非常重要,必须设置Content-type类型,负责会报错误
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4){
if(xmlhttp.status == 200){
progressStatusText.innerHTML = "";
progressStatusText.innerHTML = xmlhttp.responseText;
var temp = xmlhttp.responseText.indexOf("success");
if ( temp > 0 ){
window.clearTimeout(timer);
}else{
timer = window.setTimeout(startListener,1000);
}
}
}
}
xmlhttp.send(null);
}
function startUpload(){
timer = window.setTimeout(startListener,1000);
return true;
}
function cancelUpload(){
var xmlhttp;
try{
//IE 5.0
xmlhttp = new ActiveXObject('Msxm12.XMLHTTP');
}catch(e){
try{
//IE 5.5 及更高版本
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}catch(e){
try{
//其他浏览器
xmlhttp = new XMLHttpRequest();
}catch(e){}
}
}
var progressStatusText = document.getElementById("progressBar");
xmlhttp.open("get","<%=basePath%>upload/cancelFileUpload.action",true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//xmlhttp.setRequestHeader("Content-type", "multipart/form-data");
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4){
if(xmlhttp.status == 200){
progressStatusText.innerHTML = "";
progressStatusText.innerHTML = xmlhttp.responseText;
}
}
}
xmlhttp.send(null);
return false;
}
</script>
</head>
<body>
<div id="controlPanel">
<!-- 这个是隐藏的<iframe>作为表单提交后处理的后台目标
通过表单form的target属性指定该<iframe>将返回信息显示在<iframe>框架中
-->
<!-- -->
<iframe id='target_upload' name='target_upload' src='' style='display: none'></iframe>
<form id="fileUploadForm" name="fileUploadForm" action="<%=basePath%>upload/uploadFile.action"
enctype="multipart/form-data" method="post" onsubmit="return startUpload();" target="target_upload">
名字:<input type="text" name="name"/><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="取消上传" onclick="return cancelUpload();"/><br>
</form>
<div id="progressBar">
</div>
</div>
</body>
</html>
2.如果使用strut2框架和fileupload整合,必须配置request解析器,因为fileupload无法解析struts2封装过的request;
<!--使用没有被struts2封装过的request,可以在struts.xml中指定文件上传使用的request解析器 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="myRequestParser" class="com.ming.upload.RequestParseWrapper" scope="default" optional="true" />
<constant name="struts.multipart.handler" value="myRequestParser" />
package com.ming.upload;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;
public class RequestParseWrapper extends JakartaMultiPartRequest{
//这里对parse方法进行了覆盖,使其无法封装request
public void parse(HttpServletRequest servletRequest, String saveDir)throws IOException {
}
}
3.编写一个上传状态类,将其放入session中,这样前后端可以获取上传状态;
package com.ming.upload;
import java.util.*;
public class FileUploadStatus {
//上传总量
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 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 void setUploadTotalSize(long uploadTotalSize) {
this.uploadTotalSize = uploadTotalSize;
}
}
4.fileupload工具类ServletFileUpload可以设置一个监听器:
自定义监听器: 实现ProgressListener接口,并重写update方法
package com.ming.upload;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.ProgressListener;
public class UploadListener implements ProgressListener {
private HttpSession session=null;
public UploadListener (HttpSession session){
this.session=session;
}
/**
* 更新状态
* @param pBytesRead 读取字节总数
* @param pContentLength 数据总长度
* @param pItems 当前正在被读取的field号
*/
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
FileUploadStatus fuploadStatus = UploadStatusUtil.takeOutFileUploadStatusBean(this.session);
fuploadStatus.setUploadTotalSize(pContentLength);
//读取完成
if (pContentLength == -1) {
fuploadStatus.setStatus("完成对" + pItems + "个文件的读取:读取了 " + pBytesRead + "/" + pContentLength+ " bytes.");
fuploadStatus.setReadTotalSize(pBytesRead);
fuploadStatus.setCurrentUploadFileNum(pItems);
fuploadStatus.setProcessEndTime(System.currentTimeMillis());
fuploadStatus.setProcessRunningTime(fuploadStatus.getProcessEndTime());
}else{//读取过程中
fuploadStatus.setStatus("当前正在处理第" + pItems+"个文件:已经读取了 " + pBytesRead + " / " + pContentLength+ " bytes.");
fuploadStatus.setReadTotalSize(pBytesRead);
fuploadStatus.setCurrentUploadFileNum(pItems);
fuploadStatus.setProcessRunningTime(System.currentTimeMillis());
}
//System.out.println("已经读取:" + pBytesRead);
UploadStatusUtil.storeFileUploadStatusBean(this.session, fuploadStatus);
}
}
UploadStatusUtil工具类:
package com.ming.upload;
import javax.servlet.http.HttpSession;
public class UploadStatusUtil {
public static final String UPLOAD_STATUS="UPLOAD_STATUS";
public static final String UPLOAD_DIR="/upload";
/**
* 把FileUploadStatus Bean保存到session
* @param request
* @param uploadStatusBean
*/
public static void storeFileUploadStatusBean(
HttpSession session,
FileUploadStatus uploadStatusBean){
session.setAttribute(UPLOAD_STATUS,uploadStatusBean);
}
/**
* 从request中取出FileUploadStatus Bean
* @param request
* @return
*/
public static FileUploadStatus takeOutFileUploadStatusBean(HttpSession session){
Object obj=session.getAttribute(UploadStatusUtil.UPLOAD_STATUS);
if (obj!=null){
return (FileUploadStatus)obj;
}
else{
return null;
}
}
}
5.编写action类:
package com.ming.upload;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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.ServletFileUpload;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import com.opensymphony.xwork2.ActionSupport;
public class UploadStatusAction extends ActionSupport implements ServletRequestAware, ServletResponseAware{
static final long serialVersionUID = 1L;
private HttpServletRequest request;
private HttpServletResponse response;
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
@Override
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
/**
*
* @Title: uploadFile
* @Description: TODO(上传文件)
* @return void 返回类型
* @throws ServletException
* @throws IOException
*/
public void uploadFile(){
try {
//判断文件类型
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
//上传文件并记录上传状态到session,并响应信息
DiskFileItemFactory factory = new DiskFileItemFactory();
//设置内存阀值,超过后写入临时文件
//factory.setSizeThreshold(10240000*5);
//设置临时文件存储位置
//factory.setRepository(new File(request.getRealPath("/upload/temp")));
ServletFileUpload upload = new ServletFileUpload(factory);
//设置单个文件的最大上传size
//upload.setFileSizeMax(10240000*5);
//设置整个request的最大size
//upload.setSizeMax(10240000*5);
//注册监听类
upload.setProgressListener(new UploadListener(request.getSession()));
//保存初始化后的FileUploadStatus Bean
UploadStatusUtil.storeFileUploadStatusBean(request.getSession(),initFileUploadStatusBean(request));
try {
//注意必须重写strut2的request解析方法,struts2封装的request,fileupload无法正确解析
List<FileItem> items = upload.parseRequest(request);
//处理文件上传
for(int i=0;i<items.size();i++){
FileItem item = items.get(i);
//取消上传
if (UploadStatusUtil.takeOutFileUploadStatusBean(request.getSession()).getCancel()){
deleteUploadedFile(request);
break;
}
//保存文件
else if (!item.isFormField() && item.getName().length()>0){
String fileName=takeOutFileName(item.getName());
String path = ServletActionContext.getServletContext().getRealPath(
UploadStatusUtil.UPLOAD_DIR);
File uploadedFile = new File(path + File.separator + fileName);
item.write(uploadedFile);
//更新上传文件列表
FileUploadStatus fUploadStatus = UploadStatusUtil.takeOutFileUploadStatusBean(request.getSession());
if(fUploadStatus != null) {
fUploadStatus.getUploadFileUrlList().add(fileName);
UploadStatusUtil.storeFileUploadStatusBean(request.getSession(), fUploadStatus);
}
Thread.sleep(500);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
uploadExceptionHandle(request,"上传文件时发生错误:"+e.getMessage());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
uploadExceptionHandle(request,"保存上传文件时发生错误:"+e.getMessage());
}
}
} catch (ServletException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//清除session中的上传状态对象
request.getSession().removeAttribute(UploadStatusUtil.UPLOAD_STATUS);
}
}
/**
*
* @Title: getUploadStatus
* @Description: TODO(获取上传状态信息)
* @return void 返回类型
*/
public void getUploadStatus(){
try {
request.setCharacterEncoding("UTF-8");
FileUploadStatus fUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UploadStatusUtil.UPLOAD_STATUS);
//计算上传完成的百分比
long percentComplete = (long)Math.floor(((double) fUploadStatus.getReadTotalSize()/(double) fUploadStatus.getUploadTotalSize())*100.0);
System.out.println("com:"+percentComplete);
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.setHeader("Cache-Control", "no-cache");
if ( ((long)fUploadStatus.getReadTotalSize() == (long)fUploadStatus.getUploadTotalSize()) || (fUploadStatus.getCancel() == true)){
response.getWriter().write(fUploadStatus.getStatus().toString()+"success");
}else{
response.getWriter().write(fUploadStatus.getStatus().toString()+"<div class=\"prog-border\"><div class=\"prog-bar\" style=\"width: "
+ percentComplete + "%;\"></div></div>");
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
*
* @Title: cancelFileUpload
* @Description: TODO(取消上传)
* @return void 返回类型
* @return
*/
public void cancelFileUpload(){
try {
request.setCharacterEncoding("UTF-8");
FileUploadStatus fUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UploadStatusUtil.UPLOAD_STATUS);
fUploadStatus.setCancel(true);
request.getSession().setAttribute(UploadStatusUtil.UPLOAD_STATUS, fUploadStatus);
//调用获取状态方法
getUploadStatus();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} finally {
//清除session中的上传状态对象
request.getSession().removeAttribute(UploadStatusUtil.UPLOAD_STATUS);
}
}
/**
* 从文件路径中取出文件名
* @param filePath
* @return
*/
private String takeOutFileName(String filePath){
int pos=filePath.lastIndexOf(File.separator);
if (pos>0){
return filePath.substring(pos+1);
}
else{
return filePath;
}
}
/**
* 删除已经上传的文件
* @param request
*/
private void deleteUploadedFile(HttpServletRequest request){
FileUploadStatus fUploadStatus= UploadStatusUtil.takeOutFileUploadStatusBean(request.getSession());
for(int i=0;i<fUploadStatus.getUploadFileUrlList().size();i++){
String path = ServletActionContext.getServletContext().getRealPath(
UploadStatusUtil.UPLOAD_DIR);
File uploadedFile = new File(path+
File.separator+fUploadStatus.getUploadFileUrlList().get(i));
uploadedFile.delete();
}
fUploadStatus.getUploadFileUrlList().clear();
fUploadStatus.setStatus("删除已上传的文件");
UploadStatusUtil.storeFileUploadStatusBean(request.getSession(),fUploadStatus);
}
/**
* 上传过程中出错处理
* @param request
* @param errMsg
* @throws IOException
* @throws ServletException
*/
private void uploadExceptionHandle(
HttpServletRequest request,
String errMsg) throws ServletException, IOException{
//首先删除已经上传的文件
deleteUploadedFile(request);
FileUploadStatus fUploadStatus=UploadStatusUtil.takeOutFileUploadStatusBean(request.getSession());
fUploadStatus.setStatus(errMsg);
UploadStatusUtil.storeFileUploadStatusBean(request.getSession(),fUploadStatus);
}
/**
* 初始化文件上传状态Bean
* @param request
* @return
*/
private FileUploadStatus initFileUploadStatusBean(HttpServletRequest request){
FileUploadStatus fUploadStatus=new FileUploadStatus();
fUploadStatus.setStatus("正在准备处理");
fUploadStatus.setUploadTotalSize(request.getContentLength());
fUploadStatus.setProcessStartTime(System.currentTimeMillis());
fUploadStatus.setBaseDir(request.getContextPath()+UploadStatusUtil.UPLOAD_DIR);
return fUploadStatus;
}
}
5.配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="upload" namespace="/upload" extends="struts-default">
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult"/>
</result-types>
<action name="upload" class="com.ming.upload.UploadAction">
</action>
<action name="ajaxUpload" method="ajaxUpload" class="com.ming.upload.AjaxUploadAction">
</action>
<action name="uploadFile" method="uploadFile" class="com.ming.upload.UploadStatusAction">
</action>
<action name="getUploadStatus" method="getUploadStatus" class="com.ming.upload.UploadStatusAction">
</action>
<action name="cancelFileUpload" method="cancelFileUpload" class="com.ming.upload.UploadStatusAction">
</action>
</package>
</struts>