Struts 是通过Commons FileUpload文件上传Commons FileUpload通过将HTTP的数据保存到临时文件夹然后Struts使用fileUpload拦截器将文件绑定到Action的实例中从而我们就能够以本地文件方式的操作浏览器上传的文件
具体实现 前段时间Apache发布了Struts GA所以本文的实现是以该版本的Struts作为框架的以下是例子所依赖类包的列表
清单 依赖类包的列表
首先创建文件上传页面FileUploadjsp内容如下
<% @ page language = java contentType = text/html; charset=utf pageEncoding = utf %>
<% @ taglib prefix = s uri = /strutstags %>
<! DOCTYPE html PUBLIC //WC//DTD XHTML Transitional//EN transitionaldtd >
< html xmlns = >
< head >
< title > Struts File Upload </ title >
</ head >
< body >
< s:form action =fileUpload method =POST enctype =multipart/formdata >
< s:file name =myFile label =Image File />
< s:textfield name =caption label =Caption />
< s:submit />
</ s:form >
</ body >
</ html >
清单
FileUpload
jsp
在FileUploadjsp中先将表单的提交方式设为POST然后将enctype设为multipart/formdata这并没有什么特别之处接下来<s:file/>标志将文件上传控件绑定到Action的myFile属性
其次是FileUploadActionjava代码
package tutorial;
import javaioBufferedInputStream;
import javaioBufferedOutputStream;
import javaioFile;
import javaioFileInputStream;
import javaioFileOutputStream;
import javaioInputStream;
import javaioOutputStream;
import javautilDate;
import orgapachestrutsServletActionContext;
import comopensymphonyxworkActionSupport;
public class FileUploadAction extends ActionSupport {
private static final long serialVersionUID = l ;
private static final int BUFFER_SIZE = * ;
private File myFile;
private String contentType;
private String fileName;
private String imageFileName;
private String caption;
public void setMyFileContentType(String contentType) {
ntentType = contentType;
}
public void setMyFileFileName(String fileName) {
this fileName = fileName;
}
public void setMyFile(File myFile) {
this myFile = myFile;
}
public String getImageFileName() {
return imageFileName;
}
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this caption = caption;
}
private static void copy(File src File dst) {
try {
InputStream in = null ;
OutputStream out = null ;
try {
in = new BufferedInputStream( new FileInputStream(src) BUFFER_SIZE);
out = new BufferedOutputStream( new FileOutputStream(dst) BUFFER_SIZE);
byte [] buffer = new byte [BUFFER_SIZE];
while (inread(buffer) > ) {
outwrite(buffer);
}
} finally {
if ( null != in) {
inclose();
}
if ( null != out) {
outclose();
}
}
} catch (Exception e) {
eprintStackTrace();
}
}
private static String getExtention(String fileName) {
int pos = fileNamelastIndexOf( );
return fileNamesubstring(pos);
}
@Override
public String execute() {
imageFileName = new Date()getTime() + getExtention(fileName);
File imageFile = new File(ServletActionContextgetServletContext()getRealPath( /UploadImages ) + / + imageFileName);
copy(myFile imageFile);
return SUCCESS;
}
} 清单 tutorial/FileUploadActionjava
在FileUploadAction中我分别写了setMyFileContentTypesetMyFileFileNamesetMyFile和setCaption四个Setter方法后两者很容易明白分别对应FileUploadjsp中的<s:file/>和<s:textfield/>标志但是前两者并没有显式地与任何的页面标志绑定那么它们的值又是从何而来的呢?其实<s:file/>标志不仅仅是绑定到myFile还有myFileContentType(上传文件的MIME类型)和myFileFileName(上传文件的文件名该文件名不包括文件的路径)因此<s:file name=xxx />对应Action类里面的xxxxxxContentType和xxxFileName三个属性
FileUploadAction作用是将浏览器上传的文件拷贝到WEB应用程序的UploadImages文件夹下新文件的名称是由系统时间与上传文件的后缀组成该名称将被赋给imageFileName属性以便上传成功的跳转页面使用
下面我们就来看看上传成功的页面
<% @ page language = java contentType = text/html; charset=utf pageEncoding = utf %>
<% @ taglib prefix = s uri = /strutstags %>
<! DOCTYPE html PUBLIC //WC//DTD XHTML Transitional//EN transitionaldtd >
< html xmlns = >
< head >
< title > Struts File Upload </ title >
</ head >
< body >
< div style =padding: px; border: solid px #cccccc; textalign: center >
< img src =UploadImages/<s:property value =imageFileName /> />
< br />
< s:property value =caption />
</ div >
</ body >
</ html > 清单 ShowUploadjsp
ShowUploadjsp获得imageFileName将其UploadImages组成URL从而将上传的图像显示出来
然后是Action的配置文件
<? xml version= encoding=UTF ?>
<! DOCTYPE struts PUBLIC
//Apache Software Foundation//DTD Struts Configuration //EN
dtd >
< struts >
< package name =fileUploadDemo extends =strutsdefault >
< action name =fileUpload class =tutorialFileUploadAction >
< interceptorref name =fileUploadStack />
< result name =success > /ShowUploadjsp </ result >
</ action >
</ package >
</ struts > 清单 strutsxml
fileUpload Action显式地应用fileUploadStack的拦截器
最后是webxml配置文件
<? xml version= encoding=UTF ?>
< webapp id =WebApp_ version =
xmlns =
xmlns:xsi =instance
xsi:schemaLocation = app__xsd >
< displayname > Struts Fileupload </ displayname >
< filter >
< filtername > strutscleanup </ filtername >
< filterclass >
orgapachestrutsdispatcherActionContextCleanUp
</ filterclass >
</ filter >
< filter >
< filtername > struts </ filtername >
< filterclass >
orgapachestrutsdispatcherFilterDispatcher
</ filterclass >
</ filter >
< filtermapping >
< filtername > strutscleanup </ filtername >
< urlpattern > /* </ urlpattern >
</ filtermapping >
< filtermapping >
< filtername > struts </ filtername >
< urlpattern > /* </ urlpattern >
</ filtermapping >
< welcomefilelist >
< welcomefile > l </ welcomefile >
</ welcomefilelist >
</ webapp > 清单 WEBINF/webxml
发布运行应用程序在浏览器地址栏中键入出现图示页面
清单 FileUpload页面
选择图片文件填写Caption并按下Submit按钮提交出现图示页面
清单 上传成功页面
更多配置
在运行上述例子如果您留心一点的话应该会发现服务器控制台有如下输出
Mar : : PM orgapachestrutsdispatcherDispatcher getSaveDir
INFO: Unable to find strutsmultipartsaveDir property setting Defaulting to ntexttempdir
Mar : : PM orgapachestrutsinterceptorFileUploadInterceptor intercept
INFO: Removing file myFile C:\Program Files\Tomcat \work\Catalina\localhost\Struts_Fileupload\upload_c_e__ff_tmp 清单 服务器控制台输出
上述信息告诉我们strutsmultipartsaveDir没有配置strutsmultipartsaveDir用于指定存放临时文件的文件夹该配置写在strutsproperties文件中例如如果在strutsproperties文件加入如下代码
strutsmultipartsaveDir = /tmp 清单 struts配置
这样上传的文件就会临时保存到你根目录下的tmp文件夹中(一般为c:\tmp)如果此文件夹不存在Struts 会自动创建一个
错误处理
上述例子实现的图片上传的功能所以应该阻止用户上传非图片类型的文件在Struts 中如何实现这点呢?其实这也很简单对上述例子作如下修改即可
首先修改FileUploadjsp在<body>与<s:form>之间加入<s:fielderror />用于在页面上输出错误信息
然后修改strutsxml文件将Action fileUpload的定义改为如下所示
< action name =fileUpload class =tutorialFileUploadAction >
< interceptorref name =fileUpload >
< param name =allowedTypes >
image/bmpimage/pngimage/gifimage/jpeg
</ param >
</ interceptorref >
< interceptorref name =defaultStack />
< result name =input > /FileUploadjsp </ result >
< result name =success > /ShowUploadjsp </ result >
</ action > 清单 修改后的配置文件
显而易见起作用就是fileUpload拦截器的allowTypes参数另外配置还引入defaultStack它会帮我们添加验证等功能所以在出错之后会跳转到名称为input的结果也即是FileUploadjsp
发布运行应用程序出错时页面如下图所示
清单 出错提示页面
上面的出错提示是Struts 默认的大多数情况下我们都需要自定义和国际化这些信息通过在全局的国际资源文件中加入ntenttypenotallowed=The file you uploaded is not a image可以实现以上提及的需求对此有疑问的朋友可以参考我之前的文章《在Struts 中国际化(in)您的应用程序》
实现之后的出错页面如下图所示
清单 自定义出错提示页面
同样的做法你可以使用参数maximumSize来限制上传文件的大小它对应的字符资源名为ssageserrorfiletoolarge
字符资源ssageserroruploading用提示一般的上传出错信息
多文件上传
与单文件上传相似Struts 实现多文件上传也很简单你可以将多个<s:file />绑定Action的数组或列表如下例所示
< s:form action =doMultipleUploadUsingList method =POST enctype =multipart/formdata >
< s:file label =File () name =upload />
< s:file label =File () name =upload />
< s:file label =FIle () name =upload />
< s:submit />
</ s:form > 清单 多文件上传JSP代码片段
如果你希望绑定到数组Action的代码应类似
private File[] uploads;
private String[] uploadFileNames;
private String[] uploadContentTypes;
public File[] getUpload() { return this uploads; }
public void setUpload(File[] upload) { this uploads = upload; }
public String[] getUploadFileName() { return this uploadFileNames; }
public void setUploadFileName(String[] uploadFileName) { this uploadFileNames = uploadFileName; }
public String[] getUploadContentType() { return this uploadContentTypes; }
public void setUploadContentType(String[] uploadContentType) { this uploadContentTypes = uploadContentType; } 清单 多文件上传数组绑定Action代码片段
如果你想绑定到列表则应类似
private List < File > uploads = new ArrayList < File > ();
private List < String > uploadFileNames = new ArrayList < String > ();
private List < String > uploadContentTypes = new ArrayList < String > ();
public List < File > getUpload() {
return this uploads;
}
public void setUpload(List < File > uploads) {
this uploads = uploads;
}
public List < String > getUploadFileName() {
return this uploadFileNames;
}
public void setUploadFileName(List < String > uploadFileNames) {
this uploadFileNames = uploadFileNames;
}
public List < String > getUploadContentType() {
return this uploadContentTypes;
}
public void setUploadContentType(List < String > contentTypes) {
this uploadContentTypes = contentTypes;
} 清单 多文件上传列表绑定Action代码片段
总结
在Struts 中实现文件上传的确是轻而易举您要做的只是使用<s:file />与Action的属性绑定这又一次有力地证明了Struts 的简单易用