1. 前言
本文介绍了Springboot
应用中三种常见的文件下载场景:
- 单个文件下载:需要获取文件的大小和媒体类型,并使用
ContentDisposition
工具类构建Content-Disposition
头,避免下载文件名称乱码问题。
- 使用Gzip压缩文件:需要告诉客户端Gzip编码,并且在响应中使用
GZIPOutputStream
进行压缩。
- 一次性下载多个文件:需要把多个文件都打包到一个zip文件中,再响应给客户端,客户端可以自己解压zip文件获取多个文件
2. 单个文件下载
关键点如下:
- 获取文件大小
- 获取文件的媒体类型(Content-Type)
- 通过
ContentDisposition
工具构建Content-Disposition
头,避免下载文件名乱码
- copy数据到客户端
具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.http.ContentDisposition; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths;
@Slf4j @RestController public class DownloadController {
@GetMapping("/download") public void downloadFile(HttpServletRequest request, HttpServletResponse response) { Path file = Paths.get("/Users/xiaoyuge/Desktop/download.txt"); try { String contentType = Files.probeContentType(file); if (StringUtils.isBlank(contentType)) { contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE; } response.setContentType(contentType); response.setContentLengthLong(Files.size(file));
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.builder("attachment") .filename(file.getFileName().toString(), StandardCharsets.UTF_8).build() .toString());
Files.copy(file, response.getOutputStream()); } catch (IOException ioException) { ioException.printStackTrace(); } } }
|
3. 使用Gzip压缩文件
如果下载的文件特别大的话,可以考虑使用Gzip压缩后下载,可以减少传输字节,节省流量,但是因为使用Gzip编码会耗费额外的CPU
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.http.ContentDisposition; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipFile;
@Slf4j @RestController public class DownloadController {
@GetMapping("/gzip") public void gzip(HttpServletRequest request, HttpServletResponse response) { Path file = Paths.get("/Users/xiaoyuge/Desktop/download.txt"); try { String contentType = Files.probeContentType(file); if (StringUtils.isBlank(contentType)) { contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE; } response.setHeader(HttpHeaders.CONTENT_ENCODING, "gzip"); response.setContentType(contentType);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.builder("attachment") .filename(file.getFileName().toString(), StandardCharsets.UTF_8).build() .toString());
gzip(request, response); try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(response.getOutputStream())) { Files.copy(file, gzipOutputStream); } } catch (IOException ioException) { ioException.printStackTrace(); } } }
|
4. 一次性下载多个文件
如果需要一次性下载多个文件,那么徐亚服务器把多个文件都打包到一个zip文件中,在响应给客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Slf4j @RestController public class DownloadController {
@GetMapping("/zip") public void zip(HttpServletRequest request, HttpServletResponse response) {
List<Path> files = new ArrayList<Path>() {{ add(Paths.get("/Users/xiaoyuge/Desktop/download.txt")); add(Paths.get("/Users/xiaoyuge/Desktop/download2.txt")); }}; response.setContentType("application/zip"); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.builder("attachment") .filename("download.zip", StandardCharsets.UTF_8).build() .toString()); try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) { for (Path file : files) { try (InputStream in = Files.newInputStream(file)) { zipOutputStream.putNextEntry(new ZipEntry(file.getFileName().toString())); StreamUtils.copy(in, zipOutputStream); zipOutputStream.flush(); } } } catch (IOException ioException) { ioException.printStackTrace(); } } }
|