Java 将word转为PDF的三种方式和处理在服务器上下载后乱码的格式
我这边是因为业务需要将之前导出的word文档转换为PDF文件,然后页面预览下载这样的情况。之前导出word文档又不是我做的,所以为了不影响业务,只是将最后在输出流时转换成了PDF,当时本地调用没什么问题,一切正常,后面发布测试环境使用时才发现,导出时PDF文件内容乱码了,中文没有一个显示的。
这里记录下当时遇到的问题和解决方式:
1:解决中文不显示,乱码处理情况
我这里是使用的POI进行的转换,直接将word转换成PDF,转换方式放在后面。
当时转换后的PDF长这样:
正常格式下是有很多中文说明的。下面就是处理方式:
当时就想到了是服务器上不支持中文,所以百度了一圈,果然是,然后就开始加中文字体:
Linux 服务器上字体目录是在:/user/share/fonts 下的
1:在/user/share/fonts 下创建自己的文件夹字体,我这里是my-fonts
如果这里找不到的话,可以使用命令 fc-list
查看一下有没有,如果没有或者出现该命令不可用的情况,那就需要先安装基础字体:使用命令:yum -y install fontconfig
,完成之后就能看到/user/share/fonts 了
2:找到Windows中的字体,将字体上传到这个 my-fonts中
这里面有很多字体,我们需要的是中文字体,可以选择性上传,选择需要的中文字体上传,比如宋体,要和你文件模板中字体一致就行。上传到my-fonts文件夹下
3:安装
接着根据当前目录下的字体建立scale文件,
切换到my-fonts目录下执行命令:mkfontscale
若提示mkfontscale command not found
,则运行yum install mkfontscale
接着建立dir文件:mkfontdir
使用命令:vi /etc/fonts/fonts.conf
修改配置文件,添加:<dir>/usr/share/fonts/my-fonts</dir>
添加后:
然后运行: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转换为InputStreamByteArrayOutputStream 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转换为InputStreamByteArrayOutputStream 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的代码。
相关文章:

Java 将word转为PDF的三种方式和处理在服务器上下载后乱码的格式
我这边是因为业务需要将之前导出的word文档转换为PDF文件,然后页面预览下载这样的情况。之前导出word文档又不是我做的,所以为了不影响业务,只是将最后在输出流时转换成了PDF,当时本地调用没什么问题,一切正常…...
C\C++ 获取最值
C C 语言的不同类型的最值可以在 limits.h 头文件里找到定义 #include <limits.h>int main() {printf("%d", INT_MAX); // 整数最大值printf("%d", INT_MIN); // 整数最小值 } C C 有模板,可以通过替换下面的 int 和 doubleÿ…...

机器学习之无监督学习:九大聚类算法
今天,和大家分享一下机器学习之无监督学习中的常见的聚类方法。 今天,和大家分享一下机器学习之无监督学习中的常见的聚类方法。 在无监督学习中,我们的数据并不带有任何标签,因此在无监督学习中要做的就是将这一系列无标签的数…...

Linux高级管理-搭建网站服务
在Ihternet 网络环境中,Web 服务无疑是最为流行的应用系统。有了Web站点,企业可以充分 展示自己的产品,宣传企业形象。Web站点还为企业提供了与客户交流、电子商务交易平台等丰富 的网络应用。部署与维护Web 服务是运维工程师必须掌握的一个技…...

Windows 系统,TortoiseSVN 无法修改 Log 信息解决方法
使用SVN提交版本信息时,注释内容写的不全。通过右键TortoiseSVN的Show log看到提交的的注释,右键看到Edit log message的选项,然而提交后却给出错误提示: Repository has not been enabled to accept revision propchanges; ask …...

编译 Android gradle-4.6-all.zip 报错问题记录
编译 Android gradle-4.6-all.zip 报错问题记录 方法一:替换资源:方法二:修改源方法三:修改版本 编译时候无法下载 gradle-4.6-all Downloading https://services.gradle.org/distributions/gradle-4.6-all.zip 方法一…...

Linux系统调试课:Valgrind 内存调试
文章目录 一、为什么要学会Valgrind二、什么是内存泄露三、Valgrind的移植四、Valgrind相关参数沉淀、分享、成长,让自己和他人都能有所收获!😄 📢Valgrind 是一个开源的内存调试和性能分析工具,用于帮助开发者找出程序中的内存错误,如内存泄漏、使用未初始化的内存、非…...

python主流开发工具排名,python开发工具有哪些
本篇文章给大家谈谈python的开发工具软件有哪些,以及python主流开发工具排名,希望对各位有所帮助,不要忘了收藏本站喔。 python中用到哪些软件 一、Python代码编辑器1、sublime Textsublime Text是一款非常流行的代码编辑器,支持P…...

Spring Boot Async:从入门到精通,原理详解与最佳实践
Spring Boot 的异步功能(Async)允许我们将某些任务异步执行,而不会阻塞主线程。这对于处理耗时的操作非常有用,如发送电子邮件、生成报表、调用外部 API 等。通过异步处理,我们可以释放主线程,让它继续处理…...
oracle 19c创建db_link名称带.com域名问题处理
文章目录 一、修改PDB的global_name二、重启数据库实例三、修改domain后重试 一、修改PDB的global_name SYSorcl1>sho pdbsCON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ----------2 PDB$SEED …...

银行卡二要素API的应用案例:从在线购物到金融投资
引言 随着互联网技术的不断发展,人们的金融需求也在不断增加。随之而来的是各种新型金融服务的涌现,让用户的金融体验更加便利快捷。其中,银行卡二要素API的应用,则为用户的金融体验和安全性提供了极大的保障。 银行卡二要素API…...

MySQL 忘记root密码后重置密码操作
在忘记 MySQL 密码的情况下,可以通过 --skip-grant-tables 关闭服务器的认证,然后重置 root 的密码,具体操作步骤如下。 步骤 1):关闭正在运行的 MySQL 服务。打开 cmd 进入 MySQL 的 bin 目录。 步骤 2):输入mysqld -…...

开源电子合同签署平台小程序源码/电子文件签字+在线合同签署系统源码/电子合同小程序源码
源码简介: 开源电子合同签署平台小程序源码,它是电子文件签字在线合同签署系统源码/电子合同小程序源码 目前商业端和开源端一致,免费开源状态! 聚合市场上各类电子合同解决方案商,你无需一个一个的对接电子合同厂商…...

J.408之数据结构
J-408之数据结构_北京信息科技大学第十五届程序设计竞赛(同步赛) (nowcoder.com) 思维好题,直接用两个set存没出现的数字就好了 // Problem: 408之数据结构 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/68572/J // Me…...
前端食堂技术周刊第 107 期:技术播客节、Deno Cron、FEDAY、XState v5、Electron 2023 生态系统回顾
美味值:🌟🌟🌟🌟🌟 口味:烤椰拿铁 食堂技术周刊仓库地址:https://github.com/Geekhyt/weekly 大家好,我是童欧巴。欢迎来到前端食堂技术周刊,我们先来看下…...

三防平板|手持终端PDA|8寸/10寸工业三防平板电脑主板方案定制
近年来,随着科技的快速发展,三防平板成为了各行各业中不可或缺的工具。三防平板采用IP67级别的防护设计,通过了多项测试标准,如国标和美标,具备防水、防摔、防尘、防撞、防震、防跌落以及防盐雾等多重防护功能。因此&a…...

【C语言】动态内存管理(C语言的难点与精华,数据结构的前置知识,你真的掌握了吗?)
文章目录 引言一、为什么要动态内存分配二、动态内存分配的相关函数2.1 malloc2.2 free2.3 calloc2.4 realloc 三、常见的动态内存的错误3.1 对NULL指针的解引用3.2 对动态内存越界访问3.3 对非动态内存释放3.4 对动态内存部分释放3.5 对动态内存多次释放3.6 未对动态内存释放&…...

最长子序列问题(LCS)--动态规划解法
题目描述: 如果Z既是X的子序列,又是Y的子序列,则称Z为X和Y的公共子序列。 如果给定X、Y,求出Y及其长度。 示例: 输入 ABCPDSFJGODIHJOFDIUSHGD OSDIHGKODGHBLKSJBHKAGHI 输出 SDIHODSHG 9 分析: c…...

实时流式计算 kafkaStream
文章目录 实时流式计算Kafka StreamKafka Streams 的关键概念KStreamKafka Stream入门案例编写SpringBoot 集成 Kafka Stream 实时流式计算 一般流式计算会与批量计算相比较 流式计算就相当于上图的右侧扶梯,是可以源源不断的产生数据,源源不断的接收数…...

西南科技大学模拟电子技术实验七(集成运算放大器的非线性应用)预习报告
一、计算/设计过程 说明:本实验是验证性实验,计算预测验证结果。是设计性实验一定要从系统指标计算出元件参数过程,越详细越好。用公式输入法完成相关公式内容,不得贴手写图片。(注意:从抽象公式直接得出结果,不得分,页数可根据内容调整) 预习计算内容根据运放的非线…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...