Java 将word转为PDF的三种方式和处理在服务器上下载后乱码的格式

news2025/1/23 11:30:52

我这边是因为业务需要将之前导出的word文档转换为PDF文件,然后页面预览下载这样的情况。之前导出word文档又不是我做的,所以为了不影响业务,只是将最后在输出流时转换成了PDF,当时本地调用没什么问题,一切正常,后面发布测试环境使用时才发现,导出时PDF文件内容乱码了,中文没有一个显示的。
这里记录下当时遇到的问题和解决方式:

1:解决中文不显示,乱码处理情况

我这里是使用的POI进行的转换,直接将word转换成PDF,转换方式放在后面。
当时转换后的PDF长这样:
在这里插入图片描述
正常格式下是有很多中文说明的。下面就是处理方式:
当时就想到了是服务器上不支持中文,所以百度了一圈,果然是,然后就开始加中文字体:
Linux 服务器上字体目录是在:/user/share/fonts 下的
1:在/user/share/fonts 下创建自己的文件夹字体,我这里是my-fonts
在这里插入图片描述
2:找到Windows中的字体,将字体上传到这个 my-fonts中
在这里插入图片描述
这里面有很多字体,我们需要的是中文字体,可以选择性上传,选择需要的中文字体上传,比如宋体,要和你文件模板中字体一致就行。

3:安装
接着根据当前目录下的字体建立scale文件
mkfontscale
接着建立dir文件
mkfontdir
然后运行
fc-cache
fc-list #查看字体列表

