Struts 2文件上传示例
欢迎使用Struts 2文件上传示例。
文件上传是Web应用程序的常见任务之一,Struts 2为通过FileUploadInterceptor上传单个和多个文件提供了内置功能。
Struts 2文件上传
Struts 2的FileUploadInterceptor拦截器是在struts-default软件包中配置的,我们通常在Struts 2软件包配置中对其进行扩展。
FileUploadInterceptor还提供用于设置最大文件大小限制,允许的文件类型以及可以上传到服务器的扩展名的选项。
Struts 2提供了通过struts.multipart.maxSize
变量配置最大文件大小限制的选项。
如果在单个请求中上传多个文件,则可以方便地设置上传文件的限制。
FileUploadInterceptor截获enctype为" multipart/form-data"的请求,并自动将文件保存在temp目录中,并为操作类提供对File,文件名和文件内容类型的有用引用,以将文件保存在指定位置。
Struts 2文件上传示例
我们将通过一个示例Struts 2项目来研究实现,在该项目中我们将单个文件以及多个文件上传到服务器。
我们的最终项目结构如下图所示。
Struts 2文件上传配置
我们来看一下用于上传单个文件的应用程序的不同部分。
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Struts2FileUploadExample</display-name> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
部署描述符是不言自明的,仅添加Struts 2过滤器即可拦截客户端请求。
pom.xml
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Struts2FileUploadExample</groupId> <artifactId>Struts2FileUploadExample</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.15.1</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <warSourceDirectory>WebContent</warSourceDirectory> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> <finalName>${project.artifactId}</finalName> </build> </project>
Maven配置文件也很容易理解,并且仅包含struts-core依赖项。
UploadFile.jsp
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <%@ taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>Upload File Page</title> </head> <body> <h3>Select File to Upload</h3> <s:form action="UploadFile" method="post" enctype="multipart/form-data"> <s:file label="File" name="file"></s:file> <s:submit value="Upload"></s:submit> </s:form> </body> </html>
在UploadFile.jsp中要注意的重要点是enctype(多部分/表单数据),文件元素名称(文件)和操作(UploadFile)。
在开始执行动作类之前,让我们看一下struts.xml配置文件。
struts.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "https://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.multipart.maxSize" value="104857600" <package name="user" namespace="/" extends="struts-default"> <action name="upload"> <result>/UploadFile.jsp</result> </action> <action name="UploadFile" class="com.theitroad.struts2.actions.UploadFileAction"> <param name="filesPath">myfiles</param> <result name="success">/UploadFileSuccess.jsp</result> <result name="input">/UploadFile.jsp</result> <interceptor-ref name="defaultStack"> <param name="fileUpload.maximumSize">10485760</param> <param name="fileUpload.allowedTypes">text/plain,image/jpeg</param> </interceptor-ref> </action> </package> </struts>
请注意,通过将struts.multipart.maxSize的值设置为100 * 1024 * 1024,我已将单个请求中的最大文件大小限制设置为100 MB。
单个文件大小的FileUploadInterceptor默认限制为2 MB,因此我将其替换为UploadFile操作。
我正在使用带有参数maximumMax(10MB)和allowedTypes(txt,jpg)的defaultStack作为fileUpload拦截器。
现在,我们准备研究动作类的实现。
UploadFileAction.java
package com.theitroad.struts2.actions; import java.io.File; import java.io.IOException; import javax.servlet.ServletContext; import org.apache.struts2.util.ServletContextAware; import com.theitroad.struts2.util.FilesUtil; import com.opensymphony.xwork2.ActionSupport; public class UploadFileAction extends ActionSupport implements ServletContextAware{ private static final long serialVersionUID = -4748500436762141116L; @Override public String execute(){ System.out.println("File Name is:"+getFileFileName()); System.out.println("File ContentType is:"+getFileContentType()); System.out.println("Files Directory is:"+filesPath); try { FilesUtil.saveFile(getFile(), getFileFileName(), context.getRealPath("") + File.separator + filesPath); } catch (IOException e) { e.printStackTrace(); return INPUT; } return SUCCESS; } private File file; private String fileContentType; private String fileFileName; private String filesPath; private ServletContext context; public File getFile() { return file; } public void setFile(File file) { this.file = file; } public String getFileContentType() { return fileContentType; } public void setFileContentType(String fileContentType) { this.fileContentType = fileContentType; } public String getFileFileName() { return fileFileName; } public void setFileFileName(String fileFileName) { this.fileFileName = fileFileName; } public void setFilesPath(String filesPath) { this.filesPath = filesPath; } @Override public void setServletContext(ServletContext ctx) { this.context=ctx; } }
注意,动作类正在实现ServletContextAware接口,该接口包含单个方法setServletContext()。
这样做是为了在操作类中获取ServletContext引用,并使用它来获取Web应用程序的根目录。
这将用于将文件从temp目录保存到Web应用程序内的另一个目录。
您是否注意到为UploadFile操作定义的filesPath
参数,这就是为什么我们有setFilesPath()方法的原因。
Struts 2参数拦截器使用此方法读取struts.xml文件中配置的参数并调用其setter方法。
由fileUpload和params拦截器设置的三个变量是File,文件名和内容类型。
如果请求中的文件元素名称为" pic",则这些变量应为– File pic,String picContentType和String picFileName。
由于我们的UploadFile.jsp文件元素名称为" file",因此我们具有变量file,fileFileName和fileContentType以及其getter和setter方法。
FilesUtil是实用程序类,用于将文件从temp目录保存到Web应用程序中的另一个目录。
FileUtil.java
package com.theitroad.struts2.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class FilesUtil { public static void saveFile(File file, String fileName, String filesDirectory) throws IOException{ FileInputStream in = null; FileOutputStream out = null; File dir = new File (filesDirectory); if ( !dir.exists() ) dir.mkdirs(); String targetPath = dir.getPath() + File.separator + fileName; System.out.println("source file path ::"+file.getAbsolutePath()); System.out.println("saving file to ::" + targetPath); File destinationFile = new File ( targetPath); try { in = new FileInputStream( file ); out = new FileOutputStream( destinationFile ); int c; while ((c = in.read()) != -1) { out.write(c); } }finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } }
成功上传文件代码后的响应JSP页面是:
UploadFileSuccess.jsp
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <%@ taglib uri="/struts-tags" prefix="s" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>Upload Success Page</title> </head> <body> <h3><s:property value="fileFileName" Uploaded Successfully.</h3> </body> </html>
注意,在响应JSP页面中使用了操作类中的fileFileName
变量。
我们已经完成了单文件上传的实现,当我们执行应用程序时,我们将获得以下响应页面。
我们在服务器日志中获得以下日志。
File Name is:IMG_2053.JPG File ContentType is:image/jpeg Files Directory is:myfiles source file path ::/Users/hyman/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/Struts2FileUploadExample/upload_e287e5cd_17be_4f3f_a034_b21ae19da743_00000006.tmp saving file to ::/Users/hyman/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Struts2FileUploadExample/myfiles/IMG_2053.JPG
以上日志确认fileUpload拦截器将文件上传到temp目录中,并以.tmp扩展名重命名。
相同的文件从那里复制到我们指定的位置。
Struts 2多个文件上传
如果您了解单文件上传的工作原理,那么多文件上传非常简单。
FileUploadInterceptor将请求中的所有文件保存到temp目录中,我们可以使用Array或者List在操作类中获取它们的引用。
UploadMultipleFile.jsp
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <%@ taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>Upload File Page</title> </head> <body> <h3>Select File to Upload</h3> <s:form action="UploadMultipleFile" method="post" enctype="multipart/form-data"> <s:file label="File 1:" name="file"></s:file> <s:file label="File 2:" name="file"></s:file> <s:file label="File 3:" name="file"></s:file> <s:submit value="Upload"></s:submit> </s:form> </body> </html>
请注意,所有文件元素名称均相同。
UploadMultipleFileAction.java
package com.theitroad.struts2.actions; import java.io.File; import java.io.IOException; import java.util.Arrays; import javax.servlet.ServletContext; import org.apache.struts2.util.ServletContextAware; import com.theitroad.struts2.util.FilesUtil; import com.opensymphony.xwork2.ActionSupport; public class UploadMultipleFileAction extends ActionSupport implements ServletContextAware{ private static final long serialVersionUID = -4748500436762141236L; @Override public String execute(){ System.out.println("No of files="+getFile().length); System.out.println("File Names are:"+Arrays.toString(getFileFileName())); for(int i=0; i < getFile().length; i++){ System.out.println("File Name is:"+getFileFileName()[i]); System.out.println("File ContentType is:"+getFileContentType()[i]); System.out.println("Files Directory is:"+filesPath); try { FilesUtil.saveFile(getFile()[i], getFileFileName()[i], context.getRealPath("") + File.separator + filesPath); } catch (IOException e) { e.printStackTrace(); return INPUT; } } return SUCCESS; } private File[] file; private String[] fileContentType; private String[] fileFileName; private String filesPath; /** * We could use List also for files variable references and declare them as: * * private List<File> file = new ArrayList<File>(); * private List<String> fileContentType = new ArrayList<String>(); * private List<String> fileFileName = new ArrayList<String>(); */ private ServletContext context; public File[] getFile() { return file; } public void setFile(File[] file) { this.file = file; } public String[] getFileContentType() { return fileContentType; } public void setFileContentType(String[] fileContentType) { this.fileContentType = fileContentType; } public String[] getFileFileName() { return fileFileName; } public void setFileFileName(String[] fileFileName) { this.fileFileName = fileFileName; } public void setFilesPath(String filesPath) { this.filesPath = filesPath; } @Override public void setServletContext(ServletContext ctx) { this.context=ctx; } }
动作类类似于单次上传,不同之处在于变量现在是数组或者列表,可以容纳多个值。
我们正在迭代数组并将每个文件保存到特定目录。
UploadMultipleFileSuccess.jsp
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> <%@ taglib uri="/struts-tags" prefix="s" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>Upload Success Page</title> </head> <body> <h3><s:property value="fileFileName" Uploaded Successfully.</h3> </body> </html>
要配置它们,只需在现有的struts.xml文件中的action元素下面添加。
<action name="uploadMultiple"> <result>/UploadMultipleFile.jsp</result> </action> <action name="UploadMultipleFile" class="com.theitroad.struts2.actions.UploadMultipleFileAction"> <param name="filesPath">myfiles</param> <result name="success">/UploadMultipleFileSuccess.jsp</result> <result name="input">/UploadMultipleFile.jsp</result> <interceptor-ref name="defaultStack"> <param name="fileUpload.maximumSize">10485760</param> <param name="fileUpload.allowedTypes">text/plain,image/jpeg</param> </interceptor-ref> </action>
现在,当我们执行多个文件上传操作时,我们得到以下响应页面。
我们在服务器日志文件中获得以下日志片段。
No of files=3 File Names are:[ETERNA_Movie_List.txt, DSC05510.JPG, IMG_2053.JPG] File Name is:ETERNA_Movie_List.txt File ContentType is:text/plain Files Directory is:myfiles source file path ::/Users/hyman/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/Struts2FileUploadExample/upload_e287e5cd_17be_4f3f_a034_b21ae19da743_00000007.tmp saving file to ::/Users/hyman/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Struts2FileUploadExample/myfiles/ETERNA_Movie_List.txt File Name is:DSC05510.JPG File ContentType is:image/jpeg Files Directory is:myfiles source file path ::/Users/hyman/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/Struts2FileUploadExample/upload_e287e5cd_17be_4f3f_a034_b21ae19da743_00000008.tmp saving file to ::/Users/hyman/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Struts2FileUploadExample/myfiles/DSC05510.JPG File Name is:IMG_2053.JPG File ContentType is:image/jpeg Files Directory is:myfiles source file path ::/Users/hyman/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/Struts2FileUploadExample/upload_e287e5cd_17be_4f3f_a034_b21ae19da743_00000009.tmp saving file to ::/Users/hyman/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Struts2FileUploadExample/myfiles/IMG_2053.JPG