Struts2 Upload File Example

Introduction to Struts2 File Upload

Struts2 has built in features for uploading a file to a server using multipart servlet request (known as form based file upload defined in RFC 1867). Struts2 provides a specific interceptor (file upload interceptor) for handling file uploads. This interceptor will provide an instance of the uploaded File object to a configured Struts2 action class. File upload interceptor is part of the core Struts2 library and hence you don’t need any additional plugins for simple file upload. In this article, I will provide a step by step example of implementing file upload in Struts2.

Pre-requisites for Struts2 File Upload Sample Application

The following example assumes that you have the IDE and a sample Struts2 application already setup. Please see this article for setting up a sample Struts2 application using NetBeans and Tomcat.

Struts2 File Upload Example Application Explained

The following sample application will demonstrate how file uploads can be implemented using built-in features of Struts2. Struts2 internally uses apache commons libraries (file upload and io) for implementing the low level aspects of file upload and hence you need to have these libraries as part of your Struts2 application.

The following application provides a file upload form using which you can upload a local file to the server. Struts2 internally stores this file as a temporary file and we will copy this file into another file for further processing. Finally the application will show the details of the uploaded file including its name and the size of the file. The application also demonstrates various configuration options for the file upload and also how to handle various error messages generated by the file upload component.

Struts2 File Upload example application has the following components,

  • uploadform.jsp – A screen for selecting and uploading a file
  • ShowUploadForm.java – A Struts2 action for displaying the file upload screen
  • UploadMyFile.java – Another Struts2 action class for processing the uploaded file and writing it into server’s file system
  • uploadresults.jsp – A screen which will display the details of the file just uploaded
  • web.xml – Web application deployment descriptor where Struts2 framework is configured
  • struts.xml – Struts configuration file where action class to URL mapping and view mapping is defined
  • global.properties – i18n message resource file for overriding default error messages generated by file upload

 

File Upload Input Form (uploadform.jsp)

Let us first create a JSP file for upload file selection. Create a new JSP file fileupload.jsp file in the Web Pages folder of your NetBeans project. Replace the content of the JSP with the following,

<%@taglib prefix="s" uri="/struts-tags" %>
<html>
    <head><title>Struts2 File Upload Example</title></head>
    <body>
        <s:actionerror/>
        <s:fielderror/>
        <s:form action="UploadMyFile" enctype="multipart/form-data" method="POST">
            <s:file name="uploadFile" label="Please select a file to upload"></s:file>
            <s:submit></s:submit>
        </s:form>
    </body>
</html>

To create an upload form, Struts2 provides a custom tag <s:file>. This tag requires a label for the upload file field and a name which we will be using in the action class for processing the file. In order to upload a file, the servlet specification requires that the encoding of the form is of multipart type. This can be specified in the enctype attribute of the custom tag <s:form>. The action attribute of the <s:form> specifies the name of the action class to be invoked (UploadMyFile) when user submits this page.

Also note the use of custom tags <s:actionerrors/> and <s:fielderror/>. These can be used to display field specific or action specific error messages. All the interceptor level validations (maximumSize) generate both action errors and field errors. However global validations such as the size validation (struts.multipart.maxSize) only generates action errors. See the error message section below for more details.

Controller to Display File Upload Input Form (ShowUploadForm.java)

package org.struts2.samples.upload;

import com.opensymphony.xwork2.ActionSupport;

public class ShowUploadForm extends ActionSupport{

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }
}

This action class (defined under the package org.struts2.samples.upload) simply returns a value of SUCCESS which is mapped to fileupload.jsp in struts.xml. This is the first action class invoked in the application and the URL used in the sample application in NetBeans is – http://localhost:8084/Struts2FileUpload/upload/ShowUploadForm.action

Controller to Process Uploaded File and Display Upload Details Page (UploadMyFile.java)

Define the class UploadMyFile in package org.struts2.samples.upload.

package org.struts2.samples.upload;

