核心概念:stream 结果类型
Struts2 的 stream 结果类型会将 Action 中某个属性(通常是 InputStream)的值直接写入到 HttpServletResponse 的输出流中,从而将文件发送给客户端。

它的主要配置参数有:
| 参数 | 必需 | 描述 |
|---|---|---|
contentType |
否 | 文件的 MIME 类型,application/pdf, image/jpeg,浏览器会根据此类型决定如何处理文件(如内联显示或下载)。 |
contentLength |
否 | 文件的大小(字节),这有助于浏览器显示下载进度条。 |
contentDisposition |
否 | 控制文件是内联显示还是作为附件下载。这是实现下载的关键,通常设置为 attachment; filename="文件名"。 |
inputName |
是 | 指定 Action 中哪个属性作为 InputStream 的来源,默认值是 inputStream。 |
bufferSize |
否 | 读写缓冲区大小,默认为 1024 字节。 |
完整示例:实现文件下载
假设我们要实现一个下载服务器上文件的页面。
步骤 1:准备工作
- 创建 Web 项目:确保你的项目已经集成了 Struts2,如果你不确定,可以检查
web.xml中是否有 Struts2 的Filter配置。 - 准备下载文件:在你的 Web 项目中,创建一个目录来存放需要下载的文件,在
WebContent(或webapp) 目录下创建一个files文件夹,并放入一个名为test.txt的文件。- 项目结构大致如下:
your-project/ ├── src/ │ └── com/ │ └── example/ │ └── action/ │ └── DownloadAction.java ├── WebContent/ │ ├── files/ │ │ └── test.txt <-- 这是我们要下载的文件 │ ├── index.jsp <-- 下载页面 │ └── struts.xml <-- Struts2 核心配置文件 └── WEB-INF/ └── web.xml
- 项目结构大致如下:
步骤 2:创建 Action 类
Action 类的核心任务是提供文件的 InputStream,我们可以通过多种方式获取这个流,这里演示最常见的方式:从服务器的文件系统读取。
src/com/example/action/DownloadAction.java

