在现代Web应用中,文件上传与处理是常见的需求。本文将通过一个实际案例,详细介绍如何使用Spring Boot构建一个文件处理工具,实现以下功能:
我们将从项目搭建、核心功能实现到错误处理等方面进行全面讲解,并提供完整的代码示例。
resources/output目录保留结果副本使用Spring Initializr创建项目,添加依赖:
<dependencies>
<!-- Web支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Excel操作 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>@Controller
public class FileUploadController {
@GetMapping("/")
public String index() {
return "index"; // 对应templates/index.html
}
@PostMapping("/upload")
public ResponseEntity<byte[]> handleFileUpload(
@RequestParam("file") MultipartFile file) {
try {
Workbook workbook = imageProcessService.processZipFile(file);
// 保存到本地
saveToResourcesOutput(workbook);
// 返回Excel给用户
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
return ResponseEntity.ok()
.header("Content-Disposition", "attachment; filename=result.xlsx")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(outputStream.toByteArray());
} catch (Exception e) {
return ResponseEntity.status(500).body("处理失败".getBytes());
}
}
}private List<File> unzipFile(MultipartFile file) throws IOException {
List<File> extractedFiles = new ArrayList<>();
Path tempDir = Files.createTempDirectory("unzip_");
try (ZipInputStream zipIn = new ZipInputStream(file.getInputStream())) {
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
Path filePath = tempDir.resolve(entry.getName());
// 防止ZIP滑动攻击
if (!filePath.normalize().startsWith(tempDir)) {
throw new SecurityException("非法文件路径");
}
if (!entry.isDirectory() && isImageFile(entry.getName())) {
Files.copy(zipIn, filePath);
extractedFiles.add(filePath.toFile());
}
zipIn.closeEntry();
}
}
return extractedFiles;
}
private boolean isImageFile(String filename) {
String[] extensions = {".jpg", ".png", ".jpeg"};
return Arrays.stream(extensions).anyMatch(filename::endsWith);
}public OrderInfo getPicInfo(String imagePath) {
OrderInfo info = new OrderInfo();
try {
String base64Image = imageToBase64(imagePath);
String ocrResult = callOcrApi(base64Image); // 调用OCR API
info.setExpressNumber(extractExpressNo(ocrResult));
info.setPhoneNumber(extractPhoneNo(ocrResult));
} catch (Exception e) {
info.setError(true);
}
return info;
}private void saveToResourcesOutput(Workbook workbook) throws IOException {
Path outputDir = Paths.get("src/main/resources/output");
if (!Files.exists(outputDir)) {
Files.createDirectories(outputDir);
}
String filename = "result_" + System.currentTimeMillis() + ".xlsx";
try (FileOutputStream out = new FileOutputStream(outputDir.resolve(filename).toFile())) {
workbook.write(out);
}
}<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>图片处理工具</title>
</head>
<body>
<h1>上传ZIP压缩包</h1>
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" accept=".zip" required>
<button type="submit">提交</button>
</form>
<div th:if="${message}" th:text="${message}"></div>
</body>
</html>Error resolving template [index], template might not exist解决方案:
index.html位于resources/templates/目录增强健壮性:
try {
unzipFile(file);
} catch (IOException e) {
log.error("解压失败", e);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "无效的ZIP文件");
}大文件处理:使用SXSSFWorkbook流式写入Excel
并发处理:对多图片采用线程池并行OCR识别
临时文件清理:
@Scheduled(fixedRate = 86400000) // 每天清理
public void cleanTempFiles() {
// 删除超过1天的临时文件
}本文实现了一个完整的Spring Boot文件处理流程,关键点包括:
MultipartFile接收上传文件扩展方向:
GitHub示例:完整代码可在 https://github.com/example/file-processor 获取
通过这个案例,读者可以掌握Spring Boot中文件处理的核心技术,并快速应用到实际项目中。