SpringBoot+POI實(shí)現(xiàn)給word添加水印功能
1、前言
有個(gè)需求:整一個(gè)給 Word 加水印的demo,于是我就網(wǎng)上找唄~
看到那個(gè) Aspose 好像是收費(fèi)的,然后就把目光轉(zhuǎn)向了 POI,看到各種形形色色的也不知道哪個(gè)能用。整了一會,自己拷貝出一個(gè)比較精簡的能用的 demo 了。
2、人狠話不多,上效果圖
我一般都是直接上圖的,先看效果圖(每一頁都有的):
水印的分布如果不理想,只能小伙伴們自行研究調(diào)整了~

3、人狠話不多,直接來代碼
3.1、我的代碼結(jié)構(gòu)

3.2 、直接貼代碼了
3.2.1、pom 依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lyk</groupId>
<artifactId>springboot-word-finger</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-word-finger</name>
<description>springboot-word-finger</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2.2、處理工具類
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.stream.Stream;
/**
* @author: lyk
* @description: Word 添加水印工具類
**/
public class WatermarkUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(WatermarkUtil.class);
/** word字體 */
private static final String FONT_NAME = "宋體";
/** 字體大小 */
private static final String FONT_SIZE = "0.2pt";
/** 字體顏色 */
private static final String FONT_COLOR = "#d0d0d0";
/** 一個(gè)字平均長度,單位pt,用于:計(jì)算文本占用的長度(文本總個(gè)數(shù)*單字長度)*/
private static final Integer WIDTH_PER_WORD = 10;
/** 與頂部的間距 */
private static Integer STYLE_TOP = 0;
/** 文本旋轉(zhuǎn)角度 */
private static final String STYLE_ROTATION = "30";
/**
* @param inPutPath
* @param putPutPath
* @param fingerText
* @author: lyk
* @description: 添加水印入口方法
* @date: 2024/1/25 23:42
**/
public static void waterMarkDocXDocument(String inPutPath, String putPutPath, String fingerText) {
long beginTime = System.currentTimeMillis();
try (
OutputStream out = new FileOutputStream(putPutPath);
InputStream in = new FileInputStream(inPutPath);
OPCPackage srcPackage = OPCPackage.open(in);
XWPFDocument doc = new XWPFDocument(srcPackage)
) {
// 把整頁都打上水印
for (int lineIndex = -5; lineIndex < 20; lineIndex++) {
STYLE_TOP = 100 * lineIndex;
waterMarkDocXDocument(doc, fingerText);
}
// 輸出新文檔
doc.write(out);
LOGGER.info("添加水印成功!,一共耗時(shí)" + (System.currentTimeMillis() - beginTime) + "毫秒");
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InvalidFormatException e) {
throw new RuntimeException(e);
}
}
/**
* 為文檔添加水印
* @param doc 需要被處理的docx文檔對象
* @param fingerText 需要添加的水印文字
*/
public static void waterMarkDocXDocument(XWPFDocument doc, String fingerText) {
// 水印文字之間使用8個(gè)空格分隔
fingerText = fingerText + repeatString(" ", 8);
// 一行水印重復(fù)水印文字次數(shù)
fingerText = repeatString(fingerText, 10);
// 如果之前已經(jīng)創(chuàng)建過 DEFAULT 的Header,將會復(fù)用
XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
int size = header.getParagraphs().size();
if (size == 0) {
header.createParagraph();
}
CTP ctp = header.getParagraphArray(0).getCTP();
byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
byte[] rsidrDefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
ctp.setRsidP(rsidr);
ctp.setRsidRDefault(rsidrDefault);
CTPPr ppr = ctp.addNewPPr();
ppr.addNewPStyle().setVal("Header");
// 開始加水印
CTR ctr = ctp.addNewR();
CTRPr ctrpr = ctr.addNewRPr();
ctrpr.addNewNoProof();
CTGroup group = CTGroup.Factory.newInstance();
CTShapetype shapeType = group.addNewShapetype();
CTTextPath shapeTypeTextPath = shapeType.addNewTextpath();
shapeTypeTextPath.setOn(STTrueFalse.T);
shapeTypeTextPath.setFitshape(STTrueFalse.T);
CTLock lock = shapeType.addNewLock();
lock.setExt(STExt.VIEW);
CTShape shape = group.addNewShape();
shape.setId("PowerPlusWaterMarkObject");
shape.setSpid("_x0000_s102");
shape.setType("#_x0000_t136");
// 設(shè)置形狀樣式(旋轉(zhuǎn),位置,相對路徑等參數(shù))
shape.setStyle(getShapeStyle(fingerText));
shape.setFillcolor(FONT_COLOR);
// 字體設(shè)置為實(shí)心
shape.setStroked(STTrueFalse.FALSE);
// 繪制文本的路徑
CTTextPath shapeTextPath = shape.addNewTextpath();
// 設(shè)置文本字體與大小
shapeTextPath.setStyle("font-family:" + FONT_NAME + ";font-size:" + FONT_SIZE);
shapeTextPath.setString(fingerText);
CTPicture pict = ctr.addNewPict();
pict.set(group);
}
/**
* 構(gòu)建Shape的樣式參數(shù)
*
* @param fingerText
* @return
*/
private static String getShapeStyle(String fingerText) {
StringBuilder sb = new StringBuilder();
// 文本path繪制的定位方式
sb.append("position: ").append("absolute");
// 計(jì)算文本占用的長度(文本總個(gè)數(shù)*單字長度)
sb.append(";width: ").append(fingerText.length() * WIDTH_PER_WORD).append("pt");
// 字體高度
sb.append(";height: ").append("20pt");
sb.append(";z-index: ").append("-251654144");
sb.append(";mso-wrap-edited: ").append("f");
// 設(shè)置水印的間隔,這是一個(gè)大坑,不能用top,必須要margin-top。
sb.append(";margin-top: ").append(STYLE_TOP);
sb.append(";mso-position-horizontal-relative: ").append("page");
sb.append(";mso-position-vertical-relative: ").append("page");
sb.append(";mso-position-vertical: ").append("left");
sb.append(";mso-position-horizontal: ").append("center");
sb.append(";rotation: ").append(STYLE_ROTATION);
return sb.toString();
}
/**
* 將指定的字符串重復(fù)repeats次.
*/
private static String repeatString(String pattern, int repeats) {
StringBuilder buffer = new StringBuilder(pattern.length() * repeats);
Stream.generate(() -> pattern).limit(repeats).forEach(buffer::append);
return new String(buffer);
}
}
/**
* @author lyk
* @version 1.0
* @date 2024/1/25 23:16
* @description
*/
public class Main {
public static void main(String[] args) {
final String inPath = "src/main/java/com/lyk/finger/doc/aaaa.docx";
final String outPath = "src/main/java/com/lyk/finger/doc/out.docx";
// 添加水印
WatermarkUtil.waterMarkDocXDocument(inPath, outPath, "落魄程序員在線炒粉");
}
}
4、OK 完事~
到此這篇關(guān)于SpringBoot+POI實(shí)現(xiàn)給word添加水印功能的文章就介紹到這了,更多相關(guān)SpringBoot POI Word添加水印內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring boot使用thymeleaf跳轉(zhuǎn)頁面實(shí)例代碼
本篇文章主要介紹了spring boot使用thymeleaf跳轉(zhuǎn)頁面,實(shí)例介紹了thymeleaf的原理和介紹,有興趣的可以了解一下。2017-04-04
Spring Data JPA的Audit功能審計(jì)數(shù)據(jù)庫的變更
數(shù)據(jù)庫審計(jì)是指當(dāng)數(shù)據(jù)庫有記錄變更時(shí),可以記錄數(shù)據(jù)庫的變更時(shí)間和變更人等,這樣以后出問題回溯問責(zé)也比較方便,本文討論Spring Data JPA審計(jì)數(shù)據(jù)庫變更問題,感興趣的朋友一起看看吧2021-06-06
Spring Boot 配置隨機(jī)數(shù)的技巧代碼詳解
這篇文章主要介紹了Spring Boot 配置隨機(jī)數(shù)技巧,spring boot 支持在系統(tǒng)加載的時(shí)候配置隨機(jī)數(shù),具體實(shí)例代碼大家參考下本文2018-05-05
老生常談JVM的內(nèi)存溢出說明及參數(shù)調(diào)整
下面小編就為大家?guī)硪黄仙U凧VM的內(nèi)存溢出說明及參數(shù)調(diào)整。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03
SpringBoot實(shí)現(xiàn)ORM操作MySQL的幾種方法
本文主要介紹了SpringBoot實(shí)現(xiàn)ORM操作MySQL的幾種方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
手把手教你如何設(shè)計(jì)一套Java項(xiàng)目的Skill體系
Skill是一套模塊化的可復(fù)用能力包,其核心價(jià)值在于將特定任務(wù)的專業(yè)流程、可執(zhí)行邏輯與資源模板進(jìn)行標(biāo)準(zhǔn)化封裝,這篇文章主要介紹了如何設(shè)計(jì)一套Java項(xiàng)目Skill體系的相關(guān)資料,需要的朋友可以參考下2026-05-05
關(guān)于SpringBoot使用@Async的總結(jié)
這篇文章主要介紹了關(guān)于SpringBoot使用@Async的總結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