package com.example.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class DownloadAction extends ActionSupport {
// 1. 定义一个 InputStream 属性,用于存放文件流
// Struts2 的 stream 结果类型会默认读取名为 "inputStream" 的属性
private InputStream inputStream;
// 2. 定义文件名,用于在下载对话框中显示
private String fileName;
// Struts2 会自动调用这个方法来获取输入流
// 你也可以不实现这个方法,而是在 execute 中直接给 inputStream 赋值
public InputStream getInputStream() throws Exception {
// 获取要下载的文件在服务器上的真实路径
String filePath = ServletActionContext.getServletContext().getRealPath("/files/test.txt");
// 设置下载时显示的文件名(可以和原文件名不同)
// 注意:处理中文文件名,防止乱码
fileName = "下载的测试文件.txt";
// 创建 FileInputStream 对象
inputStream = new FileInputStream(new File(filePath));
return inputStream;
}
// 可选:提供一个 getter 方法,以便在 JSP 中获取文件名
// 这样可以在 JSP 中动态设置 content-disposition
public String getFileName() {
return fileName;
}
// 在 Action 执行完毕后,确保流被关闭
@Override
public String execute() throws Exception {
// getInputStream() 方法会在 stream 结果类型处理时被调用
// 所以这里我们只需要返回 SUCCESS
return SUCCESS;
}
// 确保在 Action 销毁时关闭流
@Override
public void destroy() {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
步骤 3:配置 struts.xml
这是最关键的一步,我们需要告诉 Struts2 当返回 SUCCESS 时,使用 stream 结果类型来处理。
WebContent/struts.xml
<?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>
<package name="default" namespace="/" extends="struts-default">
<!-- 定义下载 Action -->
<action name="download" class="com.example.action.DownloadAction">
<!--
指定当 execute() 方法返回 "SUCCESS" 时,使用 stream 结果类型
-->
<result name="success" type="stream">
<!--
指定 Action 中哪个属性是输入流。
默认就是 "inputStream",所以这里可以省略。
-->
<param name="inputName">inputStream</param>
<!--
设置文件的内容类型。
对于文本文件,通常是 text/plain。
对于 PDF,是 application/pdf。
对于图片,是 image/jpeg 等。
如果不确定,可以使用 application/octet-stream (通用二进制流)。
-->
<param name="contentType">text/plain</param>
<!--
设置下载时的文件名。
这里我们通过 EL 表达式从 Action 的 getFileName() 方法获取。
注意:这里使用了 OGNL 表达式 ${fileName}。
-->
<param name="contentDisposition">attachment; filename="${fileName}"</param>
<!--
设置缓冲区大小,可选。
-->
<param name="bufferSize">1024</param>
</result>
</action>
</package>
</struts>
步骤 4:创建下载页面
创建一个简单的 JSP 页面,上面放置一个下载链接。
WebContent/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">Struts2 文件下载示例</title>
</head>
<body>
<h2>Struts2 文件下载</h2>
<p>点击下面的链接下载文件:</p>
<!--
s:url 标签用于生成 Action 的 URL。
s:a 标签用于生成一个超链接。
-->
<s:url var="downloadUrl" action="download"/>
<s:a href="%{downloadUrl}">下载 test.txt 文件</s:a>
</body>
</html>
步骤 5:部署和测试
- 将项目部署到 Tomcat 或其他 Servlet 容器中。
- 启动服务器,访问
http://localhost:8080/your-project-name/index.jsp。 - 点击 "下载 test.txt 文件" 链接。
- 浏览器应该会弹出文件下载对话框,提示你保存名为 "下载的测试文件.txt" 的文件。
高级主题与常见问题
处理中文文件名乱码
不同浏览器处理中文文件名的方式不同,直接设置 filename="中文.txt" 可能会出现乱码,我们需要在 Action 中根据请求的 User-Agent 来进行编码。
修改 DownloadAction 中的 getFileName() 方法:
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.interceptor.ServletRequestAware; // 实现 Aware 接口
public class DownloadAction extends ActionSupport implements ServletRequestAware {
// ... 其他代码 ...
private HttpServletRequest request;
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public String getFileName() throws Exception {
String originalFileName = "测试文件.txt";
// 获取请求头中的 User-Agent
String userAgent = request.getHeader("USER-AGENT");
// 对文件名进行编码
if (userAgent != null) {
userAgent = userAgent.toLowerCase();
if (userAgent.contains("msie") || userAgent.contains("trident")) { // IE
fileName = java.net.URLEncoder.encode(originalFileName, "UTF-8");
} else if (userAgent.contains("mozilla")) { // Firefox, Chrome
fileName = new String(originalFileName.getBytes("UTF-8"), "ISO-8859-1");
} else { // 其他
fileName = java.net.URLEncoder.encode(originalFileName, "UTF-8");
}
}
return fileName;
}
// ... 其他代码 ...
}
下载动态生成的文件
如果你需要下载的不是服务器上已存在的文件,而是动态生成的(如报表、图片等),流程类似,只是获取 InputStream 的方式不同。
生成一个 CSV 文件:
import java.io.ByteArrayInputStream;
public class DynamicDownloadAction extends ActionSupport {
private InputStream inputStream;
@Override
public String execute() throws Exception {
// 动态生成文件内容
String csvContent = "姓名,年龄\n张三,25\n李四,30";
// 将字符串转换为 InputStream
inputStream = new ByteArrayInputStream(csvContent.getBytes("UTF-8"));
// 设置文件名
fileName = "用户列表.csv";
return SUCCESS;
}
// ... getter 和 setter ...
}
下载大文件时的内存问题
对于非常大的文件,使用 FileInputStream 是没有问题的,因为它使用了操作系统的文件映射机制,不会一次性将整个文件读入内存,但如果你的文件内容是动态生成在内存中的(如上面的 ByteArrayInputStream),并且文件很大,这可能会导致 OutOfMemoryError。
对于大文件,最佳实践是将其先写入到服务器的临时文件中,然后提供一个 FileInputStream 来读取它,下载完成后,记得删除这个临时文件。
实现 Struts2 文件下载的核心三要素:
- Action:提供一个
InputStream类型的属性,并为其提供 getter 方法,getter 方法负责打开文件流。 struts.xml:配置 Action 的result为stream类型,并设置inputName、contentType和contentDisposition等参数。- JSP:使用
<s:url>和<s:a>标签创建一个指向 Action 的下载链接。
通过以上步骤,你就可以轻松地在 Struts2 应用中实现稳定、可靠的文件下载功能。
