当前位置:   article > 正文

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

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

1.前言

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

2.依赖

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

        <dependency>
            <groupId>fr.opensagres.xdocreport</groupId>
            <artifactId>fr.opensagres.poi.xwpf.converter.pdf-gae</artifactId>
            <version>2.0.1</version>
        </dependency>

        <!-- Apache PDFBox 依赖用于.docx转PDF -->
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>3.0.0</version> <!-- 根据最新版本调整 -->
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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<Resource> 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<Resource> 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<String> 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<String> 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());
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204

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

<!-- 模态框(Modal) -->
<div class="modal fade" id="pdfModalMonth" tabindex="-1" role="dialog" aria-labelledby="pdfModalLabelMonth" aria-hidden="true">
    <div class="modal-dialog" style="max-width: 90%; width: auto;">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title" id="pdfModalLabelMonth">月度预测文档</h4>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <!-- 下拉框用于选择文档 -->
                <select id="MonthList" class="form-control">
                    <option value="">请选择文档</option>
                    <!-- 文档列表将在这里填充 -->
                </select>
                <iframe id="MonthViewer" style="width:100%; height:700px;"></iframe> <!-- 可以根据需要调整高度 -->
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="pdfModalQuarter" tabindex="-1" role="dialog" aria-labelledby="pdfModalLabelQuarter" aria-hidden="true">
    <div class="modal-dialog" style="max-width: 90%; width: auto;">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title" id="pdfModalLabelQuarter">月度预测文档</h4>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <!-- 下拉框用于选择文档 -->
                <select id="QuarterList" class="form-control">
                    <option value="">请选择文档</option>
                    <!-- 文档列表将在这里填充 -->
                </select>
                <iframe id="QuarterViewer" style="width:100%; height:700px;"></iframe> <!-- 可以根据需要调整高度 -->
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
            </div>
        </div>
    </div>
</div>
<a class="btn btn-sm btn-primary" id="loadMonth"  style="text-decoration: none;color: #ffffff">月度预测</a>
            <a class="btn btn-sm btn-primary" id="loadQuarter"  style="text-decoration: none;color: #ffffff">季度预测</a>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

js代码:

$(document).ready(function() {
    // 加载月度列表
    function loadMonthList() {
        $.get("/api/document/monthList", function(data) {
            // 清空现有的选项
            $("#MonthList").empty();
            $("#MonthList").append('<option value="">请选择文档</option>');

            // 假设文档名包含日期,例如 "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('<option value="' + doc + '">' + doc + '</option>');
            });
        });
    }

    // 当点击加载最新文档的按钮时
    $("#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('<option value="">请选择文档</option>');

            // 对文档进行倒序排序
            data.sort(function(a, b) {
                var dateA = parseDateFromDocName(a);
                var dateB = parseDateFromDocName(b);
                return dateB - dateA; // 从新到旧排序
            });

            // 添加新的选项
            data.forEach(function(doc) {
                $("#QuarterList").append('<option value="' + doc + '">' + doc + '</option>');
            });
        });
    }



    // 当点击加载最新文档的按钮时
    $("#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));
        }
    });
});

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

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
  1. 将字体文件复制到创建的目录中,假设你已经将simsun.ttc字体文件复制到了Linux系统的某个位置(例如~/Downloads),运行以下命令将其移动到字体目录:
sudo cp ~/Downloads/simsun.ttc /usr/share/fonts/chinese/
  • 1
  1. 更新字体缓存,安装完字体后,需要更新字体缓存,以便系统识别新安装的字体:
sudo fc-cache -fv
  • 1
  1. 安装后,你可以使用fc-list命令确认字体是否已正确安装:
fc-list | grep "simsun"
  • 1

至此,大功告成!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码创新者/article/detail/62724
推荐阅读
相关标签
  

闽ICP备14008679号