4:赋予权限
chmod 777/usr/share/fonts/my-fonts
chmod 755 /usr/share/fonts/my-fonts/*

使用命令查看: fc-list :lang=zh

2:Word转PDF实现的几种方式

1:使用POI的方式将word转换为PDF
引入依赖:

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

在关闭流之前添加并修改reponse中.docx为.pdf

response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode("日报-"+datetime+".pdf", "UTF-8"));
//转为PDF
PdfOptions options = PdfOptions.create();
PdfConverter.getInstance().convert(document, outStream, options);
//下面再是转word里面最后的代码,关闭流

2:使用aspose.words的Document方式将word转换为PDF
1:下载jar包:jar包下载
2:将jar包放入项目中resources目录下的lib文件夹中:
在这里插入图片描述
3:将jar包转为library
在这里插入图片描述
转换后就会出现上面图中箭头处的样子可以打开。

4:引入jar包依赖:

<dependency>
            <groupId>com.aspose.words</groupId>
            <artifactId>aspose-words</artifactId>
            <version>15.8.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/aspose-words-15.8.0-jdk16.jar</systemPath>
</dependency>

在打包的依赖中添加:

			<plugin>
                <configuration>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
			</plugin>

5:转换

String s = "<License><Data><Products><Product>Aspose.Total for Java</Product><Product>Aspose.Words for Java</Product></Products><EditionType>Enterprise</EditionType><SubscriptionExpiry>20991231</SubscriptionExpiry><LicenseExpiry>20991231</LicenseExpiry><SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber></Data><Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature></License>";
		//去除水印
        ByteArrayInputStream is = new ByteArrayInputStream(s.getBytes());
        License license = new License();
        license.setLicense(is);

		//将XWPFDocument转换为InputStream
        ByteArrayOutputStream b = new ByteArrayOutputStream();
        //这里的document=XWPFDocument document,在下面的word转换中
        document.write(b);
        InputStream inputStream = new ByteArrayInputStream(b.toByteArray());
        
        //这里的Document 的引入是
        //import com.aspose.words.Document;
		//import com.aspose.words.License;
		//import com.aspose.words.SaveFormat;
        Document doc = new Document(inputStream);
        doc.save(outStream, SaveFormat.PDF);
        b.close();
        inputStream.close();
        //下面再是转word里面最后的代码,关闭流

3:使用documents4j 的方式将word转换为PDF

1:引入依赖:

        <!-- word 转 pdf   通过documents4j实现    -->

        <dependency>
            <groupId>com.documents4j</groupId>
            <artifactId>documents4j-local</artifactId>
            <version>1.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.documents4j</groupId>
            <artifactId>documents4j-transformer-msoffice-word</artifactId>
            <version>1.0.3</version>
        </dependency>

2:转换如下:

		//将XWPFDocument转换为InputStream
		ByteArrayOutputStream b = new ByteArrayOutputStream();
		//这里的document=XWPFDocument document,在下面的word转换中
        document.write(b);
        InputStream docxInputStream = new ByteArrayInputStream(b.toByteArray());
        
        //下面的引入类为:
        //import com.documents4j.api.DocumentType;
		//import com.documents4j.api.IConverter;
		//import com.documents4j.job.LocalConverter;
        IConverter converter = LocalConverter.builder().build();
        boolean execute = converter.convert(docxInputStream)
                .as(DocumentType.DOCX)
                .to(outStream)
                .as(DocumentType.PDF).schedule().get();
        
        b.close();
        docxInputStream.close();

3:这里之前转换word方式记录如下

1:制作word模板,将需要转换的数值写成了${变量名}。
在这里插入图片描述
2:转换

//模板文件的地址
String filePath = "/usr/local/data/模板.docx";
//Map存储需要替换的值
Map<String, Object> map = new HashMap<>();
map.put("${date}", date);
map.put("${datetime}", datetime);
//写入
try {
            // 替换的的关键字存放到Set集合中
            Set<String> set = map.keySet();
            // 读取模板文档
            XWPFDocument document = new XWPFDocument(new FileInputStream(filePath ));
            /**
             * 替换段落中的指定文字
             */
            // 读取文档中的段落,回车符为一个段落。
            // 同一个段落里面会被“:”等符号隔开为多个对象
            Iterator<XWPFParagraph> itPara = document.getParagraphsIterator();
            while (itPara.hasNext()) {
                // 获取文档中当前的段落文字信息
                XWPFParagraph paragraph = (XWPFParagraph) itPara.next();
                List<XWPFRun> run = paragraph.getRuns();
                // 遍历段落文字对象
                for (int i = 0; i < run.size(); i++) {
                    // 获取段落对象
                    if (run.get(i) == null) {	//段落为空跳过
                        continue;
                    }
                    String sectionItem = run.get(i).getText(run.get(i).getTextPosition());						 //段落内容
                    //System.out.println("替换前 === "+sectionItem);
                    // 遍历自定义表单关键字,替换Word文档中的内容
                    Iterator<String> iterator = set.iterator();
                    while (iterator.hasNext()) {
                        // 当前关键字
                        String key = iterator.next();
                        // 替换内容
                        sectionItem = sectionItem.replace(key, 	String.valueOf(map.get(key)));
                    }
                    //System.out.println(sectionItem);
                    run.get(i).setText(sectionItem, 0);
                }
            }

            /**
             * 替换表格中的指定文字
             */
            //获取文档中所有的表格,每个表格是一个元素
            Iterator<XWPFTable> itTable = document.getTablesIterator();
            while (itTable.hasNext()) {
                XWPFTable table = (XWPFTable) itTable.next();   //获取表格内容
                int count = table.getNumberOfRows();    //表格的行数
                //遍历表格行的对象
                for (int i = 0; i < count; i++) {
                    XWPFTableRow row = table.getRow(i);    //表格每行的内容
                    List<XWPFTableCell> cells = row.getTableCells();   //每个单元格的内容
                    //遍历表格的每行单元格对象
                    for (int j = 0; j < cells.size(); j++) {
                        XWPFTableCell cell = cells.get(j);	//获取每个单元格的内容
                        List<XWPFParagraph> paragraphs = cell.getParagraphs();      //获取单元格里所有的段落
                        for (XWPFParagraph paragraph : paragraphs) {
                            //获取段落的内容
                            List<XWPFRun> run = paragraph.getRuns();
                            // 遍历段落文字对象
                            for (int o = 0; o < run.size(); o++) {
                                // 获取段落对象
                                if (run.get(o) == null || run.get(o).equals("")) {
                                    continue;
                                }
                                String sectionItem = run.get(o).getText(run.get(o).getTextPosition());	//获取段落内容
                                if (sectionItem == null || sectionItem.equals("")) {	//段落为空跳过
                                    continue;
                                }
                                //遍历自定义表单关键字,替换Word文档中表格单元格的内容
                                for (String key : map.keySet()) {
                                    // 替换内容
                                    sectionItem = sectionItem.replace(key, String.valueOf(map.get(key)));
                                    run.get(o).setText(sectionItem, 0);
                                }
                            }
                        }
                    }
                }
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String datetime = sdf.format(new Date());
            response.setStatus(200);
            response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode("模板-"+datetime+".docx", "UTF-8"));
            response.setCharacterEncoding("utf8");
            OutputStream outStream = response.getOutputStream();
            //这里将插入转换成PDF的代码
            outStream.close();
            document.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