import com.opensymphony.xwork2.ActionSupport;
import java.io.File;
import org.apache.commons.io.FileUtils;

public class UploadMyFile extends ActionSupport{

    private File uploadFile;
    private String uploadFileFileName;
    private long fileSize;

    public long getFileSize() {
        return fileSize;
    }

    public void setFileSize(long fileSize) {
        this.fileSize = fileSize;
    }

    public String getUploadFileFileName() {
        return uploadFileFileName;
    }

    public void setUploadFileFileName(String uploadFileFileName) {
        this.uploadFileFileName = uploadFileFileName;
    }

    public File getUploadFile() {
        return uploadFile;
    }

    public void setUploadFile(File uploadFile) {
        this.uploadFile = uploadFile;
    }

    @Override
    public String execute() throws Exception {
        this.fileSize = uploadFile.length();
        // write file to local file system or to database as blob
        String filePath = "c:/temp/testfile99";
        File newFile = new File(filePath);
        FileUtils.copyFile(uploadFile, newFile);
        return SUCCESS;
    }

}

Struts2 interceptor injects a file object into the class variable uploadFile using the setter method setUploadFile(). Note that the name of the field in fileupload.jsp, uploadFile is used to find the setter in the action class. Struts2 interceptor can automatically invoke the following methods (where X stands for the name of the "file" field in the JSP),

  • setX(File file) – The file object containing the uploaded file contents
  • setXContentType(String contentType) – The mime type of the uploaded file
  • setXFileName(String fileName) – The actual name of the file uploaded

In our example, we have defined setUploadFileFileName() and this will automatically set the file name in the action class. We will be using this to display the file name in the results JSP.

In the execute() method, we also find the size of the file and set it to another instance variable. We also create a permanent copy of the uploaded temporary file. Finally we forward to the results page by returning SUCCESS value.

Display Upload Details (uploadresults.jsp)


<%@taglib prefix="s" uri="/struts-tags" %>
<html>
    <head><title>Struts2 File Upload Example</title></head>
    <body>
        <h1>The uploaded file name is :<s:property value="uploadFileFileName"/>
            and the size of the file is : <s:property value="fileSize"/> bytes</h1>
    </body>
</html>

We use the custom tag <s:property> to display the file name and size.

Configure Struts2 in Web Application (web.xml)

<?xml version="1.0" encoding="UTF-8"?>

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

We configure Struts2 filter for initializing the Struts2 framework.

