当前位置: 首页 > news >正文

Java 使用 poi 和 aspose 实现 word 模板数据写入并转换 pdf 增加水印

本项目所有源码和依赖资源都在文章顶部链接,有需要可以下载使用

1. 需求描述


  1. 从指定位置读取一个 word 模板
  2. 获取业务数据并写入该 word 模板,生成新的 word 文档
  3. 将新生成的 word 文档转换为 pdf 格式
  4. 对 pdf 文档添加水印

2. 效果预览


  1. word 模板
    在这里插入图片描述
  2. 带水印的 pdf 文档
    在这里插入图片描述

3. 实现思路


  • word 模板数据写入:使用 poi-tl 库实现
  • word 转 pdf 格式:aspose-words 库实现
  • pdf 增加水印:aspose-pdf 库实现

4. 实现过程


4.1 依赖库准备

poi-tl 可以使用 maven 直接从中央仓库下载,但是 aspose 无法下载,需要从网上下载 jar 包并导入本地仓库

  • poi-tl

        <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version></dependency>
    
  • aspose-word
    将 jar 包导入本地仓库

        mvn install:install-file \-DgroupId="com.aspose" \-DartifactId="aspose-words" \-Dversion="15.8.0" \-Dpackaging="jar" \-Dfile="aspose-words-15.8.0-jdk16.jar"
    

    项目中添加依赖

        <dependency><groupId>com.aspose</groupId><artifactId>aspose-words</artifactId><version>15.8.0</version></dependency>
    
  • aspose-pdf
    将 jar 包导入本地仓库

        mvn install:install-file \-DgroupId="com.aspose" \-DartifactId="aspose-pdf" \-Dversion="17.8" \-Dpackaging="jar" \-Dfile="aspose.pdf-17.8.jar"
    

    项目中添加依赖

        <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId><version>17.8</version></dependency>
    
  • license.xml
    由于 aspose 库分为免费版和收费版,免费版导出的文档带有试用水印,所以需要添加 license.xml,版权关系不在文章中写出,有需要的可以下载文章顶部链接的完整源码包。

