一、为了上传文件,需要把表单的method设置成POST,将enctype设置为multipart/form-data。
Struts2并未提供自己的请求解析器,也就是说,Struts2不会自己去处理multipart/form-data的请求,而是调用其它上传框架来解析二进制请求数据。不过Struts2将其它上传框架进行了一次封装,简化了文件上传开发过程。
在Struts2的struts.properties配置文件中,看到了如下配置代码
#指定使用COS的文件上传解析器
#struts.multipart.parser=cos
#指定使用Pell的文件上传解析器
#struts.multipart.parser=pell
#struts2默认使用Jakarta的Common-FileUpload的文件上传解析器
struts.multipart.parser=jakarta
Struts2默认使用Common-FileUpload的文件上传框架,如果需要使用此上传文件,则项目中应该增加两个JAR文件,即commons-io-2.2.jar和commons-fileupload-1.3.1.jar。
首先前台页面uploadForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title><s:text name="文件上传测试"/></title> </head> <body> <s:form action="upload" enctype="multipart/form-data" method="POST"> <s:textfield name="title" label="文件标题" /> <s:file name="upload" label="选择文件" /> <s:submit value="上传" /> </s:form> </body> </html>
然后是Action处理类UploadAction.java
package actions; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class UploadAction extends ActionSupport { private String title; private File upload; private String uploadContentType; private String uploadFileName; private String savePath; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public File getUpload() { return upload; } public void setUpload(File upload) { this.upload = upload; } public String getUploadContentType() { return uploadContentType; } public void setUploadContentType(String uploadContentType) { this.uploadContentType = uploadContentType; } public String getUploadFileName() { return uploadFileName; } public void setUploadFileName(String uploadFileName) { this.uploadFileName = uploadFileName; } public String getSavePath() { return ServletActionContext.getServletContext().getRealPath("/uploadFiles"); } public void setSavePath(String savePath) { this.savePath = "/uploadFiles"; } //FileInputStream读取上传的文件并通过FileOutputStream写入服务器指定路径 @Override public String execute() throws Exception { System.out.println(getSavePath()); FileOutputStream fos = new FileOutputStream(getSavePath() + "/" + getUploadFileName()); FileInputStream fis = new FileInputStream(getUpload()); byte[] buffer = new byte[1024]; int len = 0; while ((len = fis.read(buffer)) > 0) { fos.write(buffer, 0, len); } return SUCCESS; } }
struts.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="true" /> <package name="yang" extends="struts-default"> <action name="upload" class="actions.UploadAction"> <result name="success">/WEB-INF/jsp/upload-success.jsp</result> <result name="input">uploadForm.jsp</result> </action> </package> </struts>
通过以上简单的例子就可以实现文件上传的基本功能。
二、手工实现文件过滤。
重写Struts2中Action的validate()方法,通过getUploadContentType();获取上传文件的类型,判断是否符合所要求文件类型来决定是否允许上传,如不允许上传,则在validate()方法中通过addFieldError("upload","<message>")添加错误信息,Struts2框架判断fielderror不为空时会自动返回input逻辑视图。限制上传文件大小的逻辑类似,通过判断File的字节长度是否在允许的范围内,在此就不展示代码示例了。可以阅读之前的校验章节了解validate()方法的工作机制。
注意:在这里需要提出一点在文件上传的Action中,有两个成员变量并没有对应的表单元素,即uploadFileName和uploadContentType,这两个成员变量分别用于封装文件名和文件类型。Action中的File类型变量直接封装文件的内容,但是Struts2会将文件域中包含的上传文件名和文件类型封装到对应的成员变量中。Struts2设计真是巧妙!
三、通过配置拦截器实现文件过滤
Struts2提供了一个文件上传的拦截器,通过struts.xml应该如下配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="true" /> <package name="yang" extends="struts-default"> <action name="upload" class="actions.UploadAction"> <interceptor-ref name="fileUpload"> <param name="allowedTypes">img/jpeg</param> <param name="maximumSize">20</param> </interceptor-ref> <interceptor-ref name="defaultStack" /> <result name="success">/WEB-INF/jsp/upload-success.jsp</result> <result name="input">index.jsp</result> </action> </package> </struts>
加粗部分即是Struts2的文件上传拦截器,必须配置defaultStack且放在fileUpload拦截器之后,因为defaultStack拦截器也配置了fileUpload拦截器,默认允许上传任何文件,拦截器的执行逻辑是前面的会覆盖后面的,所以defaultStack必须放在我们配置的文件上传拦截器之后。
该拦截器可以指定如下两个参数
- allowedTypes指定允许上传的文件类型,多个文件类型以英文逗号隔开
- maximumSize指定允许上传的文件大小,单位是字节
注意:此处Action不可以符合零配置原则,当然也可以将零配置的jar包删除,否则过滤器将不起作用。
上传失败后将通过<s:fielderror/>提示错误信息,系统默认的错误信息不易读且太长,当然也可以自定义友好错误信息。通过Action的配置文件配置错误信息。
- struts.messages.error.file.too.large文件太大提示信息的key
- struts.messages.error.content.type.not.allowed类型不允许提示信息的key
此外,Struts2还提供了一个struts.messages.error.uploadingkey,不是前面两种类型的未知上传错误,则提示此key的信息。
另外提一下:上传时在控制台看到如下提示:
Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir
是说在Struts2执行文件上传时,需通过Struts的配置文件指定一个临时目录,如果没有指定则系统默认使用javax.servlet.context.tempdir,在tomcat安装路径下的workCatalinalocalhost下。上传完成后,该临时目录将被自动删除。
在struts配置文件中
- <constant name="struts.multipart.saveDir" value=""/>可以指定上传临时目录
- <constant name="struts.multipart.maxSize" value=""/>可以指定整个表单一次上传内容的最大字节数