在Spring Boot中实现加密Zip压缩与解密下载
1. 应用场景
在文件传输场景中,常需要对敏感数据进行加密压缩,确保只有授权用户能解压查看。本文通过Spring Boot整合zip4j库,实现以下功能:
- 将多个文件加密压缩为受密码保护的Zip文件
- 通过接口下载加密Zip文件
- 提供密码验证和解密下载单个文件的能力
2. 环境准备
2.1 添加依赖
<!-- pom.xml -->
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>2.11.5</version>
</dependency>
2.2 配置文件参数
# application.yml
zip:
password: securePassword123! # 生产环境建议使用加密配置
temp-dir: /tmp/files
3. 实现加密压缩
3.1 创建加密Zip服务类
@Service
public class ZipService {
@Value("${zip.password}")
private String zipPassword;
@Value("${zip.temp-dir}")
private String tempDir;
public File createEncryptedZip(List<File> filesToZip) throws IOException {
String zipName = "encrypted_" + System.currentTimeMillis() + ".zip";
File zipFile = new File(tempDir, zipName);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
try(ZipOutputStream zos = new ZipOutputStream(zipFile, zipPassword.toCharArray())) {
for (File file : filesToZip) {
zipParameters.setFileNameInZip(file.getName());
zos.putNextEntry(zipParameters);
Files.copy(file.toPath(), zos);
zos.closeEntry();
}
}
return zipFile;
}
}
3.2 文件下载接口
@RestController
@RequestMapping("/api/zip")
public class ZipController {
@Autowired
private ZipService zipService;
@PostMapping("/encrypt")
public ResponseEntity<Resource> encryptAndDownload(@RequestBody List<MultipartFile> files)
throws IOException {
List<File> tempFiles = files.stream()
.map(this::saveToTemp)
.collect(Collectors.toList());
File zipFile = zipService.createEncryptedZip(tempFiles);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + zipFile.getName())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(new FileSystemResource(zipFile));
}
private File saveToTemp(MultipartFile file) {
// 实现文件暂存逻辑
}
}
4. 实现解密下载
4.1 解密服务方法
public File extractFile(File zipFile, String password, String targetFileName)
throws IOException {
try {
ZipFile zip = new ZipFile(zipFile);
if (!zip.isValidZipPassword(password.toCharArray())) {
throw new RuntimeException("Invalid password");
}
File outputFile = new File(tempDir, targetFileName);
zip.extractFile(targetFileName, outputFile, password.toCharArray());
return outputFile;
} catch (net.lingala.zip4j.exception.ZipException e) {
throw new RuntimeException("解密失败: " + e.getMessage());
}
}
4.2 解密下载接口
@GetMapping("/decrypt")
public ResponseEntity<Resource> decryptFile(
@RequestParam String zipFileName,
@RequestParam String password,
@RequestParam String targetFile) throws IOException {
File zipFile = new File(tempDir, zipFileName);
File decryptedFile = zipService.extractFile(zipFile, password, targetFile);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + decryptedFile.getName())
.body(new FileSystemResource(decryptedFile));
}
5. 安全增强建议
- 密码管理:避免硬编码密码,推荐使用Spring Cloud Config或Vault管理密钥
- 临时文件清理:添加定时任务定期清理临时目录
- 传输安全:务必启用HTTPS防止中间人攻击
- 访问控制:添加权限验证注解(如@PreAuthorize)
- 防暴力破解:对解密接口添加限流机制
6. 异常处理
全局异常处理示例:
@ControllerAdvice
public class ZipExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleZipErrors(RuntimeException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("处理失败: " + ex.getMessage());
}
}
7. 测试流程
- 使用Postman上传文件到
/api/zip/encrypt - 下载加密Zip文件,验证需要密码才能打开
- 调用解密接口验证密码正确性并下载单个文件
8. 总结
本文实现了以下核心功能:
- 基于AES-256的Zip加密压缩
- 安全的文件下载流处理
- 密码验证与文件提取功能
注意事项:
- 大文件处理建议使用分块传输
- 生产环境需要添加日志监控
- 建议对压缩操作添加异步处理
- 前端需要配合处理大文件上传/下载进度
可根据具体需求扩展文件列表管理、密码单独存储等功能。