最近想要用struts2来实现文件上传进度条,结合自己所学的知识和网上找到的一些资料,现在整理好了,以供各位网友作为参考,也给自己多屯点干货。
要实现文件上传的进度条的现实,关键就是要获取当前文件的上传状态,知道当前上传的是哪个文件,文件的总大小以及上传了多少。以前,学习apache fileupload框架时,可以在文件上传的时候添加一个文件上传进度的监听器,下面贴出官网给出的示例,相信有一定基础的童靴一看基本上就懂了。
//Create a progress listener
ProgressListener progressListener = new ProgressListener(){
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("We are currently reading item " + pItems);
if (pContentLength == -1) {
System.out.println("So far, " + pBytesRead + " bytes have been read.");
} else {
System.out.println("So far, " + pBytesRead + " of " + pContentLength
+ " bytes have been read.");
}
}
};
upload.setProgressListener(progressListener);
上面的ProgressListener接口有一个update()方法,在上传文件的时候会自动的调用这个方法,把相应的状态传递过来,参数pBytesRead就是当前读取的字节数,pContentLength文件的总大小,pItems当前上传的是第几个文件。了解了上面的代码后,你应该大致知道该怎么实现了吧。
但是在struts2中,上传的文件直接是保存到action里面的,并用一个File对象来接受,我们并不需要干涉文件上传的过程,我们只知道那个上传的文件是直接可以获取到的,例如下面写的这段代码:
private File file;
private String contentType;
private String fileName;
public void setUpload(File file){
this.file = file;
}
public void setUploadContentType(String contentType){
this.contentType = contentType;
}
public void setUploadFileName(String fileName){
this.fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
}
此时上传的文件已经是一个完整的文件,你能获取到它的文件类型已经文件名称。它以临时文件的方式保存在硬盘上,我们要做的只是把这个文件放到我们想要放到的目录。但是我们怎么样来添加哪个监听器呢?仔细阅读struts2的源码,可以发现如下的代码
public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException {
// don't wrap more than once
if (request instanceof StrutsRequestWrapper) {
return request;
}
String content_type = request.getContentType();
if (content_type != null && content_type.contains("multipart/form-data")) {
MultiPartRequest mpr = getMultiPartRequest();
LocaleProvider provider = getContainer().getInstance(LocaleProvider.class);
request = new MultiPartRequestWrapper(mpr, request, getSaveDir(servletContext), provider);
} else {
request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);
}
return request;
}
这个方法是Dispatcher类的方法(具体的东西大家可以去追源代码,从StrutsPrepareAndExecuteFilter.doFilter()方法里面的 request = prepare.wrapRequest(request);这段话开始),如果是文件上传request被包装成了 MultiPartRequestWrapper。
我们都知道,struts2的文件上传是以拦截的方式实现的,即FileUploadInterceptor拦截器,会调用拦截器的intercept方法,仔细的阅读intercept里面的这段方法:
MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
if (multiWrapper.hasErrors()) {
for (String error : multiWrapper.getErrors()) {
if (validation != null) {
validation.addActionError(error);
}
}
}
// bind allowed Files
Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
// get the value of this input tag
String inputName = (String) fileParameterNames.nextElement();
// get the content type
String[] contentType = multiWrapper.getContentTypes(inputName);
if (isNonEmpty(contentType)) {
// get the name of the file from the input tag
String[] fileName = multiWrapper.getFileNames(inputName);
if (isNonEmpty(fileName)) {
// get a File object for the uploaded File
File[] files = multiWrapper.getFiles(inputName);
if (files != null && files.length > 0) {
List<File> acceptedFiles = new ArrayList<File>(files.length);
List<String> acceptedContentTypes = new ArrayList<String>(files.length);
List<String> acceptedFileNames = new ArrayList<String>(files.length);
String contentTypeName = inputName + "ContentType";
String fileNameName = inputName + "FileName";
for (int index = 0; index < files.length; index++) {
if (acceptFile(action, files[index], fileName[index], contentType[index], inputName, validation)) {
acceptedFiles.add(files[index]);
acceptedContentTypes.add(contentType[index]);
acceptedFileNames.add(fileName[index]);
}
}
if (!acceptedFiles.isEmpty()) {
Map<String, Object> params = ac.getParameters();
params.put(inputName, acceptedFiles.toArray(new File[acceptedFiles.size()]));
params.put(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()]));
params.put(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()]));
}
}
} else {
if (LOG.isWarnEnabled()) {
LOG.warn(getTextMessage(action, "struts.messages.invalid.file", new String[]{inputName}));
}
}
} else {
if (LOG.isWarnEnabled()) {
LOG.warn(getTextMessage(action, "struts.messages.invalid.content.type", new String[]{inputName}));
}
}
}
我们再来仔细的看下这个类,可以发现在这个类的构造器中,有这样一个接口MultiPartRequest,它的实现类是JakartaMultiPartRequest,没错就是这个类,用来处理上传请求的,然后您可以看到这个类中的
private List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException {
DiskFileItemFactory fac = createDiskFileItemFactory(saveDir);
ServletFileUpload upload = new ServletFileUpload(fac);
upload.setSizeMax(maxSize);
return upload.parseRequest(createRequestContext(servletRequest));
}
我们所要做的工作就是在这个方法中添加一个ProgressListener, 因此我们需要对这个方法重新,改写后的这个方法如下:
private List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException {
DiskFileItemFactory fac = createDiskFileItemFactory(saveDir);
ServletFileUpload upload = new ServletFileUpload(fac);
upload.setSizeMax(maxSize);
FileUploadProgressListener progressListener = new FileUploadProgressListener(servletRequest);
upload.setProgressListener(progressListener);
return upload.parseRequest(createRequestContext(servletRequest));
}
一切都好像差不多了,但是不要忘记把这个文件上传解析器给配置进来,
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="progress" class="com.warnow.action.fileupload.ProgressMultiPartRequest" scope="default"/>
<constant name="struts.multipart.parser" value="progress" />
这个解析器在struts-default.xml文件中是有配置的如下:
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default"/>
文件上传的jsp页面如下所示:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>testUpload progress!</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type="text/javascript" src="jquery-1.6.4.js"></script>
</head>
<body>
<form action="upload.action" enctype="multipart/form-data" method="post">
<input type="file" name="upload">
<input type="submit" value="submit" οnclick="formSubmit()">
</form>
<span id="percent"></span>
<div style="width: 560px;height: 25px;background-color: rgb(193, 210, 240);">
<div id="progress" style="background-color: blue;height: 25px;width:0%"></div>
</div>
<script type="text/javascript">
function formSubmit(){
window.setInterval("getUploadStatus()", 1000);
document.forms[0].submit();
}
function getUploadStatus(){
$.post("fileUploadStatus.action",
function(data){
$("#percent").html("文件已经上传:" + data);
$("#progress").css("width", data);
});
}
</script>
</body>
</html>
效果如图:
还有一些文件未一一列出出来,现在给出源代码的链接(项目源代码)——供大家下载学习,有什么不懂的地方,欢迎随时的问我。