小工具知识网

当前位置: 首页 > 行业知识 > SpringBoot使用poi将word转换为PDF并且展示

行业知识

SpringBoot使用poi将word转换为PDF并且展示

2026-11-09 00:05:26 来源:互联网转载

1.前言

由于最近做了一个需求,界面上有一个按钮,点击按钮后将一个文件夹中的word文档显示在页面中,并且有一个下拉框可以选择不同的文档,选择文档可以显示该文档。这里我选择使用fr.opensagres.poi.xwpf.converter.pdf-gae依赖包来实现。

2.依赖

这里我只依赖了这些依赖包

                    fr.opensagres.xdocreport            fr.opensagres.poi.xwpf.converter.pdf-gae            2.0.1                                    org.apache.pdfbox            pdfbox            3.0.0         

3.代码

Java代码部分,这里我使用了两个文件夹中的文档

package com.hxgis.controller;import java.io.File;import java.io.FileInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;import java.util.Arrays;import java.util.Collections;import java.util.Comparator;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;import java.util.stream.Collectors;import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter;import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions;import org.springframework.core.io.ByteArrayResource;import org.springframework.core.io.Resource;import org.springframework.http.ResponseEntity;import org.apache.poi.xwpf.usermodel.XWPFDocument;//import org.apache.poi.xwpf.converter.pdf.PdfOptions;//import org.apache.poi.xwpf.converter.pdf.PdfConverter;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;/** * ClassName: DocumentController * Package: com.hxgis.controller * Description: * * @Author dhn * @Create 2024/1/31 11:56 * @Version 1.0 */@RestController@RequestMapping("/api/document")public class DocumentController {    private final String MONTH_PATH = "D:/ftp_data/month"; // 修改为你的文档存储路径    private final String QUARTER_PATH = "D:/ftp_data/quarter"; // 修改为你的文档存储路径//    private final String MONTH_PATH = "/home/geli/hbnyWeatherReport/month"; // 修改为你的文档存储路径//    private final String QUARTER_PATH = "/home/geli/hbnyWeatherReport/quarter"; // 修改为你的文档存储路径    @GetMapping("/monthLatest")    public ResponseEntity getDocument(@RequestParam(required = false) String name) throws IOException {        File folder = new File(MONTH_PATH);        File[] files = folder.listFiles((dir, filename) -> filename.endsWith(".docx"));        if (files == null || files.length == 0) {            return ResponseEntity.notFound().build();        }        File fileToConvert;        if (name != null && !name.isEmpty()) {            // 用户选择了特定的文件            fileToConvert = Arrays.stream(files)                    .filter(file -> file.getName().equals(name))                    .findFirst()                    .orElse(null);        } else {            // 没有特定选择,找最新的文件            Pattern pattern = Pattern.compile("(\d{4})年(\d{2})月风光资源趋势预测\.docx");            fileToConvert = Arrays.stream(files)                    .filter(file -> pattern.matcher(file.getName()).matches())                    .max(Comparator.comparingInt(file -> {                        Matcher matcher = pattern.matcher(file.getName());                        if (matcher.find()) {                            int year = Integer.parseInt(matcher.group(1));                            int month = Integer.parseInt(matcher.group(2));                            return year * 100 + month;                        }                        return 0;                    }))                    .orElse(null);        }        if (fileToConvert == null) {            return ResponseEntity.notFound().build();        }        // 以下为文件转换为PDF的代码        try (XWPFDocument document = new XWPFDocument(new FileInputStream(fileToConvert));             ByteArrayOutputStream out = new ByteArrayOutputStream()) {            PdfOptions options = PdfOptions.create();            PdfConverter.getInstance().convert(document, out, options);            byte[] pdfContent = out.toByteArray();            ByteArrayResource resource = new ByteArrayResource(pdfContent);            return ResponseEntity.ok()                    .contentLength(pdfContent.length)                    .header("Content-type", "application/pdf")                    .body(resource);        }    }    @GetMapping("/quarterLatest")    public ResponseEntity quarterLatest(@RequestParam(required = false) String name) throws IOException {        File folder = new File(QUARTER_PATH);        File[] files = folder.listFiles((dir, filename) -> filename.endsWith(".docx"));        if (files == null || files.length == 0) {            return ResponseEntity.notFound().build();        }        File fileToConvert;        if (name != null && !name.isEmpty()) {            // 用户选择了特定的文件            fileToConvert = Arrays.stream(files)                    .filter(file -> file.getName().equals(name))                    .findFirst()                    .orElse(null);        } else {            // 没有特定选择,找最新的文件            Pattern pattern = Pattern.compile("(\d{4})年(?:\d{2})月-(\d{4})年(?:\d{2})月风光资源趋势预测\.docx|" +                    "(\d{4})年(?:\d{2})-(\d{2})月风光资源趋势预测\.docx");            fileToConvert = Arrays.stream(files)                    .filter(file -> pattern.matcher(file.getName()).matches())                    .max(Comparator.comparingInt(file -> {                        Matcher matcher = pattern.matcher(file.getName());                        if (matcher.find()) {                            if (matcher.group(1) != null) {                                // 处理跨年文件名                                int yearStart = Integer.parseInt(matcher.group(1));                                int yearEnd = Integer.parseInt(matcher.group(2));                                return yearEnd * 100 + (matcher.group(4) != null ? Integer.parseInt(matcher.group(4)) : 0);                            } else if (matcher.group(3) != null) {                                // 处理同一年文件名                                int year = Integer.parseInt(matcher.group(3));                                int monthEnd = Integer.parseInt(matcher.group(4));                                return year * 100 + monthEnd;                            }                        }                        return 0;                    }))                    .orElse(null);        }        if (fileToConvert == null) {            return ResponseEntity.notFound().build();        }        // 文件转换为PDF的代码        try (XWPFDocument document = new XWPFDocument(new FileInputStream(fileToConvert));             ByteArrayOutputStream out = new ByteArrayOutputStream()) {            PdfOptions options = PdfOptions.create();            PdfConverter.getInstance().convert(document, out, options);            byte[] pdfContent = out.toByteArray();            ByteArrayResource resource = new ByteArrayResource(pdfContent);            return ResponseEntity.ok()                    .contentLength(pdfContent.length)                    .header("Content-type", "application/pdf")                    .body(resource);        }    }    @GetMapping("/monthList")    public List listAllDocs() {        File folder = new File(MONTH_PATH);        // 修改为获取.docx文件        File[] files = folder.listFiles((dir, name) -> name.endsWith(".docx"));        if (files == null) {            return Collections.emptyList();        }        // 返回文件名列表        return Arrays.stream(files)                .map(File::getName)                .collect(Collectors.toList());    }    @GetMapping("/quarterList")    public List quarterList() {        File folder = new File(QUARTER_PATH);        // 修改为获取.docx文件        File[] files = folder.listFiles((dir, name) -> name.endsWith(".docx"));        if (files == null) {            return Collections.emptyList();        }        // 返回文件名列表        return Arrays.stream(files)                .map(File::getName)                .collect(Collectors.toList());    }}