Connect Everything Together (struts.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
        <constant name="struts.custom.i18n.resources" value="global" />
        <constant name="struts.multipart.saveDir" value="c:/temp" />
        <constant name="struts.multipart.maxSize" value="2000000" />
	<package name="upload" extends="struts-default">
		<action name="ShowUploadForm" class="org.struts2.samples.upload.ShowUploadForm">
			<result name="success">/uploadform.jsp</result>
		</action>
		<action name="UploadMyFile" class="org.struts2.samples.upload.UploadMyFile">
                        <interceptor-ref name="defaultStack">
                            <param name="fileUpload.allowedTypes">text/plain</param>
                            <param name="fileUpload.maximumSize">50000</param>
                        </interceptor-ref>
                        <result name="input">/uploadform.jsp</result>
			<result name="success">/uploadresults.jsp</result>
		</action>
	</package>
</struts>

First we define a number of constant configuration attributes,

  • struts.custom.i18n.resources defines a custom global i18n resources file (global.properties)
  • struts.multipart.saveDir overrides the temporary file location for file upload
  • struts.multipart.maxSize sets a global limit for the maximum size of the file upload. This only generates action errors and the message cannot be overridden using the property struts.messages.error.file.too.large.

Now we do the standard wiring of action classes and view files. In the case of UploadMyFile, we also define a result with name "input". This view will be invoked when errors are encountered by Struts2. In our case we take user back to the upload form and display all the action errors and field errors using custom tags.

In the case of UploadMyFile, we also override the default parameters for file upload through file upload interceptor configuration. Since our package upload extends struts-default, defaultStack is already configured. We override the defaultStack with a customized defaultStack which modifies parameters for file upload interceptor. We limit the file uploads to simple text files which are less than 50kb in size.

Override Default Error Messages (global.properties)

struts.messages.error.file.too.large=File is too large

We override the i18n property struts.messages.error.file.too.large to display a custom message when the size of the file exceeds what is specified in the maximumSize parameter to the file upload interceptor. Note that global.properties is defined as a custom global resource file in struts.xml shown above.

Configuring File Upload Behavior in Struts2

In Struts2, constant configuration values can be specified in struts.xml, web.xml or in struts.properties. The struts.properties are no longer recommended and it is retained only for backward-compatibility with WebWork. You can either configure the following values in struts.xml as <constant> tag or as <init-param> in the filter configuration in web.xml.

By default the temporary files generated during file upload is stored in a location specified by the javax.servlet.context.tempdir. In some systems where this may be pointed to a memory location and you may want to change it. The location of the temporary file can be changed by providing a value for the constant struts.multipart.saveDir.

It is also possible to set a maximum size of the file being uploaded across all upload forms in an application. This is basically configured to prevent people from uploading extremely large files and there by crashing the system. The maximum size of the file in bytes can be set using the constant struts.multipart.maxSize. It is also possible to set size limit for a specific upload action by providing the maximumSize parameter to the file upload interceptor.

It is also possible to have a custom multipart parser by overriding the struts.multipart.parser property. The default parser is jakarta and some of the other parsers available are pell and cos. These parsers require additional libraries.

Following examples show how upload properties can be configured in struts.xml or web.xml,

<struts>
        <constant name="struts.multipart.saveDir" value="c:/temp" />
        <constant name="struts.multipart.maxSize" value="2000000" />
        ....
</struts>
<filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
        <init-param>
        	<param-name>struts.multipart.maxSize</param-name>
        	<param-value>20000</param-value>
        </init-param>
</filter>

It is also possible to apply the above attributes selectively to a specific upload action. This can be achieved by customizing the parameters passed to the file upload interceptor. The parameters supported are allowedTypes and maximumSize. The parameter allowedTypes specifies a list of comma separated content types which can be uploaded.

The allowed content types can also be controlled programmatically by looking at the content type made available via setXContentType() defined on the action class (see UploadMyFile.java).

Handling Error Messages

Struts2 defines two types of errors – field errors and action errors. Action errors are errors which are not specific to a field. Field errors are generated per field. Use the tag <s:actionerrors/> to display all the action errors in a bulleted list of non field specific errors. Use the tag <s:fielderror/> with value parameter to display errors for a specific field.

The file upload in Struts2 can generate action errors and field errors. If the errors are generated due to global constants such as struts.multipart.maxSize , Struts2 only populates action errors. But if errors are generated due to the configuration passed to the interceptor (maximumSize), both field errors and action errors are generated.

You can customize the error message displayed by customizing the following i18n message keys,

  • struts.messages.error.uploading – A general error that occurs when the file could not be uploaded
  • struts.messages.error.file.too.large -  Occurs when the uploaded file is too large as specified by maximumSize.
  • struts.messages.error.content.type.not.allowed   -  Occurs when the uploaded file does not match the expected content types specified

To override these keys, create a property file containing these keys in the folder where struts.xml is stored. Specify this file as the custom global message resource file by setting the struts.custom.i18n.resources constant in struts.xml.

Download Struts2 File Upload Example

Click here to download the complete Struts2 file upload sample project in NetBeans. Please note that to keep the download size small, Struts2 libraries are excluded from the zip file. You need to add them before you can run the sample application.

Click here to get latest site updates delivered to your email. You also need to click on the link sent to your email from feedburner to confirm your subscription.


October 26, 2011 | Posted in Tutorials No Comments »

Leave a Comment