Struts 2 Single and Multiple File Upload Example

File Upload is one of the common tasks of a web application and Struts 2 provides built-in feature for single and multiple file upload through FileUploadInterceptor.

FileUploadInterceptor interceptor is configured in the struts-default package that we usually extend in Struts 2 package configuration. FileUploadInterceptor also provide options to set the maximum file size limit, allowed file types and extensions that can be uploaded to the server. Struts 2 provide option to configure the maximum file size limit through struts.multipart.maxSize variable. This comes handy to set the limit to upload files incase of multiple files uploading in a single request.

FileUploadInterceptor intercepts the request with enctype as “multipart/form-data” and automatically saves the file in the temp directory and provide useful reference to File, file name and file content type to action classes to save the file at specified location.

We will look into the implementation through a sample Struts 2 project where we will upload single file as well as multiple files to server. Our final project structure looks like below image.

Struts2-File-Upload-Project

Struts 2 File Upload

Let’s look at different parts of the application for uploading a single file.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://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>

Deployment descriptor is self explanatory, just adding Struts 2 filter to intercept the client requests.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://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 configuration file is also easy to understand and includes only struts-core dependency.

<%@ 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" "http://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>

The important points to note in UploadFile.jsp are enctype (multipart/form-data), file element name (file) and action (UploadFile).

Before we move to action class implementation, let’s look at the struts.xml configuration file.

<?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.multipart.maxSize" value="104857600" />
	<package name="user" namespace="/" extends="struts-default">
		<action name="upload">
			<result>/UploadFile.jsp</result>
		</action>
		<action name="UploadFile" class="com.journaldev.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>

Notice that I have set the maximum file size limit in a single request to 100 MB by setting the value of struts.multipart.maxSize to 100*1024*1024.

FileUploadInterceptor default limit for single file size is 2 MB, so I am overriding it for UploadFile action. I am using defaultStack with params maximumSize (10MB) and allowedTypes (txt, jpg) for fileUpload interceptor.

Now we are ready to look into the action class implementation.

package com.journaldev.struts2.actions;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletContext;

import org.apache.struts2.util.ServletContextAware;

import com.journaldev.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;
	}
	
}

Notice that action class is implementing ServletContextAware interface that contains single method setServletContext(). This is done to get the ServletContext reference in action class and use it to get the web application root directory. This will be used in saving the file from temp directory to another directory inside web application.

Did you noticed filesPath parameter defined for UploadFile action, that’s why we have setFilesPath() method. This method is used by Struts 2 params interceptor to read the params configured in struts.xml file and invoke it’s setter method.

The three variables that are set by fileUpload and params interceptors are File, file name and content type. If the file element name in request is “pic” then these variables should be – File pic, String picContentType and String picFileName. Since our UploadFile.jsp file element name is “file”, we have variables file, fileFileName and fileContentType with their getter and setters.

FilesUtil is utility class that is used to save the file from temp directory to another directory in the web application.

package com.journaldev.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();
            }
        }
        
	}
}

The response JSP page after successful file upload code is:

<%@ 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" "http://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>

Notice the use of fileFileName variable from action class is used in response JSP page.

Our implementation for single file upload is ready, when we execute the application we get following response pages.

Struts2-File-Upload-Request

Struts2-File-Upload-Response

We get following logs in server logs.

File Name is:IMG_2053.JPG
File ContentType is:image/jpeg
Files Directory is:myfiles
source file path ::/Users/pankaj/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/pankaj/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Struts2FileUploadExample/myfiles/IMG_2053.JPG

Above logs confirm that fileUpload interceptor uploads file in temp directory and rename it with .tmp extension. The same file is copied from there to our specified location.

Struts 2 Multiple File Upload

If you understood how single file upload works, then multiple file upload is very easy. FileUploadInterceptor saves all the files in request to temp directory and we can use Array or List to get their reference in action classes.

<%@ 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" "http://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>
[/xml]

Notice that all the file elements name are same.

1

Action class is similar as single upload, except that the variables are now array or list to hold multiple values. We are iterating the array and saving each file to specific directory.

1
<%@ 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" "http://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>

To configure them, just add below action elements in existing struts.xml file.

		<action name="uploadMultiple">
			<result>/UploadMultipleFile.jsp</result>
		</action>

		<action name="UploadMultipleFile"
			class="com.journaldev.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>

Now when we execute multiple file upload action, we get following response pages.

Struts2-Multiple-File-Upload-Request

Struts2-Multiple-File-Upload-Response

We get following log snippet in the server log file.

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/pankaj/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/pankaj/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/pankaj/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/pankaj/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/pankaj/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/pankaj/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/Struts2FileUploadExample/myfiles/IMG_2053.JPG

That’s all for Struts 2 File Upload tutorial, I hope you liked it.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Current ye@r *

Subscribe to JournalDev Newsletter
Get the FREE access to Monthly Newsletter and Free PDF eBooks
*No Spam Guaranteed. By entering your email address, you agree also subscribing to our newsletter.
Oops! - Something went wrong.
Close
Oracle Magazine for Developers Download Now
Exclusive Offer: Citrix™ Whitepaper on Denial of Service Attack Download Now