package com.guahao.h5.zip; import org.springframework.http.*; import org.springframework.web.bind.annotation.*; import org.springframework.core.io.InputStreamResource; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.file.*; import java.util.Objects; @RestController @RequestMapping("/find") /** * 对账平台接口 */ public class DownloadZipController { // ZIP 文件所在目录 private static final String DOWNLOAD_DIR = "/root/ccbwlpt/download"; /** * 接口:下载指定 ZIP 文件 * URL: GET /api/download/{fileName} */ @GetMapping("/download/{fileName}") public ResponseEntity downloadZip( @PathVariable String fileName) { // 1. 构建完整文件路径 Path filePath = Paths.get(DOWNLOAD_DIR, fileName); // 2. 验证文件是否存在且为普通文件 if (!Files.exists(filePath)) { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(null); } if (!Files.isRegularFile(filePath)) { return ResponseEntity.badRequest() .body(null); } // 3. 验证文件确实是 ZIP(可选安全检查) if (!isZipFile(filePath)) { return ResponseEntity.badRequest() .header("X-Error", "File is not a ZIP file") .body(null); } try { // 4. 打开输入流 InputStreamResource resource = new InputStreamResource(Files.newInputStream(filePath)); // 5. 构造响应头 HttpHeaders headers = new HttpHeaders(); headers.add("Content-Disposition", "attachment; filename=\"" + fileName + "\""); headers.add("Content-Type", "application/zip"); headers.setContentLength(Files.size(filePath)); return ResponseEntity.ok() .headers(headers) .contentLength(Files.size(filePath)) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .header("X-Error", "Failed to read file: " + e.getMessage()) .body(null); } catch (SecurityException e) { return ResponseEntity.status(HttpStatus.FORBIDDEN) .header("X-Error", "Permission denied: " + e.getMessage()) .body(null); } } /** * 简单判断是否为 ZIP 文件(检查文件头) */ private boolean isZipFile(Path path) { try (RandomAccessFile raf = new RandomAccessFile(path.toFile(), "r")) { if (raf.length() < 4) return false; int magic = raf.readInt(); return magic == 0x504B0304 || magic == 0x504B0506 || magic == 0x504B0708; } catch (IOException e) { return false; } } }