Spring Boot 整合 LibreOffice:本地调用、远程服务与 Docker 一体化部署实战

Spring Boot 整合 LibreOffice:本地调用、远程服务与 Docker 一体化部署实战

在企业级应用中,文档格式转换(如 Word 转 PDF、Excel 转 HTML)是常见需求。LibreOffice 作为开源、免费且功能强大的办公套件,提供了命令行接口,非常适合集成到 Java 应用中实现自动化文档处理。

本文将详细介绍 Spring Boot 项目整合 LibreOffice 的两种主流方式

  1. 调用本地安装的 LibreOffice(适用于单机或轻量场景)
  2. 调用远程 LibreOffice 服务(适用于微服务、高并发或容器化架构)

并进一步演示如何通过 Docker Compose 将 Spring Boot 应用与 LibreOffice 容器 一体化部署,实现开箱即用的文档转换服务。


一、准备工作

技术栈

  • Spring Boot 3.x(Java 17+)
  • LibreOffice 7.0+
  • Docker & Docker Compose
  • Apache Commons IO(用于文件操作)

Maven 依赖(pom.xml

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.15.1</version>
</dependency>

二、方式一:调用本地 LibreOffice(进程调用)

适用于开发环境或单机部署,直接通过 ProcessBuilder 调用系统中已安装的 LibreOffice。

1. 安装 LibreOffice(Linux 示例)

csharp 复制代码
# Ubuntu/Debian
sudo apt-get install libreoffice

# CentOS/RHEL
sudo yum install libreoffice-headless

⚠️ 生产环境建议安装 libreoffice-headless(无图形界面版本),节省资源。

2. 编写转换工具类

arduino 复制代码
@Service
public class LocalLibreOfficeService {

    private static final String LIBREOFFICE_PATH = "/usr/bin/libreoffice";

    public void convertToPdf(File inputFile, File outputFile) throws IOException, InterruptedException {
        String outputDir = outputFile.getParent();

        ProcessBuilder builder = new ProcessBuilder(
            LIBREOFFICE_PATH,
            "--headless",
            "--convert-to", "pdf",
            "--outdir", outputDir,
            inputFile.getAbsolutePath()
        );

        Process process = builder.start();
        int exitCode = process.waitFor();

        if (exitCode != 0) {
            throw new RuntimeException("LibreOffice conversion failed with exit code: " + exitCode);
        }

        // 重命名生成的文件(LibreOffice 默认保留原文件名)
        File generated = new File(outputDir, 
            FilenameUtils.getBaseName(inputFile.getName()) + ".pdf");
        if (!generated.renameTo(outputFile)) {
            throw new RuntimeException("Failed to rename output file");
        }
    }
}

3. 控制器示例

less 复制代码
@PostMapping("/convert/local")
public ResponseEntity<Resource> convertLocal(@RequestParam("file") MultipartFile file) 
    throws IOException, InterruptedException {
    
    File input = File.createTempFile("input_", "." + getExtension(file.getOriginalFilename()));
    File output = File.createTempFile("output_", ".pdf");

    file.transferTo(input);
    localLibreOfficeService.convertToPdf(input, output);

    return ResponseEntity.ok()
        .contentType(MediaType.APPLICATION_PDF)
        .body(new ByteArrayResource(Files.readAllBytes(output.toPath())));
}

优点 :简单直接,无需额外服务

缺点:耦合本地环境,难以横向扩展,多进程竞争资源


三、方式二:调用远程 LibreOffice 服务(推荐生产使用)

将 LibreOffice 封装为独立的 REST 服务(或使用现成方案如 unoconv + FlaskGotenberg),Spring Boot 通过 HTTP 调用。

本文采用 Gotenberg ------ 一个基于 Docker 的现代化文档转换微服务,支持 LibreOffice、Chrome 等引擎。

1. 启动 Gotenberg 服务(Docker)

bash 复制代码
docker run --rm -p 3000:3000 thecodingmachine/gotenberg:8

Gotenberg 提供 /forms/libreoffice/convert 接口用于文档转换。

2. Spring Boot 调用远程服务

arduino 复制代码
@Service
public class RemoteLibreOfficeService {

    private final RestTemplate restTemplate;
    private static final String GOTENBERG_URL = "http://localhost:3000";

    public RemoteLibreOfficeService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public byte[] convertToPdf(MultipartFile file) {
        LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("files", new ByteArrayResource(file.getBytes()) {
            @Override
            public String getFilename() {
                return file.getOriginalFilename();
            }
        });

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        HttpEntity<LinkedMultiValueMap<String, Object>> request = 
            new HttpEntity<>(map, headers);

        return restTemplate.postForObject(
            GOTENBERG_URL + "/forms/libreoffice/convert",
            request,
            byte[].class
        );
    }
}

3. 控制器调用

less 复制代码
@PostMapping("/convert/remote")
public ResponseEntity<Resource> convertRemote(@RequestParam("file") MultipartFile file) {
    byte[] pdfBytes = remoteLibreOfficeService.convertToPdf(file);
    return ResponseEntity.ok()
        .contentType(MediaType.APPLICATION_PDF)
        .body(new ByteArrayResource(pdfBytes));
}

优点

  • 解耦应用与 LibreOffice
  • 可独立扩缩容
  • 支持多种格式(PDF、PNG、TXT 等)
  • 内置重试、超时、限流机制(可通过 Nginx 或服务网格增强)

四、Docker 一体化部署:Spring Boot + LibreOffice

为了实现"一键部署",我们使用 Docker Compose 同时启动应用和 LibreOffice 服务。

方案选择:Gotenberg 容器 + 自定义 Spring Boot 容器

1. Dockerfile(Spring Boot 应用)

bash 复制代码
FROM eclipse-temurin:17-jre-alpine
COPY target/app.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

2. docker-compose.yml

yaml 复制代码
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - gotenberg
    environment:
      - GOTENBERG_URL=http://gotenberg:3000

  gotenberg:
    image: thecodingmachine/gotenberg:8
    ports:
      - "3000:3000"

3. 修改 Spring Boot 配置(支持动态 URL)

ruby 复制代码
# application.yml
gotenberg:
  url: ${GOTENBERG_URL:http://localhost:3000}

并在 RemoteLibreOfficeService 中注入配置:

kotlin 复制代码
@Value("${gotenberg.url}")
private String gotenbergUrl;

4. 构建并启动

lua 复制代码
./mvnw clean package -DskipTests
docker-compose up --build

访问:

  • 应用:http://localhost:8080/convert/remote
  • Gotenberg UI:http://localhost:3000

五、对比总结

方式 适用场景 扩展性 维护成本 推荐度
本地调用 开发、测试、小型单机应用 ⭐⭐
远程服务(Gotenberg) 微服务、生产环境、高并发 ⭐⭐⭐⭐⭐
Docker 一体化 快速交付、CI/CD、演示环境 低(容器化后) ⭐⭐⭐⭐

六、注意事项

  1. 文件安全:上传文件需校验类型、大小,防止恶意文档攻击。
  2. 临时文件清理 :使用 @Scheduled 定期清理 /tmp 中的临时文件。
  3. 超时控制:LibreOffice 转换大文件可能耗时较长,需设置合理超时(如 60s)。
  4. 并发限制:LibreOffice 单实例并发能力有限,高并发场景建议部署多个 Gotenberg 实例 + 负载均衡。

结语

通过本文,你已掌握 Spring Boot 与 LibreOffice 集成的 三种部署形态:从简单的本地调用,到解耦的远程服务,再到容器化的一体化部署。无论你是构建内部工具还是对外 SaaS 产品,都能找到合适的方案。

相关推荐
cjy0001115 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
小江的记录本6 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
sheji34166 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
程序员cxuan6 小时前
人麻了,谁把我 ssh 干没了
人工智能·后端·程序员
wuyikeer7 小时前
Spring Framework 中文官方文档
java·后端·spring
Victor3567 小时前
MongoDB(61)如何避免大文档带来的性能问题?
后端
Victor3568 小时前
MongoDB(62)如何避免锁定问题?
后端
wuyikeer8 小时前
Spring BOOT 启动参数
java·spring boot·后端
子木HAPPY阳VIP9 小时前
Ubuntu 22.04 VMware 设置固定IP配置
人工智能·后端·目标检测·机器学习·目标跟踪
人间打气筒(Ada)9 小时前
如何基于 Go-kit 开发 Web 应用:从接口层到业务层再到数据层
开发语言·后端·golang