java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot文件处理

使用Spring Boot快速构建一个简单的文件处理工具

作者:码农阿豪@新空间

在现代Web应用中,文件上传与处理是常见的需求,本文将通过一个实际案例,详细介绍如何使用Spring Boot构建一个文件处理工具,感兴趣的小伙伴可以参考一下

引言

在现代Web应用中,文件上传与处理是常见的需求。本文将通过一个实际案例,详细介绍如何使用Spring Boot构建一个文件处理工具,实现以下功能:

我们将从项目搭建、核心功能实现到错误处理等方面进行全面讲解,并提供完整的代码示例。

一、项目概述与搭建

1.1 功能需求

用户通过网页上传ZIP文件

后端解压ZIP,提取图片文件

对每张图片进行OCR识别(如快递单号、手机号)

将识别结果生成Excel并提供下载

在服务器resources/output目录保留结果副本

1.2 技术栈

后端:Spring Boot 2.7+

模板引擎:Thymeleaf(前后端不分离)

文件处理:Apache Commons Compress(ZIP解压)

OCR识别:百度OCR API(或其他OCR服务)

Excel操作:Apache POI

1.3 初始化项目

使用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>

二、核心功能实现

2.1 文件上传接口

2.2 ZIP解压实现

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);
}

2.3 OCR信息识别

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;
}

2.4 生成Excel并保存

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);
    }
}

三、前端页面实现

Thymeleaf模板(index.html)

<!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>

四、错误处理与优化

4.1 常见错误解决

问题1:Thymeleaf模板找不到

Error resolving template [index], template might not exist

解决方案:

问题2:ZIP解压失败

增强健壮性:

try {
    unzipFile(file);
} catch (IOException e) {
    log.error("解压失败", e);
    throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "无效的ZIP文件");
}

4.2 性能优化建议

大文件处理:使用SXSSFWorkbook流式写入Excel

并发处理:对多图片采用线程池并行OCR识别

临时文件清理:

@Scheduled(fixedRate = 86400000) // 每天清理
public void cleanTempFiles() {
    // 删除超过1天的临时文件
}

五、问题分析与解决方案

问题描述

用户在使用Spring Boot开发一个文件处理应用时,遇到以下两个主要问题:

环境信息

Spring Boot版本:2.6.13

JDK版本:1.8

构建工具:Maven

问题场景:文件上传解析 + 生成Excel

问题分析

1.中文文件名处理失败(MALFORMED错误)

问题原因

解决方案

优化unzipFile方法,正确处理编码和路径安全:

private List<File> unzipFile(MultipartFile file) throws IOException {
    List<File> extractedFiles = new ArrayList<>();
    File tempDir = Files.createTempDirectory("unzip_").toFile();
    tempDir.deleteOnExit();

    // 尝试GBK编码(常见于Windows生成的ZIP)
    try (ZipInputStream zipIn = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"))) {
        ZipEntry entry;
        while ((entry = zipIn.getNextEntry()) != null) {
            String entryName = entry.getName();
            File destFile = new File(tempDir, entryName);
            
            // 安全检查:防止ZIP路径遍历
            String canonicalPath = destFile.getCanonicalPath();
            if (!canonicalPath.startsWith(tempDir.getCanonicalPath() + File.separator)) {
                throw new SecurityException("ZIP文件包含非法路径: " + entryName);
            }

            if (!entry.isDirectory() && isImageFile(entryName)) {
                Files.createDirectories(destFile.getParentFile().toPath());
                Files.copy(zipIn, destFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                extractedFiles.add(destFile);
            }
            zipIn.closeEntry();
        }
    } catch (Exception e) {
        // 如果GBK失败,回退到UTF-8
        try (ZipInputStream zipIn = new ZipInputStream(file.getInputStream(), StandardCharsets.UTF_8)) {
            // 重复解压逻辑...
        }
    }
    return extractedFiles;
}

关键改进点

多编码支持:优先尝试GBK(常见中文编码),失败后回退到UTF-8。

路径安全:使用getCanonicalPath检查路径合法性,防止恶意ZIP文件攻击。

代码健壮性:使用Files.copy替代手动缓冲读写,更高效可靠。

2.JAR包无法运行(NoClassDefFoundError)

问题原因

打包时未正确生成可执行的Spring Boot JAR,导致:

解决方案

修正pom.xml,确保正确打包:

<build>
    <plugins>
        <!-- 1. 指定Java编译版本 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>

        <!-- 2. 关键:正确配置Spring Boot Maven插件 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>${spring-boot.version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal> <!-- 生成可执行JAR -->
                    </goals>
                </execution>
            </executions>
            <configuration>
                <mainClass>com.debang.debang_phone_tool.DebangPhoneToolApplication</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

关键改进点

移除<skip>true</skip>:确保插件执行重新打包操作。

明确指定mainClass:避免运行时找不到主类。

验证打包结果

# 检查JAR结构
jar tf target/debang_phone_tool-0.0.1-SNAPSHOT.jar | grep BOOT-INF/lib
# 检查MANIFEST.MF
jar xf target/debang_phone_tool-0.0.1-SNAPSHOT.jar META-INF/MANIFEST.MF && cat META-INF/MANIFEST.MF

完整解决方案

修正后的项目结构

src/
├── main/
│   ├── java/
│   │   └── com/debang/debang_phone_tool/
│   │       ├── DebangPhoneToolApplication.java  # Spring Boot主类
│   │       ├── controller/                      # 控制器
│   │       └── service/                         # 业务逻辑
│   └── resources/
│       ├── static/                              # 静态文件
│       └── application.yml                      # 配置文件
pom.xml                                         # 修正后的Maven配置

打包与运行命令

# 清理并重新打包
mvn clean package

# 后台运行(Linux)
nohup java -jar target/debang_phone_tool-0.0.1-SNAPSHOT.jar > app.log 2>&1 &

# 查看日志
tail -f app.log

总结

1.编码问题

文件处理:显式指定编码(如GBK/UTF-8),避免依赖平台默认值。

路径安全:使用getCanonicalPath检查路径合法性。

2.打包问题

必须使用spring-boot-maven-plugin:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

验证JAR结构:

3.日志与监控

日志重定向:使用2>&1捕获所有输出:

nohup java -jar app.jar > app.log 2>&1 &

进程管理:结合systemd或supervisord实现服务化。

六、总结

本文实现了一个完整的Spring Boot文件处理流程,关键点包括:

扩展方向:

GitHub示例:完整代码可在 https://github.com/example/file-processor 获取

通过这个案例,读者可以掌握Spring Boot中文件处理的核心技术,并快速应用到实际项目中。

以上就是使用Spring Boot快速构建一个简单的文件处理工具的详细内容,更多关于Spring Boot文件处理的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文