Struts 2文件上传示例

时间:2020-02-23 14:36:04  来源:igfitidea点击:

欢迎使用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