news 2026/4/16 0:44:43

基于 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 是重量级进程,不要在容器中频繁启停,建议常驻运行;若追求轻量,可考虑OnlyOfficePandoc等替代方案。


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


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

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

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 想要在VS Code中享受现代化的Fortran开…

作者头像 李华
网站建设 2026/4/15 13:31:47

GLM-4-9B-Chat-1M:当AI学会“读万卷书“

GLM-4-9B-Chat-1M&#xff1a;当AI学会"读万卷书" 【免费下载链接】glm-4-9b-chat-1m 项目地址: https://ai.gitcode.com/zai-org/glm-4-9b-chat-1m 你是否曾经遇到过这样的情况&#xff1a;想要让AI帮你分析一份上百页的法律合同&#xff0c;却发现它只能处…

作者头像 李华
网站建设 2026/4/15 13:30:05

Snap2HTML实战秘籍:一键生成硬盘目录交互式网页的终极攻略

Snap2HTML实战秘籍&#xff1a;一键生成硬盘目录交互式网页的终极攻略 【免费下载链接】Snap2HTML Generates directory listings contained in a single, app-like HTML files 项目地址: https://gitcode.com/gh_mirrors/sn/Snap2HTML 还在为查找硬盘文件而烦恼吗&…

作者头像 李华
网站建设 2026/4/15 13:31:48

《2024年CSDN年度技术趋势预测:开发者必须关注的十大方向》

引言简要说明技术趋势预测的意义&#xff0c;结合CSDN平台开发者群体的关注点&#xff0c;提出本文的核心内容框架。技术趋势预测大纲人工智能与生成式AI的突破性进展大模型多模态能力普及&#xff08;如GPT-5、Claude 3等迭代方向&#xff09; AIGC工具在开发流程中的渗透&…

作者头像 李华
网站建设 2026/4/15 13:29:16

鸿蒙远程投屏终极指南:HOScrcpy实现高效开发调试

鸿蒙远程投屏终极指南&#xff1a;HOScrcpy实现高效开发调试 【免费下载链接】鸿蒙远程真机工具 该工具主要提供鸿蒙系统下基于视频流的投屏功能&#xff0c;帧率基本持平真机帧率&#xff0c;达到远程真机的效果。 项目地址: https://gitcode.com/OpenHarmonyToolkitsPlaza/…

作者头像 李华
网站建设 2026/4/15 13:31:10

音乐解析技术终极指南:突破播放限制的完整解决方案

音乐解析技术终极指南&#xff1a;突破播放限制的完整解决方案 【免费下载链接】lx-source lx-music-custom-source 洛雪音乐自定义解析源 项目地址: https://gitcode.com/gh_mirrors/lx/lx-source 问题根源&#xff1a;数字音乐时代的版权困境 当你在海外旅行时打开音…

作者头像 李华