<result name="success" type="stream"> <param name="contentType">application/octet-stream</param> <param name="inputName">inputStream</param> <param name="contentDisposition">attachment;filename="project.zip"</param> <param name="bufferSize">4096</param> </result>As we can see, unlike regular result types which map view names to JSP pages, this stream result type needs some parameters to control the file download. The following table lists all the available parameters:
Parameter name | Meaning | Default value |
contentType | Sets content MIME type for the response header. | text/plain |
contentLength | Sets content length for the response header. | |
contentDisposition | Sets content disposition for the response header. | inline |
inputName | Specifies name of the InputStream which must be defined in the action class. | inputStream |
bufferSize | Specifies size of the buffer (in bytes) used for copying data from input stream to output stream. | 1024 |
allowCaching | Enables or disables caching (by setting “Pragma” and “Cache-Control” attribute of the response header. | true |
contentCharSet | Specifies character set for the content by adding “;charset=value” to the Content-Type header. |
public class DownloadFileAction extends ActionSupport { private InputStream inputStream; // getter for the inputStream private long contentLength; public long getContentLength() { return contentLength; } public String execute() throws FileNotFoundException { File fileToDownload = new File("C:/path/to/the/file.zip"); inputStream = new FileInputStream(fileToDownload); contentLength = fileToDownload.length(); return SUCCESS; } }Remember that, in the action class we must define an InputStreamobject which has the same name as the name specified by the inputName parameter. All the variables must have appropriate getter methods.Similarly, the file name specified in the contentDisposition parameter should be also dynamic. To do so, declare this parameter as follows:
<param name="contentDisposition">attachment;filename="${fileName}"</param>
public class DownloadFileAction extends ActionSupport { // input stream object and its getter method private String fileName; public String getFileName() { return fileName; } public String execute() throws FileNotFoundException { File fileToDownload = new File("C:/path/to/the/file.zip"); fileName = fileToDownload.getName(); return SUCCESS; } }Okay, that’s enough for the configuration of stream result type. Let’s see a complete sample application now.The application consists of the following files:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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=UTF-8"> <title>Download File</title> </head> <body> <h1 align="center">Struts2 File Download Demo</h1> <h3 align="center"> <a href="/downloadFile">Download this file</a> </h3> </body> </html>This page has a hyperlink that points to relative URL of the Struts action.
package net.codejava.struts; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import com.opensymphony.xwork2.ActionSupport; public class DownloadFileAction extends ActionSupport { private InputStream inputStream; private String fileName; private long contentLength; public String execute() throws FileNotFoundException { File fileToDownload = new File("E:/Download/struts-2.3.12-src.zip"); inputStream = new FileInputStream(fileToDownload); fileName = fileToDownload.getName(); contentLength = fileToDownload.length(); return SUCCESS; } public long getContentLength() { return contentLength; } public String getFileName() { return fileName; } public InputStream getInputStream() { return inputStream; } }The execute() method of this action class picks a file from an absolute path and put it into the input stream. The file name and content length (file size) are also set accordingly.
<?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> <package name="Struts2FileDownload" extends="struts-default"> <action name="downloadFile" class="net.codejava.struts.DownloadFileAction"> <result name="success" type="stream"> <param name="contentType">application/octet-stream</param> <param name="inputName">inputStream</param> <param name="contentDisposition">attachment;filename="${fileName}"</param> <param name="bufferSize">4096</param> </result> </action> </package> </struts>Note that in this configuration we fix the contentTypeto application/octet-stream which means binary type. In your application, you may override this parameter in the action class to return content type that exactly matches your file type.
<?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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 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>Struts2FileDownload</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>
http://localhost:8080/Struts2FileDownload/Download.jsp
The download page would appear as follows:Click on the link “Download this file”, the browser will automatically download the file, or ask for download (Firefox):Depending on the value you set for the contentType parameter, the browser behaves differently. For example, if the contentType is set to image/jpeg then the browser will display the image.You can download an Eclipse-based project of this application in the attachments section.