- 相信文件上传功能是当下很多web程序必需品,Struts为我们提供了简单易用的文件上传功能。
基于传统Servlet的文件上传与使用Struts的文件上传比对
文件上传是通过表单来实现的,表单传递数据有两种形式,一种是以字符串的形式,另外一种是以二进制流的形式。当要在表单中传文件时,enctype就必须设置成为二进制流形式,即enctype="multipart/form-data"。这时表单中不单单是文件,还有其他的表单域也会以二进制流形式传递。传统的Servlet中,需要将文件从二进制流中分离出来,一般是通过设置一个不会被使用到的符号做标记来进行分离,这样文件上传的工作是比较繁琐的。庆幸的是Struts为我们提供了更简单易用的文件上传功能,让我们不用自己编写代码去从二进制数据流中分离出文件。
Sturts中的文件上传
在Struts中,文件上传会被划分为单文件上传和多文件上传,之所以会这么划分,是因为单文件上传和多文件上传时,Action的属性类型有所不同,所以需要区分对待,下面也会划分为单文件上传和多文件上传来讲。
首先文件上传是由动作来处理的,Struts要求我们在动作中具备以下的三个属性:
- [inutName]
- [inputName]FileName
- [inputName]ContentType
其中inputName是表单中,文件上传域的name属性名称,比方说,你在表单中存在一个文件上传域<s:file name="file"/>,那么我们的动作中就必须具备file、fileFileName、fileContentType三个属性名称。
文件上传常量配置
文件上传时,我一般在struts.xml中配置两个常量
<!-- 在配置文件中需要配置两个关于文件上传的常量 -->
<constant name="struts.multipart.maxSize" value="104857600"></constant>
<constant name="struts.multipart.saveDir" value="/tmpfiles"></constant>
其中名称为struts.multipart.maxSize常量是配置上传的所有文件总大小限制,这个常量的默认值是2MB,这里的计量单位是B。如果上传的文件大小超过了该常量值的大小,那么动作将会返回INPUT,execute方法不执行,并抛出一个SizeLimitExceededException,这时候,[inutName]、[inputName]FileName和[inputName]ContentType三个属性值都将null。
而名称为struts.mutipart.saveDir常量是配置上传文件时产生的临时文件(从客户端将文件传送到服务器是会产生临时文件的)的存放路径,相对的路径是web程序的根。
单文件上传
单个文件上传时,上述的三个属性所取的类型如下:
- [inputName]:File
- [inputName]FileName:String
- [inputName]ContentType:String
当表单提交到动作后,会自动将属性填充进来,[inputName]是存放在服务器临时目录下的临时文件,所以千万不要使用[inputName].getName()来获取文件名,临时文件的名称是随机的,后缀是.tmp,但是它内部的数据是我们想要的数据。[inputName]FileName是上传的那个文件的文件名称,这个文件名称是带后缀的。[inputName]ContentType是上传的文件的MIME类型。
当属性填充完后,需要做的是将临时文件拷贝到服务器的某个路径下,在动作的execute方法中书写我们的业务逻辑就可以,以下是一个实例:
@SuppressWarnings("serial")
public class SingleUploadAction extends ActionSupport implements ServletContextAware {
private File file; //取名为[inputName]
private String fileFileName; //取名为[inputName]Fileame
private String fileContentType; //取名为[inputName]ContentType
private ServletContext context;
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getFileFileName() {
return fileFileName;
}
public void setFileFileName(String fileFileName) {
this.fileFileName = fileFileName;
}
public String getFileContentType() {
return fileContentType;
}
public void setFileContentType(String fileContentType) {
this.fileContentType = fileContentType;
}
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
/*
* 执行应该做的IO操作,将临时文件拷贝到应用程序根目录下的upload文件夹中,且文件名跟上传的文件同名
*/
if(fileFileName == null)
{
System.out.println(file);
System.out.println(fileContentType);
return INPUT;
}
File parent = new File(context.getRealPath("/upload"));
if(parent.exists())
{
RandomAccessFile fileReader = new RandomAccessFile(file, "r");
File dest = new File(parent, fileFileName);
dest.createNewFile();
RandomAccessFile fileWriter = new RandomAccessFile(dest, "rw");
byte[] buffer = new byte[1024];
int len = -1;
while((len = fileReader.read(buffer)) != -1)
{
fileWriter.write(buffer, 0, len);
}
fileWriter.close();
fileReader.close();
}
return SUCCESS;
}
public void setServletContext(ServletContext arg0) {
// TODO Auto-generated method stub
this.context = arg0;
}
}
动作的配置
处理文件上传的Action要配置文件上传拦截器,以下是配置的实例:
<action name="singleUpload" class="com.daniel.action.SingleUploadAction">
<interceptor-ref name="fileUpload">
<param name="allowedTypes">application/pdf</param>
</interceptor-ref>
<interceptor-ref name="basicStack"></interceptor-ref>
<result name="success">/jsp/ListFile.jsp</result>
<result name="input">/jsp/SingleUpload.jsp</result>
</action>
其中参数allowedTypes是允许上传的文件类型,可以配置多个类型,用逗号隔开。
如果碰到不允许上传的文件类型,依旧会执行execute方法,而且动作中[inutName]、[inputName]FileName和[inputName]ContentType三个属性值都将null。
多文件上传
多文件上传时,上述的三个属性所取的类型如下:
- [inputName]:File[] 或者List<File>
- [inputName]FileName:String[]
- [inputName]ContentType:String[]
单文件上传与多文件上传的异同
不同点:仅在于三个属性的类型不一样。
相同点:业务逻辑的编写、动作配置、运行机制。