news 2026/10/4 15:52:22

基于 Spring Boot + JODConverter 实现文档在线转换为 PDF 功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于 Spring Boot + JODConverter 实现文档在线转换为 PDF 功能

基于 Spring Boot + JODConverter 实现文档在线转换为 PDF 功能

作者:Qwen(阿里云 Qwen)
适用场景:企业办公系统、OA、知识库、文档管理平台等需要将 Word/Excel/PPT 等格式转为 PDF 的 Web 应用
技术栈:Spring Boot 3.x + JODConverter + LibreOffice + Hutool + OSS


一、背景与需求

在很多企业级应用中,用户上传的.docx、.xlsx、.pptx等 Office 文档,往往需要统一转换为PDF 格式进行预览、归档或打印。原因包括:

  • PDF 具有跨平台一致性;
  • 防止内容被随意编辑;
  • 便于前端使用 PDF.js 等库进行安全预览。

而市面上成熟的解决方案中,LibreOffice + JODConverter是一个开源、稳定且支持多种格式的组合,非常适合集成到 Spring Boot 项目中。

本文将带你从零搭建一个RESTful 文档转 PDF 接口,并附上完整的生产级代码。


二、技术选型说明

组件作用
LibreOffice开源办公套件,提供文档渲染与转换能力(需后台运行)
JODConverterJava 封装库,通过 UNO API 调用 LibreOffice 进行格式转换
Spring Boot快速构建 Web 服务
Hutool简化文件操作、路径处理、工具类封装
OSS Service可选,用于临时文件存储或结果上传(如 MinIO、阿里云 OSS)

⚠️ 注意:JODConverter 依赖 LibreOffice 进程,必须确保服务器已安装并启动 LibreOffice 服务(通常以--headless --accept="socket..."模式运行)。


三、核心实现步骤

1. 添加依赖(Maven)

<!-- JODConverter 核心 --> <dependency> <groupId>org.jodconverter</groupId> <artifactId>jodconverter-spring-boot-starter</artifactId> <version>4.4.6</version> </dependency> <!-- Hutool 工具包 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.22</version> </dependency>

如果你使用的是JODConverter Local(本地调用 LibreOffice),还需确保libreoffice已安装:

# Ubuntu sudo apt install libreoffice # 后台启动 LibreOffice(无界面模式) soffice --headless --accept="socket,host=127.0.0.1,port=2002;urp;" --nofirststartwizard &

2. 编写 Controller:接收文件并返回 PDF