前端代码html代码,使用两个按钮,点击后弹出模态框,在模态框中有iframe来展示pdf:

                                        

月度预测文档

× 请选择文档 关闭

月度预测文档

× 请选择文档 关闭 月度预测 季度预测

js代码:

$(document).ready(function() {    // 加载月度列表    function loadMonthList() {        $.get("/api/document/monthList", function(data) {            // 清空现有的选项            $("#MonthList").empty();            $("#MonthList").append('请选择文档');            // 假设文档名包含日期,例如 "2024年01月风光资源趋势预测.docx"            // 对文档进行倒序排序            data.sort(function(a, b) {                // 转换为日期格式进行比较                var dateA = new Date(a.split('年')[0], a.split('年')[1].split('月')[0] - 1);                var dateB = new Date(b.split('年')[0], b.split('年')[1].split('月')[0] - 1);                return dateB - dateA; // 从新到旧排序            });            // 添加新的选项            data.forEach(function(doc) {                $("#MonthList").append('' + doc + '');            });        });    }    // 当点击加载最新文档的按钮时    $("#loadMonth").click(function() {        loadMonthList(); // 调用函数加载文档列表        // 加载最新的PDF文档        $("#MonthViewer").attr("src", "/api/document/monthLatest");        // 显示模态框        $("#pdfModalMonth").modal("show");    });    // 当选择不同的文档时    $("#MonthList").change(function() {        var selectedFile = $(this).val();        if(selectedFile) {            $("#MonthViewer").attr("src", "/api/document/monthLatest?name=" + encodeURIComponent(selectedFile));        }    });    // 加载季度列表    function parseDateFromDocName(docName) {        var year, month;        var parts = docName.match(/(\d{4})年(\d{2})-(\d{2})月|(\d{4})年(\d{2})月-(\d{4})年(\d{2})月/);        if (parts) {            if (parts[1]) {                // 格式是 "YYYY年MM-DD月"                year = parseInt(parts[1], 10);                month = parseInt(parts[2], 10); // 使用开始月份            } else {                // 格式是 "YYYY年MM月-YYYY年MM月"                year = parseInt(parts[4], 10);                month = parseInt(parts[5], 10); // 使用开始月份            }        }        return new Date(year, month - 1); // JavaScript中的月份是从0开始的    }    function loadQuarterList() {        $.get("/api/document/quarterList", function(data) {            // 清空现有的选项            $("#QuarterList").empty();            $("#QuarterList").append('请选择文档');            // 对文档进行倒序排序            data.sort(function(a, b) {                var dateA = parseDateFromDocName(a);                var dateB = parseDateFromDocName(b);                return dateB - dateA; // 从新到旧排序            });            // 添加新的选项            data.forEach(function(doc) {                $("#QuarterList").append('' + doc + '');            });        });    }    // 当点击加载最新文档的按钮时    $("#loadQuarter").click(function() {        loadQuarterList(); // 调用函数加载文档列表        // 加载最新的PDF文档        $("#QuarterViewer").attr("src", "/api/document/quarterLatest");        // 显示模态框        $("#pdfModalQuarter").modal("show");    });    // 当选择不同的文档时    $("#QuarterList").change(function() {        var selectedFile = $(this).val();        if(selectedFile) {            $("#QuarterViewer").attr("src", "/api/document/quarterLatest?name=" + encodeURIComponent(selectedFile));        }    });});

4.遇到的问题

做完一切后,发现有些文档中的标题的中文没有显示出来,我就对比显示的文档和没显示的文档,发现是因为字体的原因,宋体是可以显示出来的,但是宋体(中文)显示不出来。把宋体(中文)改成宋体就可以显示。

但是这只是我windows系统上运行是没问题的,我把项目部署到服务器(centos)后,发现中文一点都展示不出来,这时候我就很纳闷,为什么在windows上能显示出来,linux上显示不出来,经过查阅资料,我发现是由于Linux上缺乏一些中文字体,例如宋体、仿宋等,这些字体是我文档中用到的字体,所以下一步我要将windows中的字体放在服务器上。

5.在Linux中安装宋体

在Linux系统中安装宋体(SimSun)字体,需要手动下载字体文件或从Windows系统中复制字体文件,然后将其安装到Linux系统中。宋体不包含在开源字体包中,因为它是微软的商业字体。下面是一般步骤:

  1. 从Windows复制:如果你有访问Windows系统的权限,可以从C:\Windows\Fonts目录找到simsun.ttc(宋体)和其他中文字体文件,并将其复制到你的Linux系统中。
  2. 在Linux系统上安装字体一般有以下几个步骤:
    1. 创建字体目录(如果尚不存在)
sudo mkdir -p /usr/share/fonts/chinese
  1. 将字体文件复制到创建的目录中,假设你已经将simsun.ttc字体文件复制到了Linux系统的某个位置(例如~/Downloads),运行以下命令将其移动到字体目录:
sudo cp ~/Downloads/simsun.ttc /usr/share/fonts/chinese/
  1. 更新字体缓存,安装完字体后,需要更新字体缓存,以便系统识别新安装的字体:
sudo fc-cache -fv
  1. 安装后,你可以使用fc-list命令确认字体是否已正确安装:
fc-list | grep "simsun"

至此,大功告成!

上一篇:微信小程序源码解读入门指南,零基础也能轻松掌握核心知识!

下一篇:服务器突然断电后怎么处理?