文件下载
本文旨在详细说明如何在 Java 后端应用程序中实现 PDF 和 DOCX 文件的下载功能,结合 tio-boot
框架和 hutool
工具库。
环境依赖
在开始之前,请确保您的项目已添加以下依赖:
- hutool-core:提供丰富的工具类,例如资源访问工具。
- tio-boot:作为网络框架处理 HTTP 请求和响应。
- ZXing(用于二维码生成):用于生成二维码图片。
Maven 依赖示例
<dependencies>
<!-- Hutool 核心库 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.11</version>
</dependency>
<!-- Tio-Boot 框架 -->
<dependency>
<groupId>com.litongjava</groupId>
<artifactId>tio-boot</artifactId>
<version>最新版本</version>
</dependency>
<!-- ZXing 核心库(用于二维码生成) -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
实现文件下载功能
返回字节数据
下载 PDF 文件
实现步骤
- 定义请求路径:使用
@RequestPath("/download/pdf/{id}")
注解标注方法,定义处理 PDF 文件下载的请求路径。 - 读取文件:使用
ResourceUtil.getStream("pdf/" + id + ".pdf")
根据文件 ID 动态获取 PDF 文件的输入流。 - 发送响应:将 PDF 文件内容以字节形式发送给客户端,并设置
Content-Type
为application/pdf; charset=utf-8
。
示例代码
@RequestPath("/download/pdf/{id}")
public HttpResponse downloadPdf(String id, HttpRequest request) {
log.info("id:{}", id);
InputStream inputStream = ResourceUtil.getStream("pdf/" + id + ".pdf");
int available;
try {
available = inputStream.available();
byte[] fileBytes = new byte[available];
inputStream.read(fileBytes, 0, available);
HttpResponse response = Resps.bytesWithContentType(request, fileBytes, "application/pdf; charset=utf-8");
return response;
} catch (IOException e) {
e.printStackTrace();
return Resps.json(request, RespBodyVo.fail("Error generating captcha"));
}
}
下载 DOCX 文件
实现步骤
- 定义请求路径:使用
@RequestPath("/download/docx/{id}")
注解标注方法,定义处理 DOCX 文件下载的请求路径。 - 读取文件:使用
ResourceUtil.getStream(id+".docx")
根据文件 ID 动态获取 DOCX 文件的输入流。 - 发送响应:将 DOCX 文件内容以字节形式发送给客户端,并设置
Content-Type
为application/vnd.openxmlformats-officedocument.wordprocessingml.document; charset=utf-8
。
示例代码
@RequestPath("/download/docx/{id}")
public HttpResponse download(String id, HttpRequest request) {
InputStream inputStream = ResourceUtil.getStream(id+".docx");
int available;
try {
available = inputStream.available();
byte[] fileBytes = new byte[available];
inputStream.read(fileBytes, 0, available);
String contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document; charset=utf-8";
HttpResponse response = Resps.bytesWithContentType(request, fileBytes, contentType);
return response;
} catch (IOException e) {
e.printStackTrace();
return Resps.json(request, RespBodyVo.fail("Error generating captcha"));
}
}
通过浏览器触发文件下载
实现步骤
- 定义请求路径:创建一个控制器方法,处理文件下载请求。
- 设置响应头:设置
Content-Type
和Content-Disposition
以指示浏览器下载文件。 - 发送文件内容:将文件内容以字节形式发送给客户端。
示例代码
package com.litongjava.tio.web.hello.controller;
import com.litongjava.tio.boot.http.TioRequestContext;
import com.litongjava.tio.http.common.HttpResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class DocumentController {
public HttpResponse export(Long documentId) {
String downloadFilename = "my.md";
log.info("filename:{}", downloadFilename);
String contentType = "text/markdown; charset=utf-8";
HttpResponse httpResponse = TioRequestContext.getResponse();
httpResponse.setContentType(contentType);
httpResponse.setHeader("Content-Disposition", "attachment; filename=\"" + downloadFilename + "\"");
httpResponse.setString("Hi");
return httpResponse;
}
}
原理解析
浏览器触发文件下载的原理主要依赖于 HTTP 响应头的配置,尤其是 Content-Type
和 Content-Disposition
。以下是具体原理解析:
Content-Type:
- 指定返回内容的 MIME 类型,告知浏览器内容的格式。
- 例如,
application/pdf
表示 PDF 文件,application/vnd.openxmlformats-officedocument.wordprocessingml.document
表示 DOCX 文件,image/png
表示 PNG 图片等。
Content-Disposition:
- 控制内容的显示方式。
attachment
表示内容应作为附件下载,而不是直接在浏览器中显示。filename
参数指定下载文件的默认名称。
响应内容:
- 通过将文件内容作为字节流写入响应体,浏览器接收到响应后会根据
Content-Disposition
头信息提示用户下载文件。
- 通过将文件内容作为字节流写入响应体,浏览器接收到响应后会根据
详细步骤:
- 客户端请求:用户通过浏览器访问特定的下载 URL(例如
/download/pdf/123
)。 - 服务器处理:
- 服务器接收到请求后,读取对应的文件(如 PDF 文件)。
- 设置响应头:
Content-Type
:指定文件类型(例如application/pdf
)。Content-Disposition
:设置为attachment; filename="文件名.pdf"
,指示浏览器下载文件并使用指定名称。
- 将文件内容以字节流写入响应体。
- 浏览器响应:
- 根据响应头,浏览器识别出需要下载文件,并弹出下载对话框,提示用户保存文件。
示例流程:
- 用户访问
http://localhost/download/document/123
。 - 服务器读取
document_123.md
文件内容。 - 设置响应头:
Content-Type: text/markdown; charset=utf-8
Content-Disposition: attachment; filename="document_123.md"
- 将文件内容写入响应体。
- 浏览器收到响应后,提示用户下载
document_123.md
文件。
注意事项:
- 确保文件路径和命名方式符合实际项目需求。
- 对于大文件,考虑使用流式传输以避免内存占用过高。
- 处理异常情况,如文件不存在或读取失败,返回合适的错误响应。
结论
通过上述实现,您可以在 Java Web 应用中方便地添加文件下载功能,支持多种文件格式,如 PDF、DOCX、图片(验证码和二维码)等。关键在于正确设置 HTTP 响应头和处理文件的字节流传输。请根据实际项目需求调整文件路径和命名方式,确保下载功能的稳定性和安全性。