上面就是别人之前业务场景中的转换word的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1289307.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

挂耳式蓝牙耳机性价比排行榜吗,排名靠前的几款耳机推荐

当涉及挂耳式蓝牙耳机的选择时&#xff0c;消费者常常陷入选择困境&#xff0c;面对市场上琳琅满目的产品&#xff0c;很难找到性价比兼具的理想之选&#xff0c;为了帮助大家在众多选择中快速定位高性价比的耳机&#xff0c;我们精心整理了一份挂耳式蓝牙耳机性价比排行榜&…

javaWebssh图书系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

系统前景 图书有很多&#xff0c;老的图书书的管理靠纸介质&#xff0c;浪费人力和物力&#xff0c;给图书管理者带来极大的资源浪费。随着计算机信息化的普及&#xff0c;对图书的管理带来本质的改变&#xff0c;图书的销售情况以及&#xff0c;图书管理&#xff0c;以及年终对…

搜不到你想找的资料?那是你还没有掌握这些搜索技巧

文章目录 Google搜索命令sitefiletypeintitleinauthor:define:related:OR:- (减号):.. (两个点):weather:stocks:movie:link: 示例site:filetype:intitle:inauthor:define:related:OR:- (减号):.. (两个点):*** (星号):**cache:info:weather:stocks:movie:link: 补充 Google搜索…

解析操作系统是如何启动起来的?

操作系统被称为“第一个程序”&#xff0c;the first programme&#xff0c;原因很简单&#xff0c;只有当操作系统启动起来后才能运行我们编写的程序&#xff0c;那么你有没有想过这个问题&#xff1a;操作系统是怎样启动起来的呢&#xff1f;实际上这个过程就像发射火箭一样有…

解决vue ssr服务端渲染运行时报错:net::ERR_PROXY_CONNECTION_FAILED

现象&#xff1a; 从代码里找了半天也没有找到问题&#xff0c;但是由于ssr服务端渲染配置本身非常复杂&#xff0c;步骤又繁琐&#xff0c; 而且报错又很多&#xff0c;不知道哪里出了问题。 感觉是header或者cookie丢失造成的&#xff0c;因为据说ssr本身有这样的缺陷&…

NHN和SuiFrens合作的限量版配饰正式发售

SuiFrens那些可爱、富有想象力的生物&#xff0c;即将迎来全新装扮&#xff0c;而你也可以一同享受。今天&#xff0c;限量版NHN x SuiFrens Pebble City幸运配饰系列正式推出&#xff0c;同时还有机会在SuiFrens商店免费领取独家限量版NHN帽子。 NHN x SuiFens Pebble City配饰…

17、pytest自动使用fixture

官方实例 # content of test_autouse_fixture.py import pytestpytest.fixture def first_entry():return "a"pytest.fixture def order():return []pytest.fixture(autouseTrue) def append_first(order, first_entry):return order.append(first_entry)def test_s…

CVE初探之漏洞反弹Shell(CVE-2019-6250)

概述 ZMQ(Zero Message Queue)是一种基于消息队列得多线程网络库&#xff0c;C编写&#xff0c;可以使得Socket编程更加简单高效。 该编号为CVE-2019-6250的远程执行漏洞&#xff0c;主要出现在ZMQ的核心引擎libzmq(4.2.x以及4.3.1之后的4.3.x)定义的ZMTP v2.0协议中。 这一…

调试文心大模型或chatgpt的function Calling函数应用场景

沉默了一段时间&#xff0c;最近都在研究AI大模型的产品落地应用&#xff0c;我觉得这个function calling出来后&#xff0c;对目前辅助办公有革命性的改变&#xff0c;可以它来做什么呢&#xff1f;我们先来调试看看&#xff0c;chatgpt和文心大模型的ERNIE Bot支持这个&#…

电力智慧运维系统

电力智慧运维系统是以提高用户侧电力运行安全&#xff0c;降低运维成本为目标&#xff1b;采用智能化运维管理工具—“电易云”&#xff0c;帮助企业建立电力运维体系全方位的信息化、数字化平台&#xff0c;实现设备运行的数字化在线监控与线下维护处理的有机融合&#xff0c;…

在线学习平台-项目搭建

ER图: 外面的圆圈是外键(外键建在多的一边) 平台搭建: 参考这篇博客:若依的基本使用 测试: 先随便写一个测试的控制层看看项目是否搭建成功 调用验证码接口拿到uuid和token 更改token有效时长 之和的请求都需要带上token,测试时可以把token设置长一些 继承插件 需要什么…

C语言能判断一个变量是int还是float吗?

C语言能判断一个变量是int还是float吗&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「C语言从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家&#xff01;&…

HXDSP2441-HXD-PRO(CPU)在线仿真器

HXD-PRO&#xff08;CPU&#xff09;在线仿真器 CPU下载器具体使用方法参考《HXD-PRO在线仿真器使用手册》&#xff0c;需要注意的是&#xff0c;CPU下载器在PLL初始化后才可以正常连接。

体育场找座位 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题目描述 在一个大型体育场内举办了一场大型活动&#xff0c;由于疫情防控的需要&#xff0c;要求每位观众的必须间隔至少一个空位才允许落座。现在给出一排观众座位分布图&#xff0c;座位中存在已落座的观众&…

阅读笔记——《Hopper: Interpretative Fuzzing for Libraries》

【参考文献】Zhan Q, Fang R, Bindu R, et al. Removing RLHF Protections in GPT-4 via Fine-Tuning[J]. arXiv preprint arXiv:2311.05553, 2023.【注】本文仅为作者个人学习笔记&#xff0c;如有冒犯&#xff0c;请联系作者删除。 目录 摘要 一、介绍 二、背景 1、库的模…

代码随想录算法训练营第五十七天 | 647. 回文子串,516.最长回文子序列,动态规划总结篇

目录 647. 回文子串 516.最长回文子序列 动态规划总结篇 647. 回文子串 题目链接&#xff1a;647. 回文子串 &#xff08;1&#xff09;dp[ i ][ j ] 表示从 i 到 j 的字符串是否为回文子串&#xff1b; &#xff08;2&#xff09;若 s[ i ] s[ j ] 若 j - i < 1 dp…

QT-在ui界面中给QWidget增加Layout布局的两种方法

QT-在ui界面中给QWidget增加Layout布局的两种方法 方式一 在UI界面&#xff0c;用拖拽的方式加入Layout方式二 用notepad软件打开.ui文件&#xff0c;手动加入Layout代码 目标&#xff1a;去除右下角红标&#xff0c;给tab标签增加Layout属性。 方式一 在UI界面&#xff0c;用…

我一人全干!之二,vue3后台管理系统树形目录的实现。

一个完整的后台管理系统需要一个树形结构的目录&#xff0c;方便用户切换页面。 因为使用的是element-plus的ui库&#xff0c;所以首选el-menu组件&#xff0c;点击查看文档。 因为此组件不是树形结构的&#xff0c;所以需要封装成系统需要的树形结构组件。可以使用vue的递归组…

Docker架构、镜像操作和容器操作

一、docker基本管理和概念 1、概念 docker&#xff1a;开源的应用容器引擎。基于go语言开发的。运行在Linux系统中的开源的轻量级的“虚拟机” docker的容器技术可用在一台主机上轻松到达为任何应用创建一个轻量级到的&#xff0c;可移植的&#xff0c;自给自足的容器 dock…

微信小程序收款手续费怎么搞成0.2

今天&#xff0c;我将分享如何有效地降低日常中的收款手续费率。我们都知道&#xff0c;不管是微信支付还是支付宝&#xff0c;平台都会从中扣除一定的手续费。但你是否知道&#xff0c;其实手续费率是可以降低的呢&#xff1f;今天介绍如何申请最低手续费率为0.2%的方法&#…