Upload multiple files using single browse button in Struts2

This tutorial shows how to upload multiple files using single browse button in Struts 2 framework. There is another tutorial on Multiple Files Upload in Struts2 which uses multiple browse buttons for multiple file upload but this tutorial uses only one button for uploading multiple file upload in Struts2. You need to use just attribute multiple="multiple" with <s:file/> tag for uploading multiple files using the single browse button.

I won’t explain much details in this tutorial but if you need more explaination then you can go through another tutorial Multiple Files Upload in Struts2.

Prerequisites

Java at least 8, Struts 2.5, commons-fileupload, commons-io, Java Servlet, Gradle 6.5.1, Maven 3.6.3, Tomcat Server 9.0.24

Project Setup

You can create gradle or maven based project in your favorite IDE. The name of the project is struts-2-multiple-files-upload-single-browse-button.

You can use build.gradle script for your gradle based project:

plugins {
	id 'war'
    id 'java-library'
}

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenCentral()
}

dependencies {
	implementation("org.apache.struts:struts2-core:2.5.22")
	implementation 'javax.servlet:javax.servlet-api:4.0.1'
	implementation 'commons-fileupload:commons-fileupload:1.4'
	implementation 'commons-io:commons-io:2.7'
	implementation 'org.apache.logging.log4j:log4j-core:2.13.3'
	implementation 'org.apache.logging.log4j:log4j-api:2.13.3'
}

You can use below pom.xml file for your maven based project:

<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>com.roytuts</groupId>
	<artifactId>struts-2-multiple-files-upload-single-browse-button</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>at least 1.8</java.version>
	</properties>
	
	<dependencies>		
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-core</artifactId>
			<version>2.5.22</version>
		</dependency>
		
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>4.0.1</version>
		</dependency>
		
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.4</version>
		</dependency>
		
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.7</version>
		</dependency>
		
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.13.3</version>
		</dependency>
		
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
			<version>2.13.3</version>
		</dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
                <configuration>
					<source>${java.version}</source>
					<target>${java.version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Struts Configuration

You need to tie the action class, view and URL together in this configuration file. The configuration file name is struts.xml and kept under src/main/resources folder.

The mapping tells the Struts 2 framework which class will respond to the user’s action (the URL), which method of that class will be executed, and what view to render based on the String result that method returns.

<?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.5.dtd">
<struts>
	<!-- upload max file size limit -->
	<constant name="struts.multipart.maxSize" value="10485760" />

	<package name="default" namespace="/" extends="struts-default">
		<!-- file upload action -->
		<action name="uploadMultipleFile"
			class="com.roytuts.struts.multiple.files.upload.single.browse.button.MultipleFileUploadAction">
			<!-- redirect to input page for file upload again -->
			<result name="success">/index.jsp</result>
			<!-- input page for file upload -->
			<result name="input">/index.jsp</result>
			<interceptor-ref name="defaultStack">
				<param name="maximumSize">10485760</param>
				<!-- what type of files are allowed to be uploaded -->
				<param name="allowedTypes">text/plain,image/jpeg,image/png,image/gif,image/pjpeg</param>
			</interceptor-ref>
		</action>
	</package>
</struts>

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

FileUploadInterceptor default limit for single file size is 2 MB, so I am overriding it for uploadMultipleFiles action. I am using defaultStack with params maximumSize (10MB) and allowedTypes (text/plain,image/jpeg,image/png,image/gif,image/pjpeg) for fileUpload interceptor.

View File

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

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ 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=ISO-8859-1">
<title>Multiple Files Upload Example using Single Browse button -
	Struts2</title>
</head>
<body>
	<!-- show error message only when error occurrs -->
	<s:if test="hasActionErrors()">
		<s:actionerror />
	</s:if>
	
	<!-- show success message only when file successfully uploads -->
	<s:if test="hasActionMessages()">
		<s:actionmessage />
	</s:if>
	
	<s:form action="uploadMultipleFile" method="post"
		enctype="multipart/form-data">
		<!-- input type file for file upload, make sure to set multiple="multiple" for multiple uploads -->
		<s:file label="File" name="files" multiple="multiple"></s:file>
		<s:submit value="Upload Files"></s:submit>
	</s:form>
</body>
</html>

Action Class

Create Controller or Action file MultipleFileUploadAction.java with the following source code.

package com.roytuts.struts.multiple.files.upload.single.browse.button;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import javax.servlet.ServletContext;

import org.apache.struts2.util.ServletContextAware;

import com.opensymphony.xwork2.ActionSupport;

public class MultipleFileUploadAction extends ActionSupport implements ServletContextAware {

	private static final long serialVersionUID = 5109187855480607759L;
	// input type file name - files
	private File[] files;
	// all uploaded file names
	private String[] filesFileName;
	// all uploaded files content type
	private String[] filesContentType;
	// servletcontext for getting the context
	private ServletContext servletContext;

	public File[] getFiles() {
		return files;
	}

	public void setFiles(File[] files) {
		this.files = files;
	}

	public String[] getFilesFileName() {
		return filesFileName;
	}

	public void setFilesFileName(String[] filesFileName) {
		this.filesFileName = filesFileName;
	}

	public String[] getFilesContentType() {
		return filesContentType;
	}

	public void setFilesContentType(String[] filesContentType) {
		this.filesContentType = filesContentType;
	}

	public ServletContext getServletContext() {
		return servletContext;
	}

	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	@Override
	public void validate() {
		// check whether at least one file was selected for upload
		if (null == files) {
			addActionMessage("You must select at least one file!");
		}
	}

	@Override
	public String execute() throws Exception {
		FileInputStream fileInputStream = null;
		FileOutputStream fileOutputStream = null;
		File dir = new File(servletContext.getRealPath(""));
		System.out.println("servletContext.getRealPath(\"\"): " + servletContext.getRealPath(""));
		if (!dir.exists()) {
			dir.mkdirs();
		}
		try {
			for (int i = 0; i < files.length; i++) {
				String targetPath = dir.getPath() + File.separator + filesFileName[i];
				System.out.println("targetPath: " + targetPath);
				File f = new File(targetPath);
				fileInputStream = new FileInputStream(files[i]);
				fileOutputStream = new FileOutputStream(f);
				int c;
				while ((c = fileInputStream.read()) != -1) {
					fileOutputStream.write(c);
				}
			}
		} catch (Exception e) {
			addActionError("Error occurred during uploading the file!");
			return INPUT;
		} finally {
			if (fileInputStream != null) {
				fileInputStream.close();
			}
			if (fileOutputStream != null) {
				fileOutputStream.close();
			}
		}

		addActionMessage("File(s) successfully uploaded!");

		return SUCCESS;
	}

}

Deployment Descriptor – web.xml

The web app configuration file which is the entry point for any web app.

<?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>Struts2 Multiple Files Upload using single browse button</display-name>
	
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

Testing Application

Now you can deploy your application into Tomcat server and hit the URL http://localhost:8080/struts-2-multiple-files-upload/ in the browser and you will see the following page as shown in the image:

struts 2 multiple files upload using single browse button

On successful files upload, you will see below message:

struts 2 multiple files upload using single browse button

Source Code

Download

Thanks for reading.

Leave a Reply

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