当前位置: 首页 > 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;这个问题之前其实困…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

mac:大模型系列测试

0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何&#xff0c;是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试&#xff0c;是可以跑通文章里面的代码。训练速度也是很快的。 注意…...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...