Single file upload example in struts 2

Introduction

File Upload is one of the common tasks of a web application and Struts 2 provides built-in feature for single file upload through FileUploadInterceptor. Interceptors are cross cutting concerns or common concerns like Logging.

FileUploadInterceptor 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 in case 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.

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-single-file-upload.

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-single-file-upload</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.

I have also specified the environment I am working on is development.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd">
    
<struts>
	<constant name="struts.devMode" value="true" />
	
	<!-- upload max file size limit -->
	<constant name="struts.multipart.maxSize" value="10485760" />
	
	<package name="default" namespace="/" extends="struts-default">
		<action name="uploadSingleFile"
			class="com.roytuts.struts.single.file.upload.SingleFileUploadAction">
			
			<param name="filePath">file</param>
			<result name="success">/index.jsp</result>
			<result name="input">/index.jsp</result>
			
			<interceptor-ref name="defaultStack">
				<param name="maximumSize">10485760</param>
				<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 uploadSingleFile 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 are enctype (multipart/form-data), file element name (file) and action (uploadSingleFile).

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!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>Struts 2 Single File Upload Example</title>
</head>
<body>
    <s:if test="hasActionErrors()">
        <s:actionerror />
    </s:if>
    <s:if test="hasActionMessages()">
        <s:actionmessage />
    </s:if>
    <s:form action="uploadSingleFile" method="post" enctype="multipart/form-data">
        <s:file label="File" name="file"></s:file>
        <s:submit value="Upload"></s:submit>
    </s:form>
</body>
</html>

Action Class

Notice that action class is implementing ServletContextAware interface that contains overridden 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.

The filePath parameter defined for uploadSingleFile action, hence we have setFilePath() method in the above class. 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 file upload and params interceptors are File, file name and content type. If the file element name in request is “f” then these variables should be – File f, String fContentType and String fFileName. Since our single.jsp file element name is “file”, we have variables file, fileFileName and fileContentType with their getters and setters.

package com.roytuts.struts.single.file.upload;

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 SingleFileUploadAction extends ActionSupport implements ServletContextAware {

	private static final long serialVersionUID = 1L;

	private File file;
	private String filePath;
	private String fileFileName;
	private String fileContentType;
	private ServletContext servletContext;

	public File getFile() {
		return file;
	}

	public void setFile(File file) {
		this.file = file;
	}

	public String getFilePath() {
		return filePath;
	}

	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}

	public String getFileFileName() {
		return fileFileName;
	}

	public void setFileFileName(String fileFileName) {
		this.fileFileName = fileFileName;
	}

	public String getFileContentType() {
		return fileContentType;
	}

	public void setFileContentType(String fileContentType) {
		this.fileContentType = fileContentType;
	}

	public ServletContext getServletContext() {
		return servletContext;
	}

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

	@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();
		}
		String targetPath = dir.getPath() + File.separator + fileFileName;
		System.out.println("targetPath: " + targetPath);
		File f = new File(targetPath);
		try {
			fileInputStream = new FileInputStream(file);
			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 successfully uploaded!");
		return SUCCESS;
	}

	@Override
	public void validate() {
		if (file == null) {
			addActionMessage("You must select a file!");
		}

	}

}

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 Single Files Upload</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-single-file-upload/ in the browser and you will see the following page as shown in the image:

struts 2 single file upload

Error message appear when you do not select file:

struts 2 single file upload

When file successfully uploaded:

struts 2 single file upload

Now file is successfully uploaded to the location: .metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\struts2-file-upload\

struts 2 single file upload

Hope you got an idea how to upload single file in Struts 2.

Source Code

Download

Thanks for reading.

Leave a Reply

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