@RestController @RequestMapping("${spring.application.name}/document/converter") @AllArgsConstructor @Tag(name = "DocumentConverterController", description = "文档转换API") public class DocumentConverterController { private final DocumentConverterService documentConverterService; @PostMapping(value = "/toPdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @Operation(summary = "上传任意文档,转换为PDF并下载") public ResponseEntity<byte[]> toPdf(@RequestPart("file") MultipartFile file) { byte[] pdfBytes = documentConverterService.toPdfByte(file); String filename = FileNameUtil.getPrefix(file.getOriginalFilename()) + "." + "pdf"; return HttpFileUtil.downloadByte(pdfBytes, filename); } }

✅ 支持.doc,.docx,.xls,.xlsx,.ppt,.pptx等常见格式。


3. 实现 Service:核心转换逻辑

关键方法toPdf(MultipartFile)流程如下:

  1. 校验文件有效性;
  2. 保存为临时文件(因 JODConverter 只接受File对象);
  3. 调用 LibreOffice 转换;
  4. 读取 PDF 字节数组;
  5. 清理临时文件(防止磁盘爆满)。
@Slf4j @Service @AllArgsConstructor public class DocumentConverterServiceImpl implements DocumentConverterService { private final OssProperties ossProperties; private final OssService ossService; private DocumentConverter getConverter() { try { DocumentConverter converter = SpringUtil.getBean(DocumentConverter.class); AssertUtil.notNull(converter, "请先配置LibreOffice!"); return converter; } catch (NoSuchBeanDefinitionException ex) { throw new ServiceException("请先配置LibreOffice!"); } } @Override public File toPdf(MultipartFile file) { if (file == null || file.isEmpty()) { throw new ServiceException("文件不能为空"); } // 构建临时目录 String tempDir = ossProperties.getLocal().getPath() + "/temp/" + IdGeneratorUtil.getSnowflakeNextIdStr(); File inputFile = FileUtil.writeFromStream(file.getInputStream(), tempDir + "/" + file.getOriginalFilename()); try { return this.toPdf(inputFile); // 重载方法 } finally { FileUtil.del(tempDir); // 清理整个临时目录 } } @Override public File toPdf(File inputFile) { String ext = FileNameUtil.getSuffix(inputFile.getName()).toLowerCase(); if ("pdf".equals(ext)) { return inputFile; // 已是 PDF,无需转换 } String outputPath = inputFile.getParent() + "/" + FileUtil.getPrefix(inputFile.getName()) + ".pdf"; File outputFile = FileUtil.touch(outputPath); long start = System.currentTimeMillis(); try { getConverter().convert(inputFile).to(outputFile).execute(); log.info("转换成功,耗时 {} ms", System.currentTimeMillis() - start); return outputFile; } catch (Exception e) { log.error("文档转换失败", e); throw new ServiceException("不支持的文档格式或转换异常"); } } @Override public byte[] toPdfByte(MultipartFile file) { File pdfFile = null; try { pdfFile = toPdf(file); return FileUtil.readBytes(pdfFile); } finally { if (pdfFile != null) { FileUtil.del(pdfFile.getParentFile()); // 安全删除父目录 } } } }

🔒安全提示:务必在finally块中删除临时文件,避免攻击者通过大量上传占满磁盘。


4. 工具类补充:HttpFileUtil

用于生成可下载的 PDF 响应:

public class HttpFileUtil { public static ResponseEntity<byte[]> downloadByte(byte[] content, String filename) { HttpHeaders headers = new HttpHeaders(); headers.setContentDispositionFormData("attachment", URLEncoder.encode(filename, StandardCharsets.UTF_8)); headers.setContentType(MediaType.APPLICATION_PDF); headers.setContentLength(content.length); return new ResponseEntity<>(content, headers, HttpStatus.OK); } }

四、部署与配置建议

1. LibreOffice 启动脚本(推荐 systemd)

创建/etc/systemd/system/libreoffice.service:

[Unit] Description=LibreOffice Headless Service After=network.target [Service] Type=simple User=your-app-user ExecStart=/usr/bin/soffice --headless --accept="socket,host=127.0.0.1,port=2002;urp;" --nofirststartwizard Restart=always [Install] WantedBy=multi-user.target

然后启用:

sudo systemctl daemon-reload sudo systemctl enable libreoffice sudo systemctl start libreoffice

2. JODConverter 配置(application.yml)

jodconverter: local: office-home: /usr/lib/libreoffice # 可选,自动检测通常足够 port: 2002 task-execution-timeout: 120000 # 超时2分钟

五、扩展功能(可选)

  • 异步转换:使用@Async避免大文件阻塞 HTTP 请求;
  • 结果上传 OSS:如代码中的toPdfAndUpload方法;
  • 格式白名单校验:防止恶意文件(如.exe)上传;
  • 转换队列限流:避免 LibreOffice 进程过载。

六、总结

通过Spring Boot + JODConverter + LibreOffice,我们实现了高效、稳定的文档转 PDF 能力。该方案已在多个生产系统中验证,支持高并发(配合连接池)、格式丰富、易于维护。

💡最后提醒:LibreOffice 是重量级进程,不要在容器中频繁启停,建议常驻运行;若追求轻量,可考虑OnlyOffice或Pandoc等替代方案。


GitHub 示例项目(可自行搭建):欢迎 Star ⭐
关键词:#SpringBoot #PDF #文档转换 #LibreOffice #JODConverter #Java


如有疑问,欢迎评论区交流!如果你觉得这篇文章对你有帮助,别忘了点赞、收藏、转发~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 16:45:31

Postman便携版完整指南:免安装快速上手API测试工具

Postman便携版完整指南&#xff1a;免安装快速上手API测试工具 【免费下载链接】postman-portable &#x1f680; Postman portable for Windows 项目地址: https://gitcode.com/gh_mirrors/po/postman-portable Postman便携版是一款专为开发者打造的即开即用API测试解决…

作者头像 李华
网站建设 2026/10/2 10:29:08

Modern Fortran终极配置:VS Code环境搭建完全手册

Modern Fortran终极配置&#xff1a;VS Code环境搭建完全手册 【免费下载链接】vscode-fortran-support Fortran language support for Visual Studio Code 项目地址: https://gitcode.com/gh_mirrors/vs/vscode-fortran-support 想要在Visual Studio Code中高效开发For…

作者头像 李华
网站建设 2026/10/2 10:29:09

Betaflight固件编译:如何选择正确的GCC工具链版本

Betaflight固件编译&#xff1a;如何选择正确的GCC工具链版本 【免费下载链接】betaflight Open Source Flight Controller Firmware 项目地址: https://gitcode.com/gh_mirrors/be/betaflight 你是否曾经在编译Betaflight固件时&#xff0c;面对各种GCC版本感到困惑&am…

作者头像 李华
网站建设 2026/10/4 0:49:38

Obsidian PDF注释终极指南:如何实现高效PDF阅读与知识管理

Obsidian PDF注释终极指南&#xff1a;如何实现高效PDF阅读与知识管理 【免费下载链接】awesome-obsidian &#x1f576;️ Awesome stuff for Obsidian 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-obsidian 想要在Obsidian中打造一个强大的PDF注释系统吗&am…

作者头像 李华
网站建设 2026/10/2 10:29:09

Obsidian PDF注释终极指南:如何在5分钟内快速掌握高效笔记管理

Obsidian PDF注释终极指南&#xff1a;如何在5分钟内快速掌握高效笔记管理 【免费下载链接】awesome-obsidian &#x1f576;️ Awesome stuff for Obsidian 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-obsidian 想要彻底改变您的PDF阅读和笔记管理方式吗&am…

作者头像 李华
网站建设 2026/10/3 15:04:32

3步搞定Postman便携版:免安装API测试完整指南

3步搞定Postman便携版&#xff1a;免安装API测试完整指南 【免费下载链接】postman-portable &#x1f680; Postman portable for Windows 项目地址: https://gitcode.com/gh_mirrors/po/postman-portable Postman便携版为开发者提供了即开即用的API测试解决方案&#…

作者头像 李华