支持文件單個下載,也支持文件夾打包下載。
package com.xxx.logs.console.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.LinkedList; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @RestController @RequestMapping("/logs/system") public class LogsSystemController extends BaseController { @GetMapping("/download") public void download(HttpServletResponse response, @RequestParam("path") String path) throws Exception { // 轉為path Path folderPath = Paths.get(path); // 響應為二進制數據流 response.setContentType("application/octet-stream"); if (!Files.isDirectory(folderPath)) { // 文件下載 File file = new File(path); if (!file.exists()) { LOGGER.error("file not exists: " + path); throw new IOException("file not exists: " + path); } try (InputStream input = new FileInputStream(file); OutputStream output = response.getOutputStream()) { // 寫入數據 int len; // 設置10kb緩沖區 byte[] buffer = new byte[1024 * 10]; // 文件設置,附件的形式打開 response.setHeader("content-disposition", "attachment; filename=" + file.getName()); while ((len = input.read(buffer)) > 0) { output.write(buffer, 0, len); } output.flush(); } catch (IOException e) { LOGGER.error(e.getMessage(), e); throw new RuntimeException(e); } } else { // 文件夾下載 // 文件設置,附件形式打開 response.setHeader("content-disposition", "attachment; filename=" + new String((folderPath.getFileName().toString() + ".zip").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) { // 文件路徑/ID LinkedList<String> filePath = new LinkedList<>(); Files.walkFileTree(folderPath, new FileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { // 開始遍歷目錄 if (!dir.equals(folderPath)) { filePath.addLast(dir.getFileName().toString()); // 寫入目錄 ZipEntry zipEntry = new ZipEntry(filePath.stream().collect(Collectors.joining("/", "", "/"))); try { zipOutputStream.putNextEntry(zipEntry); zipOutputStream.flush(); } catch (IOException e) { LOGGER.error(e.getMessage(), e); throw new RuntimeException(e); } } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // 開始遍歷文件 try (InputStream inputStream = Files.newInputStream(file)) { // 創建一個壓縮項,指定名稱 String fileName = filePath.size() > 0 ? filePath.stream().collect(Collectors.joining("/", "", "")) + "/" + file.getFileName().toString() : file.getFileName().toString(); ZipEntry zipEntry = new ZipEntry(fileName); // 添加到壓縮流 zipOutputStream.putNextEntry(zipEntry); // 寫入數據 int len; // 設置10kb緩沖區 byte[] buffer = new byte[1024 * 10]; while ((len = inputStream.read(buffer)) > 0) { zipOutputStream.write(buffer, 0, len); } zipOutputStream.flush(); } catch (IOException e) { LOGGER.error(e.getMessage(), e); throw new RuntimeException(e); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { // 結束遍歷目錄 if (!filePath.isEmpty()) { filePath.removeLast(); } return FileVisitResult.CONTINUE; } }); zipOutputStream.closeEntry(); } catch (IOException e) { LOGGER.error(e.getMessage(), e); } } } }