4.2 核心实现方法
@SpringBootApplication
public class Word2PDFApplication {public static void main(String[] args) {SpringApplication.run(Word2PDFApplication.class, args);// word 模板String wordTemplatePath = "src/main/resources/templates/简历模板.docx";// 写入数据后的 wordString wordOutputPath = "src/main/resources/templates/简历模板-output.docx";// word 转换为 pdfString pdfOutputPath = "src/main/resources/templates/简历模板.pdf";// pdf 增加水印String pdfWithMarkerOutputPath = "src/main/resources/templates/简历模板-marker.pdf";// step 1: 封装模板数据Map<String, Object> dataMap = getPersonDataMap();// step 2: 将数据写入 word 模板writeDataToWord(dataMap, wordTemplatePath, wordOutputPath);// step 3: 将 word 转换为 pdfconvertWordToPdf(wordOutputPath, pdfOutputPath);// step 4: 将 pdf 增加水印addMarkerToPdf(pdfOutputPath, pdfWithMarkerOutputPath);}// 封装业务数据,用于填入模板对应占位符中private static Map<String, Object> getPersonDataMap() {Map<String, Object> personDataMap = new HashMap<>();personDataMap.put("name", "张三");personDataMap.put("sex", "男");personDataMap.put("birthDate", "1998-12-02");personDataMap.put("id", "420202199812020011");personDataMap.put("phone", "18819297766");personDataMap.put("skills", "java Spring MySQL ...");return personDataMap;}// 将业务数据写入 word 模板,并生成新的 word 文件private static void writeDataToWord(Map<String, Object> dataMap, String wordTemplatePath, String wordOutputPath) {XWPFTemplate render = XWPFTemplate.compile(wordTemplatePath).render(dataMap);File dest = new File(wordOutputPath);if (!dest.getParentFile().exists()) {dest.getParentFile().mkdirs();}try {render.writeToFile(wordOutputPath);} catch (IOException e) {throw new RuntimeException(e);}}// 将新生成的带有业务数据的 word 文档转换为 pdf 格式private static void convertWordToPdf(String wordOutputPath, String pdfOutputPath) {// 验证 License 若不验证则转化出的 pdf 文档带有水印if (!getAsposeWordLicense()) {return;}FileOutputStream os = null;try {long old = System.currentTimeMillis();File file = new File(pdfOutputPath);os = new FileOutputStream(file);Document doc = new Document(wordOutputPath);doc.save(os, SaveFormat.PDF);long now = System.currentTimeMillis();System.out.println("pdf转换成功,共耗时:" + ((now - old) / 1000.0) + "秒");} catch (Exception e) {e.printStackTrace();} finally {if (os != null) {try {os.flush();os.close();} catch (IOException e) {e.printStackTrace();}}}}// 对转换后的 pdf 文档添加水印效果private static void addMarkerToPdf(String pdfOutputPath, String pdfWithMarkerOutputPath) {// 验证 License 若不验证则增加水印后的 pdf 文档带有试用水印boolean asposePdfLicense = getAsposePdfLicense();if (!asposePdfLicense) {return;}com.aspose.pdf.Document pdfDocument = new com.aspose.pdf.Document(pdfOutputPath);TextStamp textStamp = new TextStamp("水印文本");textStamp.getTextState().setFontSize(14.0F);textStamp.getTextState().setFontStyle(FontStyles.Bold);textStamp.setRotateAngle(45);textStamp.setOpacity(0.2);// 设置水印间距float xOffset = 100;float yOffset = 100;// 添加水印到每一页for (Page page : pdfDocument.getPages()) {float xPosition = 0;float yPosition = 0;// 在页面上添加水印直到页面被覆盖while (yPosition < page.getRect().getHeight()) {textStamp.setXIndent(xPosition);textStamp.setYIndent(yPosition);page.addStamp(textStamp);xPosition += xOffset;// 如果水印超过页面宽度,移到下一行if (xPosition + textStamp.getWidth() > page.getRect().getWidth()) {xPosition = 0;yPosition += yOffset;}}}// 保存修改后的文档pdfDocument.save(pdfWithMarkerOutputPath);}// 验证 license,否则有试用水印private static boolean getAsposeWordLicense() {boolean result = false;InputStream is = null;try {ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();org.springframework.core.io.Resource[] resources = resolver.getResources("classpath:license.xml");is = resources[0].getInputStream();License asposeLic = new License();asposeLic.setLicense(is);result = true;} catch (Exception e) {e.printStackTrace();} finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}return result;}// 验证 license,否则有试用水印private static boolean getAsposePdfLicense() {boolean result = false;InputStream is = null;try {ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();org.springframework.core.io.Resource[] resources = resolver.getResources("classpath:license.xml");is = resources[0].getInputStream();com.aspose.pdf.License asposeLic = new com.aspose.pdf.License();asposeLic.setLicense(is);result = true;} catch (Exception e) {e.printStackTrace();} finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}return result;}
}

相关文章:

Java 使用 poi 和 aspose 实现 word 模板数据写入并转换 pdf 增加水印

本项目所有源码和依赖资源都在文章顶部链接&#xff0c;有需要可以下载使用 1. 需求描述 从指定位置读取一个 word 模板获取业务数据并写入该 word 模板&#xff0c;生成新的 word 文档将新生成的 word 文档转换为 pdf 格式对 pdf 文档添加水印 2. 效果预览 word 模板 带水印的…...

Spring Boot进阶(93):体验式教程:手把手教你整合Spring Boot和Zipkin

&#x1f4e3;前言 分布式系统开发中&#xff0c;服务治理是一个比较重要的问题。为了更好地实现服务治理&#xff0c;需要解决服务跟踪问题&#xff0c;即如何对分布式系统中的服务进行监控和追踪。本文将介绍如何使用Zipkin进行服务跟踪&#xff0c;并结合Spring Boot进行整合…...

Lvs +keepalivede : 高可用集群

keepalived为Ivs应运而生的高可用服务。Ivs的调度器无法做高可用&#xff0c;于是keepalived这个软件。 实现的是调度器的高可用。 但是: keepalived不是专为Ivs集群服务的&#xff0c;也可以做其他代理服务器的高可用。 lvs的高可用集群&#xff1a;主调度器和备调度器&…...

得物 Redis 设计与实践yu

一、前言 自建 Redis 系统是得物 DBA 团队自研高性能分布式 KV 缓存系统&#xff0c;目前管理的 ECS 内存总容量超过数十TB&#xff0c;数百多个 Redis 缓存集群实例&#xff0c;数万多个 Redis 数据节点&#xff0c;其中内存规格超过 1T 的大容量集群多个。 自建 Redis 系统采…...

优咔科技创新连接方案助力高质量5G车联服务

上海优咔网络科技有限公司 CEO 闫楠 【摘要】本文就智能网联汽车对高质量5G车联服务的需求背景和行业趋势进行了分析&#xff0c;主要介绍采用5G双SIM卡的创新连接方案&#xff0c;重点讲述双SIM卡联网的端到端体系架构和技术方案&#xff0c;并就优咔科技全方位支撑行业领先车…...

(a /b)*c的值

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…...

Hive 常用DML操作

本专栏案例数据集链接: https://download.csdn.net/download/shangjg03/88478038 1.加载文件数据到表 1.1 语法 LOAD DATA [LOCAL] INPATH filepath [OVERWRITE] INTO TABLE</...

centos部署tomcat

Java Downloads | Oracle 上面是下载网址 Tomcat是由Apache开发的一个Servlet容器&#xff0c;实现了对Servlet和JSP的支持&#xff0c;并提供了作为Web服务器的一些特有功能&#xff0c;如Tomcat管理和控制平台&#xff0c;安全域管理和Tomcat阀 简单来说&#xff1a;Tomcat…...

【Spark】配置参数关系-重要

并行度数量 并行度指所有Executor可以同时执行的Task数&#xff0c; 每个Executor中的一个Core&#xff08;线程&#xff0c;虚拟核数&#xff09;同时只能执行一个Task&#xff0c; 所以 最大并行度 Executor数量 * 每个Executor的Core数&#xff1b; eg&#xff1a;资源配…...

[Qt之“MMM dd yyyyhh:mm:ss“]时间格式

这是时间格式字符串&#xff0c;用于表示日期和时间的显示格式。具体解释如下&#xff1a; “MMM”&#xff1a;表示月份的缩写&#xff0c;例如Jan、Feb、Mar等。“dd”&#xff1a;表示日期的两位数&#xff0c;例如01、02、03等。“yyyy”&#xff1a;表示年份的四位数&…...

SSM宾馆客房管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 宾馆客房管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统…...

永远在路上

今年的1024是自己过的第八个程序员节&#xff0c;虽然没有放假&#xff0c;但是公司给每一个程序员都发了一个水果拼盘的福利&#xff0c;礼轻情意重吧&#xff01;毕竟有许多公司都欠薪的情况下&#xff0c;我们公司不仅按时发薪资&#xff0c;而且还有固定福利和节日福利&…...

JS递归函数详解

递归函数是一种在函数内部调用自身的编程技巧。通过不断地将问题分解为更小的子问题&#xff0c;递归函数可以处理复杂的任务&#xff0c;并提供简洁和可读性高的代码实现。 基本原理&#xff1a; 1.递归函数由两个主要部分组成&#xff1a;基准条件&#xff08;base case&…...

JS问题:如何实现文本一键复制和长按复制功能?

前端功能问题系列文章&#xff0c;点击上方合集↑ 序言 大家好&#xff0c;我是大澈&#xff01; 本文约2000字&#xff0c;整篇阅读大约需要4分钟。 本文主要内容分三部分&#xff0c;第一部分是需求分析&#xff0c;第二部分是实现步骤&#xff0c;第三部分是问题详解。 …...

react实现步进器

创建一个步进器组件&#xff0c;包含当前步骤&#xff08;currentStep&#xff09;的状态以及前进和后退的操作&#xff1a; import React, { useState } from react;function Stepper() {const [currentStep, setCurrentStep] useState(1);const handleNext () > {setCu…...

【jenkins】centos7在线安装jenkins

一、系统要求 最低推荐配置 256MB可用内存 1GB可用磁盘空间(作为一个Docker容器运行jenkins的话推荐10GB) 软件配置 Java 8—​无论是Java运行时环境&#xff08;JRE&#xff09;还是Java开发工具包&#xff08;JDK&#xff09;都可以 二、安装jenkins 准备一台安装有ce…...

Hive常用DDL操作

本专栏案例数据集链接: https://download.csdn.net/download/shangjg03/88478038 1. Database 1.1 查看数据库列表 show databases; 1.2 使用数据库 USE database_name;...

关于css中设置变量用于全局Css或者Js中使用

一、配置变量css文件 src/styles/variables.scss // 设置色值变量// 1、继承body中设置的样式内嵌style"--baseColor:#0075FF;" // 一般常用于Saas系统&#xff0c;如qiankun框架主应用决定子应用的样式 $primary: var(--baseColor, #0075FF); // 主色调&#xff0…...

Elasticsearch(十五)搜索---搜索匹配功能⑥--基于地理位置查询

一、前言 随着互联网的热门&#xff0c;越来越多的传统行业将全部或者部分业务转移到互联网上&#xff0c;其中不乏一些和地理位置强相关的行业。基于地理位置的搜索功能&#xff0c;大大提升了人们的生活和工作效率。例如&#xff0c;外出旅行时&#xff0c;只需要用手机打开…...

为什么axios会有params和data两个参数

不知道大家有没有过这种感觉&#xff0c;突然一个问题百思不得其解&#xff0c;然后突然有一天就明白了。然后就感觉这个问题原来这么简单&#xff0c;本来想记录下来&#xff0c;但是又感觉这么简单的问题记录下来没啥意义。但是回过头来想一想&#xff0c;这个问题之前其实困…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...