Struts 2 File Upload Example

Filed Under: Struts 2

Welcome to Struts 2 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.

Struts 2 File Upload

Struts 2 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.

Struts 2 File Upload Example

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.

Struts 2 File Upload Example

Struts 2 File Upload Configuration

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

web.xml


<?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.

pom.xml


<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.

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" "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.

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.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.

UploadFileAction.java


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.

FileUtil.java


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:

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" "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 Example 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.

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" "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>

Notice that all the file elements name are same.

UploadMultipleFileAction.java


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

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.

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" "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.

Struts 2 Multiple File Upload Request

Struts 2 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 example, you can download the complete project from below link and learn more about it.

Comments

  1. daniele says:

    Greating for post, How do i delete file insert? Existe an example do u say?

  2. Mahesh says:

    Dear Pankaj,

    I am getting following error “HTTP Status 404 – There is no Action mapped for namespace [/] and action name [UploadMultipleFile_] associated with context path [/Struts2FileUploadExample]”

    Thanks..

  3. Mahesh says:

    Dear Pankaj,

    I am getting following error “HTTP Status 404 – There is no Action mapped for namespace [/] and action name [] associated with context path [/Struts2FileUploadExample]”.

    Thanks

  4. skr says:

    hello pankaj sir,

    can u write some example on how to save image in proejct/image/ folder or image directly in database

    and which one best.

  5. Mel says:

    I need to set file size limit to upload single file size 5MB.
    see the code below.
    struts.xml

    /UploadFile.jsp

    myfiles
    /UploadFileSuccess.jsp
    /UploadFile.jsp

    5242880
    text/plain,image/jpeg

  6. Binh Thanh Nguyen says:

    Thanks, nice tips

  7. Vinay says:

    Dear Sir Please also make a tutorial about sending Email using Struts 2

  8. peter saurus says:

    As of html 5 you can use to upload multiple files

  9. Aman Verma says:

    Is there a way to display uploaded image in single file upload example….I am facing a problem as when i upload image and move it to a user defined location the uploaded image is shown as a broken link but if ido not specify upload location the image gets stored in working folder of jboss and is displayed correctly..

  10. tibi says:

    if a file is not uploaded i give an error messag, how can i set an error message for the one file which was not uploaded (in a multi file upload situation)?

    i would add a field error:
    addFieldError(“file”, getText(“error.imgRequired”, args));

    but now all file uploads get an error….

  11. rajkumar says:

    Hi Pankaj ,

    I have one Task that I want to select the files which are inside a folder.
    when I choose the folder all files inside that has to be loaded and send as an attachments to the particular email id.

    Could you help me Please!

    1. Pankaj says:

      What is so hard here? All you need is IO classes to list and read files and Email program to attach them and send it. I am sure you know how to list files and read them, for email you can get some help from https://www.journaldev.com/2532/java-program-to-send-email-using-smtp-gmail-tls-ssl-attachment-image-example

  12. Sanjay Nagare says:

    Thanks i found those files path on console.

    Thanks for your valuable example.

  13. Serge Myronyuk says:

    Dear Pankaj,

    Thank you very much for your article.

    I downloaded your sources and tried to deployed but got the following error:

    “There is no Action mapped for namespace [/] and action name [] associated with context path”

    This error was removed by inserting in struts.xml

    after

    Thanks

    1. Pankaj says:

      Can you please tell me URL you tried to access? From your error it seems you are trying to access root of application but that wont work, please check the image in post for action URLs.

      1. Serge says:

        Default URL was – http://localhost:8080/Struts2FileUploadExample/

        I imported your sources as maven project into eclipse kepler. For compiling I used jdk1.6.0_25 and tomcat 7.0.42-x64 Then Run As->Run on Server and default URL was

        1. Pankaj says:

          Thats the problem, use URL as http://localhost:8080/Struts2FileUploadExample/upload.action for single file upload and http://localhost:8080/Struts2FileUploadExample/uploadMultiple.action for multiple file uploads.

          1. Sanjay Nagare says:

            I have successfully uploaded mutiple files,but can you tell me the path where these files will locate on disk.

            Thanks Pankaj in advance…

Leave a Reply

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

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages