先看效果:
在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。片段如下:
-
public class MultiPartRequestWrapper extends StrutsRequestWrapper {
-
protected static final Logger LOG = LoggerFactory.getLogger(MultiPartRequestWrapper.class);
-
Collection errors;
-
MultiPartRequest multi;
-
-
-
-
-
-
-
-
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 errors;
-
MultiPartRequest multi;
-
-
-
-
-
-
-
-
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中配置的,如下:
-
<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" />
-
-
-
<constant name="struts.multipart.handler" value="jakarta" />
现在的设想是,strut2不要帮我解析上传的文件,留到action中,我自己设置。所以我们要覆盖这是配置,如下:
-
-
<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如下:
-
-
-
-
-
-
public class MyRequestParseWrapper extends JakartaMultiPartRequest {
-
-
-
-
-
-
-
@Override
-
public void parse(HttpServletRequest servletRequest, String saveDir)
-
throws IOException {
-
-
}
-
}
-
-
-
-
-
-
public class MyRequestParseWrapper extends JakartaMultiPartRequest {
-
-
-
-
-
-
-
@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未结束,不可以向客户端写数据,所以文件超大,就会阻塞回写信息。
具体的上传我封装了一下,具体代码如下:
action代码:
-
import java.io.IOException;
-
import com.ufinity.mars.utils.UploadFile;
-
import com.ufinity.mars.utils.UploadFile.Progress;
-
import com.ufinity.savor.service.FileService;
-
-
-
-
-
-
public class FileAction extends AbstractAction {
-
-
private static final long serialVersionUID = 6649027352616232244L;
-
private FileService fileService;
-
-
-
-
-
-
public String preupload() {
-
return SUCCESS;
-
}
-
-
-
-
-
-
public String uploadfile() {
-
try {
-
UploadFile.upload(this.request, this.response);
-
} catch (IOException e) {
-
LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());
-
}
-
return null;
-
}
-
-
-
-
-
-
public String progress() {
-
String callback1 = this.request.getParameter("callback1");
-
String callback2 = this.request.getParameter("callback2");
-
-
String key = Integer.toString(request.hashCode());
-
-
Progress p = new 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 {
-
-
-
-
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;
-
}
-
-
-
-
-
-
public FileService getFileService() {
-
return fileService;
-
}
-
-
-
-
-
-
-
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;
-
-
-
-
-
-
public class FileAction extends AbstractAction {
-
-
private static final long serialVersionUID = 6649027352616232244L;
-
private FileService fileService;
-
-
-
-
-
-
public String preupload() {
-
return SUCCESS;
-
}
-
-
-
-
-
-
public String uploadfile() {
-
try {
-
UploadFile.upload(this.request, this.response);
-
} catch (IOException e) {
-
LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());
-
}
-
return null;
-
}
-
-
-
-
-
-
public String progress() {
-
String callback1 = this.request.getParameter("callback1");
-
String callback2 = this.request.getParameter("callback2");
-
-
String key = Integer.toString(request.hashCode());
-
-
Progress p = new 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 {
-
-
-
-
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;
-
}
-
-
-
-
-
-
public FileService getFileService() {
-
return fileService;
-
}
-
-
-
-
-
-
-
public void setFileService(FileService fileService) {
-
this.fileService = fileService;
-
}
-
}
页面代码:
注意: common-upload.jar依赖common-io.jar
最后,以前写过一个servlet的上传文件显示进度(很久以前的事了,唉。。。),在这里:
http://blog.csdn.net/tom_221x/archive/2009/01/14/3777064.aspx
有兴趣的实现一个试试吧,还以加入多个文件的队列上传,或是多线程上传,还可以加入断点续传。哈哈,实现了记得要开源噢!
----------------------------------------->>转载于:http://blog.csdn.net/lufeng66/article/details/7354281
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29119536/viewspace-1175521/
,如需转载,请注明出处,否则将追究法律责任。