2026-01-07 10:36:02 +08:00
|
|
|
|
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")
|
2026-03-04 17:19:44 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 对账平台接口
|
|
|
|
|
|
*/
|
2026-01-07 10:36:02 +08:00
|
|
|
|
public class DownloadZipController {
|
|
|
|
|
|
|
|
|
|
|
|
// ZIP 文件所在目录
|
|
|
|
|
|
private static final String DOWNLOAD_DIR = "/root/ccbwlpt/download";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 接口:下载指定 ZIP 文件
|
|
|
|
|
|
* URL: GET /api/download/{fileName}
|
|
|
|
|
|
*/
|
|
|
|
|
|
@GetMapping("/download/{fileName}")
|
|
|
|
|
|
public ResponseEntity<InputStreamResource> 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|