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

