news 2026/3/30 18:00:17

基于 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/3/29 3:34:20

鸿蒙远程投屏效能革命:破解跨设备开发难题的智能解决方案

鸿蒙远程投屏效能革命&#xff1a;破解跨设备开发难题的智能解决方案 【免费下载链接】鸿蒙远程真机工具 该工具主要提供鸿蒙系统下基于视频流的投屏功能&#xff0c;帧率基本持平真机帧率&#xff0c;达到远程真机的效果。 项目地址: https://gitcode.com/OpenHarmonyToolki…

作者头像 李华
网站建设 2026/3/27 11:13:15

终极指南:如何在浏览器中轻松查看CAD图纸

终极指南&#xff1a;如何在浏览器中轻松查看CAD图纸 【免费下载链接】three-dxf A dxf viewer for the browser using three.js 项目地址: https://gitcode.com/gh_mirrors/th/three-dxf Three.js DXF查看器是一款革命性的工具&#xff0c;让您能够在浏览器中直接显示和…

作者头像 李华
网站建设 2026/3/27 15:33:33

Snap2HTML完整指南:一键生成交互式目录网页的终极解决方案

Snap2HTML完整指南&#xff1a;一键生成交互式目录网页的终极解决方案 【免费下载链接】Snap2HTML Generates directory listings contained in a single, app-like HTML files 项目地址: https://gitcode.com/gh_mirrors/sn/Snap2HTML 想要快速将硬盘目录结构转换为美观…

作者头像 李华
网站建设 2026/3/30 15:56:17

如何在VS Code中高效配置Modern Fortran:从零到精通的终极指南

如何在VS Code中高效配置Modern Fortran&#xff1a;从零到精通的终极指南 【免费下载链接】vscode-fortran-support Fortran language support for Visual Studio Code 项目地址: https://gitcode.com/gh_mirrors/vs/vscode-fortran-support Modern Fortran扩展让Fortr…

作者头像 李华
网站建设 2026/3/26 23:33:35

10个颠覆认知的IOCCC代码解密技巧:当C语言遇上艺术

10个颠覆认知的IOCCC代码解密技巧&#xff1a;当C语言遇上艺术 【免费下载链接】winner Winners of the International Obfuscated C Code Contest 项目地址: https://gitcode.com/GitHub_Trending/wi/winner 你见过会画画的代码吗&#xff1f;当编程遇上艺术&#xff0…

作者头像 李华
网站建设 2026/3/27 9:25:47

Blur:终极视频运动模糊处理工具,让普通视频拥有电影级质感

Blur&#xff1a;终极视频运动模糊处理工具&#xff0c;让普通视频拥有电影级质感 【免费下载链接】blur Add motion blur to videos 项目地址: https://gitcode.com/gh_mirrors/bl/blur 想要为你的视频添加专业级的运动模糊效果吗&#xff1f;Blur这款免费开源的桌面应…

作者头像 李华