- 浏览: 10765 次
- 性别:
- 来自: 北京
最新评论
先看效果:
在struts2中上传是很简单的,struts2会先把文件写到临时文件中,以后在提供这个文件的File对象到action中。具体原理看这里:
http://blog.csdn.net/tom_221x/archive/2009/01/12/3761390.aspx。
利用servlet和common-upload.jar很容易实现显示文件上传的进度,在common-upload组件中实现一个ProgressListener接口,组件会把上传的实时进度传给你。但是想在struts2中,实时的显示进度是有些困难的。因为struts2把request对象给封装了,在Action中拿到request对象,如果是上传文件,那么struts2已经把文件写到文件系统里去了。
struts2上传文件的时候封装request对象其实是org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper,也就是说在action中拿到的实际类型是MultiPartRequestWrapper。片段如下:
[java] view plaincopyprint?public class MultiPartRequestWrapper extends StrutsRequestWrapper {
protected static final Logger LOG = LoggerFactory.getLogger(MultiPartRequestWrapper.class);
Collection<String> errors;
MultiPartRequest multi;
/**
* Process file downloads and log any errors.
*
* @param request Our HttpServletRequest object
* @param saveDir Target directory for any files that we save
* @param multiPartRequest Our MultiPartRequest object
*/
public MultiPartRequestWrapper(MultiPartRequest multiPartRequest, HttpServletRequest request, String saveDir) {
super(request);
multi = multiPartRequest;
try {
multi.parse(request, saveDir);
for (Object o : multi.getErrors()) {
String error = (String) o;
addError(error);
}
} catch (IOException e) {
addError("Cannot parse request: "+e.toString());
}
}
public class MultiPartRequestWrapper extends StrutsRequestWrapper {
protected static final Logger LOG = LoggerFactory.getLogger(MultiPartRequestWrapper.class);
Collection<String> errors;
MultiPartRequest multi;
/**
* Process file downloads and log any errors.
*
* @param request Our HttpServletRequest object
* @param saveDir Target directory for any files that we save
* @param multiPartRequest Our MultiPartRequest object
*/
public MultiPartRequestWrapper(MultiPartRequest multiPartRequest, HttpServletRequest request, String saveDir) {
super(request);
multi = multiPartRequest;
try {
multi.parse(request, saveDir);
for (Object o : multi.getErrors()) {
String error = (String) o;
addError(error);
}
} catch (IOException e) {
addError("Cannot parse request: "+e.toString());
}
}
可以看到在构造的时候,调用multi.parse(request, saveDir)把上传的数据给封装了。这个MultiPartRequest的解析功能是在struts-default.xml中配置的,如下:
[xhtml] view plaincopyprint?<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="struts" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default"/>
!-- 文件解析器类 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default" />
!-- 这就是struts2的文件解析器设置 -->
<constant name="struts.multipart.handler" value="jakarta" />
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="struts" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default"/>
<!-- 文件解析器类 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default" />
<!-- 这就是struts2的文件解析器设置 -->
<constant name="struts.multipart.handler" value="jakarta" />
现在的设想是,strut2不要帮我解析上传的文件,留到action中,我自己设置。所以我们要覆盖这是配置,如下:
[xhtml] view plaincopyprint?<!-- 重写文件上传解析方法 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="myRequestParser"
class="com.*.*.utils.MyRequestParseWrapper" scope="default" optional="true" />
;constant name="struts.multipart.handler" value="myRequestParser" />
<!-- 重写文件上传解析方法 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="myRequestParser"
class="com.*.*.utils.MyRequestParseWrapper" scope="default" optional="true" />
<constant name="struts.multipart.handler" value="myRequestParser" />
这个MyRequestParseWrapper如下:
[java] view plaincopyprint?/**
* 重写struts2的request封装类
*
* @author scott.Cgi
*/
public class MyRequestParseWrapper extends JakartaMultiPartRequest {
/*
* (non-Javadoc)
* @see
* org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest#parse
* (javax.servlet.http.HttpServletRequest, java.lang.String)
*/
@Override
public void parse(HttpServletRequest servletRequest, String saveDir)
throws IOException {
//什么也不做
}
}
/**
* 重写struts2的request封装类
*
* @author scott.Cgi
*/
public class MyRequestParseWrapper extends JakartaMultiPartRequest {
/*
* (non-Javadoc)
* @see
* org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest#parse
* (javax.servlet.http.HttpServletRequest, java.lang.String)
*/
@Override
public void parse(HttpServletRequest servletRequest, String saveDir)
throws IOException {
//什么也不做
}
}
这样一来,在action中拿到的request就是带有上传文件的了。
接下来,所以说实现原理,依然使用common-uplaod.jar组件:
1. 页面有2个iframe,一个上传数据,一个显示进度。
2. 当然有2个action,一个上传数据,一个回写进度。
3. 上传的时候首先请求的是更新进度的iframe, 这个iframe执行客户端js发起上传文件请求,第二个iframe开始上传数据。与此同时,第一个iframe开始回写进度。进度对象保存在session中,通过request的hashcode为key。进度从第一个进度iframe,传递到第二个上传iframe中,实现进度信息的通信。
说明一下,2个iframe是因为,request未结束,不可以向客户端写数据,所以文件超大,就会阻塞回写信息。
具体的上传我封装了一下,具体代码如下:
[java] view plaincopyprint?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;
/**
* 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 {
LOG.info("客户端提交类型: " + request.getContentType());
if (request.getContentType() == null) {
throw new IOException(
"the request doesn't contain a multipart/form-data stream");
}
String key = request.getParameter("key");
Progress p = (Progress)request.getSession().getAttribute(key);
// 设置上传文件总大小
p.setLength(request.getContentLength());
LOG.info("上传文件大小为 : " + p.getLength());
// 上传临时路径
String path = request.getSession().getServletContext().getRealPath("/");
LOG.info("上传临时路径 : " + path);
// 设置上传工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(path));
// 阀值,超过这个值才会写到临时目录
factory.setSizeThreshold(1024 * 1024 * 10);
ServletFileUpload upload = new ServletFileUpload(factory);
// 最大上传限制
upload.setSizeMax(1024 * 1024 * 200);
// 设置监听器监听上传进度
upload.setProgressListener(p);
try {
LOG.info("解析上传文件....");
List<FileItem> items = upload.parseRequest(request);
LOG.info("上传数据...");
for (FileItem item : items) {
// 非表单域
if (!item.isFormField()) {
LOG.info("上传路径 : " + path + item.getName());
FileOutputStream fos = new FileOutputStream(path + item.getName());
// 文件全在内存中
if (item.isInMemory()) {
fos.write(item.get());
p.setComplete(true);
} 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("删除临时文件!");
p.setComplete(true);
LOG.info("更新progress对象状态为完成状态!");
}
}
} catch (Exception e) {
LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage());
// 发生错误,进度信息对象设置为完成状态
p.setComplete(true);
request.getSession().removeAttribute(key);
}
}
/**
* 执行客户端脚本
*
* @param response
* http response
* @param script
* javscript string
* @throws IOException
* IOException
*/
public static void execClientScript(HttpServletResponse resposne,
String script) throws IOException {
PrintWriter out = resposne.getWriter();
out.println("<mce:script type='text/javascript'><!--
" + script + "
// --></mce:script>");
// fix ie problem
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.flush();
}
/**
* 上传文件进度信息
*
* @author wanglei
* @version 0.1
*/
public static class Progress implements ProgressListener {
// 文件总长度
private long length = 0;
// 已上传的文件长度
private long currentLength = 0;
// 上传是否完成
private boolean isComplete = false;
/*
* (non-Javadoc)
* @see org.apache.commons.fileupload.ProgressListener#update(long,
* long, int)
*/
@Override
public void update(long bytesRead, long contentLength, int items) {
this.currentLength = bytesRead;
}
/**
* the getter method of length
*
* @return the length
*/
public long getLength() {
return length;
}
/**
* the getter method of currentLength
*
* @return the currentLength
*/
public long getCurrentLength() {
return currentLength;
}
/**
* the getter method of isComplete
*
* @return the isComplete
*/
public boolean isComplete() {
return isComplete;
}
/**
* the setter method of the length
*
* @param length
* the length to set
*/
public void setLength(long length) {
this.length = length;
}
/**
* the setter method of the currentLength
*
* @param currentLength
* the currentLength to set
*/
public void setCurrentLength(long currentLength) {
this.currentLength = currentLength;
}
/**
* the setter method of the isComplete
*
* @param isComplete
* the isComplete to set
*/
public void setComplete(boolean isComplete) {
this.isComplete = isComplete;
}
}
}
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;
/**
* 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 {
LOG.info("客户端提交类型: " + request.getContentType());
if (request.getContentType() == null) {
throw new IOException(
"the request doesn't contain a multipart/form-data stream");
}
String key = request.getParameter("key");
Progress p = (Progress)request.getSession().getAttribute(key);
// 设置上传文件总大小
p.setLength(request.getContentLength());
LOG.info("上传文件大小为 : " + p.getLength());
// 上传临时路径
String path = request.getSession().getServletContext().getRealPath("/");
LOG.info("上传临时路径 : " + path);
// 设置上传工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(path));
// 阀值,超过这个值才会写到临时目录
factory.setSizeThreshold(1024 * 1024 * 10);
ServletFileUpload upload = new ServletFileUpload(factory);
// 最大上传限制
upload.setSizeMax(1024 * 1024 * 200);
// 设置监听器监听上传进度
upload.setProgressListener(p);
try {
LOG.info("解析上传文件....");
List<FileItem> items = upload.parseRequest(request);
LOG.info("上传数据...");
for (FileItem item : items) {
// 非表单域
if (!item.isFormField()) {
LOG.info("上传路径 : " + path + item.getName());
FileOutputStream fos = new FileOutputStream(path + item.getName());
// 文件全在内存中
if (item.isInMemory()) {
fos.write(item.get());
p.setComplete(true);
} 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("删除临时文件!");
p.setComplete(true);
LOG.info("更新progress对象状态为完成状态!");
}
}
} catch (Exception e) {
LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage());
// 发生错误,进度信息对象设置为完成状态
p.setComplete(true);
request.getSession().removeAttribute(key);
}
}
/**
* 执行客户端脚本
*
* @param response
* http response
* @param script
* javscript string
* @throws IOException
* IOException
*/
public static void execClientScript(HttpServletResponse resposne,
String script) throws IOException {
PrintWriter out = resposne.getWriter();
out.println("<mce:script type='text/javascript'><!--
" + script + "
// --></mce:script>");
// fix ie problem
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.flush();
}
/**
* 上传文件进度信息
*
* @author wanglei
* @version 0.1
*/
public static class Progress implements ProgressListener {
// 文件总长度
private long length = 0;
// 已上传的文件长度
private long currentLength = 0;
// 上传是否完成
private boolean isComplete = false;
/*
* (non-Javadoc)
* @see org.apache.commons.fileupload.ProgressListener#update(long,
* long, int)
*/
@Override
public void update(long bytesRead, long contentLength, int items) {
this.currentLength = bytesRead;
}
/**
* the getter method of length
*
* @return the length
*/
public long getLength() {
return length;
}
/**
* the getter method of currentLength
*
* @return the currentLength
*/
public long getCurrentLength() {
return currentLength;
}
/**
* the getter method of isComplete
*
* @return the isComplete
*/
public boolean isComplete() {
return isComplete;
}
/**
* the setter method of the length
*
* @param length
* the length to set
*/
public void setLength(long length) {
this.length = length;
}
/**
* the setter method of the currentLength
*
* @param currentLength
* the currentLength to set
*/
public void setCurrentLength(long currentLength) {
this.currentLength = currentLength;
}
/**
* the setter method of the isComplete
*
* @param isComplete
* the isComplete to set
*/
public void setComplete(boolean isComplete) {
this.isComplete = isComplete;
}
}
}
action代码:
[java] view plaincopyprint?import java.io.IOException;
import com.ufinity.mars.utils.UploadFile;
import com.ufinity.mars.utils.UploadFile.Progress;
import com.ufinity.savor.service.FileService;
/**
* file action
*
* @author scott.Cgi
*/
public class FileAction extends AbstractAction {
/** {field's description} */
private static final long serialVersionUID = 6649027352616232244L;
private FileService fileService;
/**
* 上传文件页面
*
* @return page view
*/
public String preupload() {
return SUCCESS;
}
/**
* 上传文件
*
* @return page view
*/
public String uploadfile() {
try {
UploadFile.upload(this.request, this.response);
} catch (IOException e) {
LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());
}
return null;
}
/**
* 显示上传文件进度进度
*
* @return page view
*/
public String progress() {
String callback1 = this.request.getParameter("callback1");
String callback2 = this.request.getParameter("callback2");
// 缓存progress对象的key值
String key = Integer.toString(request.hashCode());
// 新建当前上传文件的进度信息对象
Progress p = new Progress();
// 缓存progress对象
this.request.getSession().setAttribute(key, p);
response.setContentType("text/html;charset=UTF-8");
response.setHeader("pragma", "no-cache");
response.setHeader("cache-control", "no-cache");
response.setHeader("expires", "0");
try {
UploadFile.execClientScript(response, callback1 + "(" + key + ")");
long temp = 0l;
while (!p.isComplete()) {
if (temp != p.getCurrentLength()) {
temp = p.getCurrentLength();
// 向客户端显示进度
UploadFile.execClientScript(response, callback2 + "("
+ p.getCurrentLength() + "," + p.getLength() + ")");
} else {
//LOG.info("progress的状态 :" + p.isComplete());
//LOG.info("progress上传的数据量 :+ " + p.getCurrentLength());
//上传进度没有变化时候,不向客户端写数据,写数据过于频繁会让chrome没响应
Thread.sleep(300);
}
}
} catch (Exception e) {
LOG.error("调用客户端脚本错误,原因 :" + e.getMessage());
p.setComplete(true);
}
this.request.getSession().removeAttribute(key);
LOG.info("删除progress对象的session key");
return null;
}
/**
* the getter method of fileService
*
* @return the fileService
*/
public FileService getFileService() {
return fileService;
}
/**
* the setter method of the fileService
*
* @param fileService
* the fileService to set
*/
public void setFileService(FileService fileService) {
this.fileService = fileService;
}
}
import java.io.IOException;
import com.ufinity.mars.utils.UploadFile;
import com.ufinity.mars.utils.UploadFile.Progress;
import com.ufinity.savor.service.FileService;
/**
* file action
*
* @author scott.Cgi
*/
public class FileAction extends AbstractAction {
/** {field's description} */
private static final long serialVersionUID = 6649027352616232244L;
private FileService fileService;
/**
* 上传文件页面
*
* @return page view
*/
public String preupload() {
return SUCCESS;
}
/**
* 上传文件
*
* @return page view
*/
public String uploadfile() {
try {
UploadFile.upload(this.request, this.response);
} catch (IOException e) {
LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());
}
return null;
}
/**
* 显示上传文件进度进度
*
* @return page view
*/
public String progress() {
String callback1 = this.request.getParameter("callback1");
String callback2 = this.request.getParameter("callback2");
// 缓存progress对象的key值
String key = Integer.toString(request.hashCode());
// 新建当前上传文件的进度信息对象
Progress p = new Progress();
// 缓存progress对象
this.request.getSession().setAttribute(key, p);
response.setContentType("text/html;charset=UTF-8");
response.setHeader("pragma", "no-cache");
response.setHeader("cache-control", "no-cache");
response.setHeader("expires", "0");
try {
UploadFile.execClientScript(response, callback1 + "(" + key + ")");
long temp = 0l;
while (!p.isComplete()) {
if (temp != p.getCurrentLength()) {
temp = p.getCurrentLength();
// 向客户端显示进度
UploadFile.execClientScript(response, callback2 + "("
+ p.getCurrentLength() + "," + p.getLength() + ")");
} else {
//LOG.info("progress的状态 :" + p.isComplete());
//LOG.info("progress上传的数据量 :+ " + p.getCurrentLength());
//上传进度没有变化时候,不向客户端写数据,写数据过于频繁会让chrome没响应
Thread.sleep(300);
}
}
} catch (Exception e) {
LOG.error("调用客户端脚本错误,原因 :" + e.getMessage());
p.setComplete(true);
}
this.request.getSession().removeAttribute(key);
LOG.info("删除progress对象的session key");
return null;
}
/**
* the getter method of fileService
*
* @return the fileService
*/
public FileService getFileService() {
return fileService;
}
/**
* the setter method of the fileService
*
* @param fileService
* the fileService to set
*/
public void setFileService(FileService fileService) {
this.fileService = fileService;
}
}
页面代码:
[xhtml] view plaincopyprint? <mce:style type="text/css"><!--
iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px;
}
#p_in{
width:0%;
height:100%;
background-color:#6b8e23;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
--></mce:style><style type="text/css" mce_bogus="1"> iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px;
}
#p_in{
width:0%;
height:100%;
background-color:#6b8e23;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
</style>
</head>
<body>
<div class="main">
<div class="top">
<jsp:include page="/top.jsp" />
</div>
<div style="width: 250px; margin: 0 auto;">
<div class="errorbox">
<s:actionerror/>
</div>
<form id="uploadfile_form" name="uploadfile_form" enctype="multipart/form-data"
method="post" target="uploadfile_iframe">
<input type="file" name="file" />
<br><br>
<button onclick="progress()">提交</button>
<div id="p_out"><div id="p_in"></div></div>
<div id="dis"></div>
</form>
<iframe frameborder="0" id="uploadfile_iframe" name="uploadfile_iframe" src="javascript:void(0)" mce_src="javascript:void(0)"></iframe>
<iframe frameborder="0" id="progress_iframe" name="progress_iframe" src="javascript:void(0)" mce_src="javascript:void(0)"></iframe>
</div>
</div>
</body>
<mce:script type="text/javascript"><!--
//上传文件
function uploadFile(key){
document.forms[0].action = 'uploadfile.action?callback=parent.upload&key='+key;
document.forms[0].submit();
document.getElementById('dis').innerHTML = "开始传送数据...";
}
//获取文件上传进度
function progress(){
document.getElementById('progress_iframe').src = 'progress.action?callback1=parent.uploadFile&callback2=parent.upload';
document.getElementById('dis').innerHTML = '初始化数据...';
document.getElementById('p_in').style.width = "0%";
}
//更新进度
function upload(len, total){
document.getElementById('p_in').style.width = (Math.round(len/total*100))+'%';
document.getElementById('dis').innerHTML = len + '/' + total + ' Byte';
if(len === total) {
document.getElementById('dis').innerHTML = "文件上传完成!";
}
}
// --></mce:script>
</html>
<mce:style type="text/css"><!--
iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px;
}
#p_in{
width:0%;
height:100%;
background-color:#6b8e23;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
--></mce:style><style type="text/css" mce_bogus="1"> iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px;
}
#p_in{
width:0%;
height:100%;
background-color:#6b8e23;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
</style>
</head>
<body>
<div class="main">
<div class="top">
<jsp:include page="/top.jsp" />
</div>
<div style="width: 250px; margin: 0 auto;">
<div class="errorbox">
<s:actionerror/>
</div>
<form id="uploadfile_form" name="uploadfile_form" enctype="multipart/form-data"
method="post" target="uploadfile_iframe">
<input type="file" name="file" />
<br><br>
<button onclick="progress()">提交</button>
<div id="p_out"><div id="p_in"></div></div>
<div id="dis"></div>
</form>
<iframe frameborder="0" id="uploadfile_iframe" name="uploadfile_iframe" src="javascript:void(0)" mce_src="javascript:void(0)"></iframe>
<iframe frameborder="0" id="progress_iframe" name="progress_iframe" src="javascript:void(0)" mce_src="javascript:void(0)"></iframe>
</div>
</div>
</body>
<mce:script type="text/javascript"><!--
//上传文件
function uploadFile(key){
document.forms[0].action = 'uploadfile.action?callback=parent.upload&key='+key;
document.forms[0].submit();
document.getElementById('dis').innerHTML = "开始传送数据...";
}
//获取文件上传进度
function progress(){
document.getElementById('progress_iframe').src = 'progress.action?callback1=parent.uploadFile&callback2=parent.upload';
document.getElementById('dis').innerHTML = '初始化数据...';
document.getElementById('p_in').style.width = "0%";
}
//更新进度
function upload(len, total){
document.getElementById('p_in').style.width = (Math.round(len/total*100))+'%';
document.getElementById('dis').innerHTML = len + '/' + total + ' Byte';
if(len === total) {
document.getElementById('dis').innerHTML = "文件上传完成!";
}
}
// --></mce:script>
</html>
注意: common-upload.jar依赖common-io.jar
在struts2中上传是很简单的,struts2会先把文件写到临时文件中,以后在提供这个文件的File对象到action中。具体原理看这里:
http://blog.csdn.net/tom_221x/archive/2009/01/12/3761390.aspx。
利用servlet和common-upload.jar很容易实现显示文件上传的进度,在common-upload组件中实现一个ProgressListener接口,组件会把上传的实时进度传给你。但是想在struts2中,实时的显示进度是有些困难的。因为struts2把request对象给封装了,在Action中拿到request对象,如果是上传文件,那么struts2已经把文件写到文件系统里去了。
struts2上传文件的时候封装request对象其实是org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper,也就是说在action中拿到的实际类型是MultiPartRequestWrapper。片段如下:
[java] view plaincopyprint?public class MultiPartRequestWrapper extends StrutsRequestWrapper {
protected static final Logger LOG = LoggerFactory.getLogger(MultiPartRequestWrapper.class);
Collection<String> errors;
MultiPartRequest multi;
/**
* Process file downloads and log any errors.
*
* @param request Our HttpServletRequest object
* @param saveDir Target directory for any files that we save
* @param multiPartRequest Our MultiPartRequest object
*/
public MultiPartRequestWrapper(MultiPartRequest multiPartRequest, HttpServletRequest request, String saveDir) {
super(request);
multi = multiPartRequest;
try {
multi.parse(request, saveDir);
for (Object o : multi.getErrors()) {
String error = (String) o;
addError(error);
}
} catch (IOException e) {
addError("Cannot parse request: "+e.toString());
}
}
public class MultiPartRequestWrapper extends StrutsRequestWrapper {
protected static final Logger LOG = LoggerFactory.getLogger(MultiPartRequestWrapper.class);
Collection<String> errors;
MultiPartRequest multi;
/**
* Process file downloads and log any errors.
*
* @param request Our HttpServletRequest object
* @param saveDir Target directory for any files that we save
* @param multiPartRequest Our MultiPartRequest object
*/
public MultiPartRequestWrapper(MultiPartRequest multiPartRequest, HttpServletRequest request, String saveDir) {
super(request);
multi = multiPartRequest;
try {
multi.parse(request, saveDir);
for (Object o : multi.getErrors()) {
String error = (String) o;
addError(error);
}
} catch (IOException e) {
addError("Cannot parse request: "+e.toString());
}
}
可以看到在构造的时候,调用multi.parse(request, saveDir)把上传的数据给封装了。这个MultiPartRequest的解析功能是在struts-default.xml中配置的,如下:
[xhtml] view plaincopyprint?<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="struts" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default"/>
!-- 文件解析器类 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default" />
!-- 这就是struts2的文件解析器设置 -->
<constant name="struts.multipart.handler" value="jakarta" />
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="struts" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default"/>
<!-- 文件解析器类 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default" />
<!-- 这就是struts2的文件解析器设置 -->
<constant name="struts.multipart.handler" value="jakarta" />
现在的设想是,strut2不要帮我解析上传的文件,留到action中,我自己设置。所以我们要覆盖这是配置,如下:
[xhtml] view plaincopyprint?<!-- 重写文件上传解析方法 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="myRequestParser"
class="com.*.*.utils.MyRequestParseWrapper" scope="default" optional="true" />
;constant name="struts.multipart.handler" value="myRequestParser" />
<!-- 重写文件上传解析方法 -->
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="myRequestParser"
class="com.*.*.utils.MyRequestParseWrapper" scope="default" optional="true" />
<constant name="struts.multipart.handler" value="myRequestParser" />
这个MyRequestParseWrapper如下:
[java] view plaincopyprint?/**
* 重写struts2的request封装类
*
* @author scott.Cgi
*/
public class MyRequestParseWrapper extends JakartaMultiPartRequest {
/*
* (non-Javadoc)
* @see
* org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest#parse
* (javax.servlet.http.HttpServletRequest, java.lang.String)
*/
@Override
public void parse(HttpServletRequest servletRequest, String saveDir)
throws IOException {
//什么也不做
}
}
/**
* 重写struts2的request封装类
*
* @author scott.Cgi
*/
public class MyRequestParseWrapper extends JakartaMultiPartRequest {
/*
* (non-Javadoc)
* @see
* org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest#parse
* (javax.servlet.http.HttpServletRequest, java.lang.String)
*/
@Override
public void parse(HttpServletRequest servletRequest, String saveDir)
throws IOException {
//什么也不做
}
}
这样一来,在action中拿到的request就是带有上传文件的了。
接下来,所以说实现原理,依然使用common-uplaod.jar组件:
1. 页面有2个iframe,一个上传数据,一个显示进度。
2. 当然有2个action,一个上传数据,一个回写进度。
3. 上传的时候首先请求的是更新进度的iframe, 这个iframe执行客户端js发起上传文件请求,第二个iframe开始上传数据。与此同时,第一个iframe开始回写进度。进度对象保存在session中,通过request的hashcode为key。进度从第一个进度iframe,传递到第二个上传iframe中,实现进度信息的通信。
说明一下,2个iframe是因为,request未结束,不可以向客户端写数据,所以文件超大,就会阻塞回写信息。
具体的上传我封装了一下,具体代码如下:
[java] view plaincopyprint?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;
/**
* 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 {
LOG.info("客户端提交类型: " + request.getContentType());
if (request.getContentType() == null) {
throw new IOException(
"the request doesn't contain a multipart/form-data stream");
}
String key = request.getParameter("key");
Progress p = (Progress)request.getSession().getAttribute(key);
// 设置上传文件总大小
p.setLength(request.getContentLength());
LOG.info("上传文件大小为 : " + p.getLength());
// 上传临时路径
String path = request.getSession().getServletContext().getRealPath("/");
LOG.info("上传临时路径 : " + path);
// 设置上传工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(path));
// 阀值,超过这个值才会写到临时目录
factory.setSizeThreshold(1024 * 1024 * 10);
ServletFileUpload upload = new ServletFileUpload(factory);
// 最大上传限制
upload.setSizeMax(1024 * 1024 * 200);
// 设置监听器监听上传进度
upload.setProgressListener(p);
try {
LOG.info("解析上传文件....");
List<FileItem> items = upload.parseRequest(request);
LOG.info("上传数据...");
for (FileItem item : items) {
// 非表单域
if (!item.isFormField()) {
LOG.info("上传路径 : " + path + item.getName());
FileOutputStream fos = new FileOutputStream(path + item.getName());
// 文件全在内存中
if (item.isInMemory()) {
fos.write(item.get());
p.setComplete(true);
} 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("删除临时文件!");
p.setComplete(true);
LOG.info("更新progress对象状态为完成状态!");
}
}
} catch (Exception e) {
LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage());
// 发生错误,进度信息对象设置为完成状态
p.setComplete(true);
request.getSession().removeAttribute(key);
}
}
/**
* 执行客户端脚本
*
* @param response
* http response
* @param script
* javscript string
* @throws IOException
* IOException
*/
public static void execClientScript(HttpServletResponse resposne,
String script) throws IOException {
PrintWriter out = resposne.getWriter();
out.println("<mce:script type='text/javascript'><!--
" + script + "
// --></mce:script>");
// fix ie problem
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.flush();
}
/**
* 上传文件进度信息
*
* @author wanglei
* @version 0.1
*/
public static class Progress implements ProgressListener {
// 文件总长度
private long length = 0;
// 已上传的文件长度
private long currentLength = 0;
// 上传是否完成
private boolean isComplete = false;
/*
* (non-Javadoc)
* @see org.apache.commons.fileupload.ProgressListener#update(long,
* long, int)
*/
@Override
public void update(long bytesRead, long contentLength, int items) {
this.currentLength = bytesRead;
}
/**
* the getter method of length
*
* @return the length
*/
public long getLength() {
return length;
}
/**
* the getter method of currentLength
*
* @return the currentLength
*/
public long getCurrentLength() {
return currentLength;
}
/**
* the getter method of isComplete
*
* @return the isComplete
*/
public boolean isComplete() {
return isComplete;
}
/**
* the setter method of the length
*
* @param length
* the length to set
*/
public void setLength(long length) {
this.length = length;
}
/**
* the setter method of the currentLength
*
* @param currentLength
* the currentLength to set
*/
public void setCurrentLength(long currentLength) {
this.currentLength = currentLength;
}
/**
* the setter method of the isComplete
*
* @param isComplete
* the isComplete to set
*/
public void setComplete(boolean isComplete) {
this.isComplete = isComplete;
}
}
}
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;
/**
* 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 {
LOG.info("客户端提交类型: " + request.getContentType());
if (request.getContentType() == null) {
throw new IOException(
"the request doesn't contain a multipart/form-data stream");
}
String key = request.getParameter("key");
Progress p = (Progress)request.getSession().getAttribute(key);
// 设置上传文件总大小
p.setLength(request.getContentLength());
LOG.info("上传文件大小为 : " + p.getLength());
// 上传临时路径
String path = request.getSession().getServletContext().getRealPath("/");
LOG.info("上传临时路径 : " + path);
// 设置上传工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(path));
// 阀值,超过这个值才会写到临时目录
factory.setSizeThreshold(1024 * 1024 * 10);
ServletFileUpload upload = new ServletFileUpload(factory);
// 最大上传限制
upload.setSizeMax(1024 * 1024 * 200);
// 设置监听器监听上传进度
upload.setProgressListener(p);
try {
LOG.info("解析上传文件....");
List<FileItem> items = upload.parseRequest(request);
LOG.info("上传数据...");
for (FileItem item : items) {
// 非表单域
if (!item.isFormField()) {
LOG.info("上传路径 : " + path + item.getName());
FileOutputStream fos = new FileOutputStream(path + item.getName());
// 文件全在内存中
if (item.isInMemory()) {
fos.write(item.get());
p.setComplete(true);
} 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("删除临时文件!");
p.setComplete(true);
LOG.info("更新progress对象状态为完成状态!");
}
}
} catch (Exception e) {
LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage());
// 发生错误,进度信息对象设置为完成状态
p.setComplete(true);
request.getSession().removeAttribute(key);
}
}
/**
* 执行客户端脚本
*
* @param response
* http response
* @param script
* javscript string
* @throws IOException
* IOException
*/
public static void execClientScript(HttpServletResponse resposne,
String script) throws IOException {
PrintWriter out = resposne.getWriter();
out.println("<mce:script type='text/javascript'><!--
" + script + "
// --></mce:script>");
// fix ie problem
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.println("---------------------------------------------------");
out.flush();
}
/**
* 上传文件进度信息
*
* @author wanglei
* @version 0.1
*/
public static class Progress implements ProgressListener {
// 文件总长度
private long length = 0;
// 已上传的文件长度
private long currentLength = 0;
// 上传是否完成
private boolean isComplete = false;
/*
* (non-Javadoc)
* @see org.apache.commons.fileupload.ProgressListener#update(long,
* long, int)
*/
@Override
public void update(long bytesRead, long contentLength, int items) {
this.currentLength = bytesRead;
}
/**
* the getter method of length
*
* @return the length
*/
public long getLength() {
return length;
}
/**
* the getter method of currentLength
*
* @return the currentLength
*/
public long getCurrentLength() {
return currentLength;
}
/**
* the getter method of isComplete
*
* @return the isComplete
*/
public boolean isComplete() {
return isComplete;
}
/**
* the setter method of the length
*
* @param length
* the length to set
*/
public void setLength(long length) {
this.length = length;
}
/**
* the setter method of the currentLength
*
* @param currentLength
* the currentLength to set
*/
public void setCurrentLength(long currentLength) {
this.currentLength = currentLength;
}
/**
* the setter method of the isComplete
*
* @param isComplete
* the isComplete to set
*/
public void setComplete(boolean isComplete) {
this.isComplete = isComplete;
}
}
}
action代码:
[java] view plaincopyprint?import java.io.IOException;
import com.ufinity.mars.utils.UploadFile;
import com.ufinity.mars.utils.UploadFile.Progress;
import com.ufinity.savor.service.FileService;
/**
* file action
*
* @author scott.Cgi
*/
public class FileAction extends AbstractAction {
/** {field's description} */
private static final long serialVersionUID = 6649027352616232244L;
private FileService fileService;
/**
* 上传文件页面
*
* @return page view
*/
public String preupload() {
return SUCCESS;
}
/**
* 上传文件
*
* @return page view
*/
public String uploadfile() {
try {
UploadFile.upload(this.request, this.response);
} catch (IOException e) {
LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());
}
return null;
}
/**
* 显示上传文件进度进度
*
* @return page view
*/
public String progress() {
String callback1 = this.request.getParameter("callback1");
String callback2 = this.request.getParameter("callback2");
// 缓存progress对象的key值
String key = Integer.toString(request.hashCode());
// 新建当前上传文件的进度信息对象
Progress p = new Progress();
// 缓存progress对象
this.request.getSession().setAttribute(key, p);
response.setContentType("text/html;charset=UTF-8");
response.setHeader("pragma", "no-cache");
response.setHeader("cache-control", "no-cache");
response.setHeader("expires", "0");
try {
UploadFile.execClientScript(response, callback1 + "(" + key + ")");
long temp = 0l;
while (!p.isComplete()) {
if (temp != p.getCurrentLength()) {
temp = p.getCurrentLength();
// 向客户端显示进度
UploadFile.execClientScript(response, callback2 + "("
+ p.getCurrentLength() + "," + p.getLength() + ")");
} else {
//LOG.info("progress的状态 :" + p.isComplete());
//LOG.info("progress上传的数据量 :+ " + p.getCurrentLength());
//上传进度没有变化时候,不向客户端写数据,写数据过于频繁会让chrome没响应
Thread.sleep(300);
}
}
} catch (Exception e) {
LOG.error("调用客户端脚本错误,原因 :" + e.getMessage());
p.setComplete(true);
}
this.request.getSession().removeAttribute(key);
LOG.info("删除progress对象的session key");
return null;
}
/**
* the getter method of fileService
*
* @return the fileService
*/
public FileService getFileService() {
return fileService;
}
/**
* the setter method of the fileService
*
* @param fileService
* the fileService to set
*/
public void setFileService(FileService fileService) {
this.fileService = fileService;
}
}
import java.io.IOException;
import com.ufinity.mars.utils.UploadFile;
import com.ufinity.mars.utils.UploadFile.Progress;
import com.ufinity.savor.service.FileService;
/**
* file action
*
* @author scott.Cgi
*/
public class FileAction extends AbstractAction {
/** {field's description} */
private static final long serialVersionUID = 6649027352616232244L;
private FileService fileService;
/**
* 上传文件页面
*
* @return page view
*/
public String preupload() {
return SUCCESS;
}
/**
* 上传文件
*
* @return page view
*/
public String uploadfile() {
try {
UploadFile.upload(this.request, this.response);
} catch (IOException e) {
LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());
}
return null;
}
/**
* 显示上传文件进度进度
*
* @return page view
*/
public String progress() {
String callback1 = this.request.getParameter("callback1");
String callback2 = this.request.getParameter("callback2");
// 缓存progress对象的key值
String key = Integer.toString(request.hashCode());
// 新建当前上传文件的进度信息对象
Progress p = new Progress();
// 缓存progress对象
this.request.getSession().setAttribute(key, p);
response.setContentType("text/html;charset=UTF-8");
response.setHeader("pragma", "no-cache");
response.setHeader("cache-control", "no-cache");
response.setHeader("expires", "0");
try {
UploadFile.execClientScript(response, callback1 + "(" + key + ")");
long temp = 0l;
while (!p.isComplete()) {
if (temp != p.getCurrentLength()) {
temp = p.getCurrentLength();
// 向客户端显示进度
UploadFile.execClientScript(response, callback2 + "("
+ p.getCurrentLength() + "," + p.getLength() + ")");
} else {
//LOG.info("progress的状态 :" + p.isComplete());
//LOG.info("progress上传的数据量 :+ " + p.getCurrentLength());
//上传进度没有变化时候,不向客户端写数据,写数据过于频繁会让chrome没响应
Thread.sleep(300);
}
}
} catch (Exception e) {
LOG.error("调用客户端脚本错误,原因 :" + e.getMessage());
p.setComplete(true);
}
this.request.getSession().removeAttribute(key);
LOG.info("删除progress对象的session key");
return null;
}
/**
* the getter method of fileService
*
* @return the fileService
*/
public FileService getFileService() {
return fileService;
}
/**
* the setter method of the fileService
*
* @param fileService
* the fileService to set
*/
public void setFileService(FileService fileService) {
this.fileService = fileService;
}
}
页面代码:
[xhtml] view plaincopyprint? <mce:style type="text/css"><!--
iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px;
}
#p_in{
width:0%;
height:100%;
background-color:#6b8e23;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
--></mce:style><style type="text/css" mce_bogus="1"> iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px;
}
#p_in{
width:0%;
height:100%;
background-color:#6b8e23;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
</style>
</head>
<body>
<div class="main">
<div class="top">
<jsp:include page="/top.jsp" />
</div>
<div style="width: 250px; margin: 0 auto;">
<div class="errorbox">
<s:actionerror/>
</div>
<form id="uploadfile_form" name="uploadfile_form" enctype="multipart/form-data"
method="post" target="uploadfile_iframe">
<input type="file" name="file" />
<br><br>
<button onclick="progress()">提交</button>
<div id="p_out"><div id="p_in"></div></div>
<div id="dis"></div>
</form>
<iframe frameborder="0" id="uploadfile_iframe" name="uploadfile_iframe" src="javascript:void(0)" mce_src="javascript:void(0)"></iframe>
<iframe frameborder="0" id="progress_iframe" name="progress_iframe" src="javascript:void(0)" mce_src="javascript:void(0)"></iframe>
</div>
</div>
</body>
<mce:script type="text/javascript"><!--
//上传文件
function uploadFile(key){
document.forms[0].action = 'uploadfile.action?callback=parent.upload&key='+key;
document.forms[0].submit();
document.getElementById('dis').innerHTML = "开始传送数据...";
}
//获取文件上传进度
function progress(){
document.getElementById('progress_iframe').src = 'progress.action?callback1=parent.uploadFile&callback2=parent.upload';
document.getElementById('dis').innerHTML = '初始化数据...';
document.getElementById('p_in').style.width = "0%";
}
//更新进度
function upload(len, total){
document.getElementById('p_in').style.width = (Math.round(len/total*100))+'%';
document.getElementById('dis').innerHTML = len + '/' + total + ' Byte';
if(len === total) {
document.getElementById('dis').innerHTML = "文件上传完成!";
}
}
// --></mce:script>
</html>
<mce:style type="text/css"><!--
iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px;
}
#p_in{
width:0%;
height:100%;
background-color:#6b8e23;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
--></mce:style><style type="text/css" mce_bogus="1"> iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px;
}
#p_in{
width:0%;
height:100%;
background-color:#6b8e23;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
</style>
</head>
<body>
<div class="main">
<div class="top">
<jsp:include page="/top.jsp" />
</div>
<div style="width: 250px; margin: 0 auto;">
<div class="errorbox">
<s:actionerror/>
</div>
<form id="uploadfile_form" name="uploadfile_form" enctype="multipart/form-data"
method="post" target="uploadfile_iframe">
<input type="file" name="file" />
<br><br>
<button onclick="progress()">提交</button>
<div id="p_out"><div id="p_in"></div></div>
<div id="dis"></div>
</form>
<iframe frameborder="0" id="uploadfile_iframe" name="uploadfile_iframe" src="javascript:void(0)" mce_src="javascript:void(0)"></iframe>
<iframe frameborder="0" id="progress_iframe" name="progress_iframe" src="javascript:void(0)" mce_src="javascript:void(0)"></iframe>
</div>
</div>
</body>
<mce:script type="text/javascript"><!--
//上传文件
function uploadFile(key){
document.forms[0].action = 'uploadfile.action?callback=parent.upload&key='+key;
document.forms[0].submit();
document.getElementById('dis').innerHTML = "开始传送数据...";
}
//获取文件上传进度
function progress(){
document.getElementById('progress_iframe').src = 'progress.action?callback1=parent.uploadFile&callback2=parent.upload';
document.getElementById('dis').innerHTML = '初始化数据...';
document.getElementById('p_in').style.width = "0%";
}
//更新进度
function upload(len, total){
document.getElementById('p_in').style.width = (Math.round(len/total*100))+'%';
document.getElementById('dis').innerHTML = len + '/' + total + ' Byte';
if(len === total) {
document.getElementById('dis').innerHTML = "文件上传完成!";
}
}
// --></mce:script>
</html>
注意: common-upload.jar依赖common-io.jar
相关推荐
总的来说,Struts2实现文件上传进度条显示需要整合服务器端的进度回调和客户端的进度更新,确保数据的实时同步。同时,为了提高用户体验,应考虑优化大文件上传的性能,如分块上传、断点续传等技术。通过以上步骤,...
2. **后端处理**:在Struts1的Action中,我们需要自定义一个ActionForm,扩展`org.apache.struts.action.ActionForm`,并重写`execute()`方法来处理文件上传。在这个方法里,可以使用`FormFile`对象获取文件,并将其...
总的来说,"struts2+ajax文件进度条的实现"是一个典型的前后端协同工作的示例,它展示了如何在Java web应用中优化用户体验,特别是在处理大文件上传时。通过理解Ajax的工作原理、Struts2的文件上传机制以及前端组件...
在Java Struts2框架中实现文件上传进度条显示,主要涉及到的技术点包括Struts2的文件上传、Ajax异步通信以及前端进度条组件的使用。下面将详细讲解这些知识点。 首先,Struts2的文件上传功能是通过Struts2提供的`...
Struts2 Uploadify是一个在Java Web开发中常用的插件,它结合了Struts2框架和Uploadify jQuery插件,能够实现文件的多选、上传进度显示以及后台处理等功能。这个项目示例提供了一个完整的解决方案,使得用户在上传多...
"Struts2文件上传带进度条页面无刷新"的实现涉及多个技术点,包括Struts2的文件上传插件、AJAX异步通信以及前端进度条展示。 首先,Struts2的文件上传依赖于`struts2-upload-plugin`。这个插件扩展了Struts2的核心...
在Struts中,可以实现单文件和多文件的上传,并且为了提升用户体验,我们还可以添加进度条来显示文件上传的状态。本文将详细介绍如何在Struts中实现这两个功能,并带上传进度条。 首先,我们需要了解Struts中处理...
在Struts2中,实现文件上传功能是非常常见的需求,而带进度条的文件上传则可以提供更好的用户体验,让用户了解文件上传的进度,减少用户的等待焦虑感。 Struts2的文件上传主要依赖于Apache的Commons FileUpload库。...
总的来说,Struts2实现文件上传显示进度条效果需要理解文件上传的处理流程,创建一个监听器来捕获上传进度,并通过合适的通信机制将这些信息传递到前端进行显示。这是一个涉及到后端处理、前端交互以及网络通信的...
Struts2文件上传进度条是Web开发中一个实用的功能,它允许用户在文件上传过程中查看当前的上传进度,提供更好的用户体验。在这个项目中,我们利用Struts2框架的拦截器机制来实现这一功能。 首先,我们需要理解...
struts2上传文件的进度条显示,绝对可用! 所达到效果 1.显示总文件大小 2.显示已上传文件大小 3.显示当前进度(百分比控制) 4.显示剩余上传时间 5.显示当前速度 (本人研究了很久才搞出来的,希望大家指教)
### Struts 1.2 下实现文件上传进度条的关键知识点 #### 一、背景与目的 在基于Struts 1.2的Web应用中,实现文件上传时常常需要提供一个友好的用户界面来显示文件上传进度。这不仅提高了用户体验,还能够实时反馈...
2. 带进度条的文件上传:在传统的文件上传过程中,用户通常无法得知文件上传的具体进度,只能等待上传完成。而带进度条的文件上传则解决了这个问题,它通常基于HTML5的File API,可以实时更新文件上传进度。例如,`...
struts2+hibernate+spring,struts2文件上传带进度条,页面美观,功能齐全。下载后把工程导入到myeclipse后即可运行,不需任何配置。由于压缩后文件较大,所以该功能下的lib为空,下载后请自己导入struts2,hibernate...
这是根据uploadify3 2结合struts2搭建的文件上传环境 可以直接导入eclipse运行 每步实现基本都加了注释 以下是我碰到的问题: 1 判断session是否失效 本实例没测试这个问题 但在工作项目中碰到了 但原因在这里...
在Struts2中实现文件上传功能,可以极大地提升用户体验,尤其是当上传大文件时,进度条显示可以让用户知道文件上传的状态,提高交互性。本教程将详细讲解如何在Struts2中集成JQuery File Upload插件,实现文件上传的...
在这个项目中,Struts2提供了一套灵活的动作和拦截器机制,使得文件上传可以通过自定义Action类来实现,同时它支持与Ajax的交互,可以实现无刷新的进度条展示。 2. **Spring**:Spring框架是一个全面的企业级应用...
在Struts2中处理文件上传是一项常见的任务,尤其是当用户需要上传大文件时,提供一个带有进度条的界面可以显著提高用户体验。下面我们将深入探讨如何在Struts2中实现带进度条的文件上传。 1. **Struts2文件上传基础...
在Struts2中,实现文件上传功能是非常常见的需求,而带进度条的文件上传则可以提供更好的用户体验,让用户了解文件上传的进度,增加交互性和可靠性。 文件上传在Web开发中扮演着重要角色,尤其是在处理大文件或者...