您现在的位置是:首页 > 名人名句

Java / Spring Boot + POI 给 Word 添加水印

作者:焦糖时间:2024-05-15 14:45:05分类:名人名句

简介  文章浏览阅读1.3k次,点赞10次,收藏17次。Java / Spring Boot给 Word 文档添加水印代码示例_xwpfdocument全文水印

点击全文阅读

1、前言(瞎扯)

有个需求:整一个给 Word 加水印的demo,于是我就网上找呗~
看到那个 Aspose 好像是收费的,然后就把目光转向了 POI,看到各种形形色色的也不知道哪个能用。整了一会,自己拷贝出一个比较精简的能用的 demo 了。

2、人狠话不多,上效果图

我一般都是直接上图的,先看效果图(每一页都有的):

水印的分布如果不理想,只能小伙伴们自行研究调整了~

在这里插入图片描述

3、人狠话不多,直接来代码

3.1、我的代码结构

目录结构

3.2 、直接贴代码了

pom 依赖的版本不要改,修改版本可能会导致一些东西缺失
代码你们可以直接复制这里的使用
或者在码云仓库:点击这里跳转

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";    /** 一个字平均长度,单位pt,用于:计算文本占用的长度(文本总个数*单字长度)*/    private static final Integer WIDTH_PER_WORD = 10;    /** 与顶部的间距 */    private static Integer STYLE_TOP = 0;    /** 文本旋转角度 */    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("添加水印成功!,一共耗时" + (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个空格分隔        fingerText = fingerText + repeatString(" ", 8);        // 一行水印重复水印文字次数        fingerText = repeatString(fingerText, 10);        // 如果之前已经创建过 DEFAULT 的Header,将会复用        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");        // 设置形状样式(旋转,位置,相对路径等参数)        shape.setStyle(getShapeStyle(fingerText));        shape.setFillcolor(FONT_COLOR);        // 字体设置为实心        shape.setStroked(STTrueFalse.FALSE);        // 绘制文本的路径        CTTextPath shapeTextPath = shape.addNewTextpath();        // 设置文本字体与大小        shapeTextPath.setStyle("font-family:" + FONT_NAME + ";font-size:" + FONT_SIZE);        shapeTextPath.setString(fingerText);        CTPicture pict = ctr.addNewPict();        pict.set(group);    }    /**     * 构建Shape的样式参数     *     * @param fingerText     * @return     */    private static String getShapeStyle(String fingerText) {        StringBuilder sb = new StringBuilder();        // 文本path绘制的定位方式        sb.append("position: ").append("absolute");        // 计算文本占用的长度(文本总个数*单字长度)        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");        // 设置水印的间隔,这是一个大坑,不能用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();    }    /**     * 将指定的字符串重复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 完事~

拿去好好享用吧~
注意:大文档不确定是否有效,我没有大文档测试,如果那种几百页的文档请自行查看,据网友反馈大文档后面的生成不了水印(200页之后的)

点击全文阅读

郑重声明:

本站所有活动均为互联网所得,如有侵权请联系本站删除处理

我来说两句