赣州做网站推广,做百度推广网站多少钱,网站春节放假,百度指数搜索榜度指数1、前言(瞎扯) 有个需求#xff1a;整一个给 Word 加水印的demo#xff0c;于是我就网上找呗~ 看到那个 Aspose 好像是收费的#xff0c;然后就把目光转向了 POI#xff0c;看到各种形形色色的也不知道哪个能用。整了一会#xff0c;自己拷贝出一个比较精简的能用的 demo …1、前言(瞎扯) 有个需求整一个给 Word 加水印的demo于是我就网上找呗~ 看到那个 Aspose 好像是收费的然后就把目光转向了 POI看到各种形形色色的也不知道哪个能用。整了一会自己拷贝出一个比较精简的能用的 demo 了。 2、人狠话不多上效果图
我一般都是直接上图的先看效果图每一页都有的 水印的分布如果不理想只能小伙伴们自行研究调整了~ 3、人狠话不多直接来代码
3.1、我的代码结构 3.2 、直接贴代码了 pom 依赖的版本不要改修改版本可能会导致一些东西缺失 代码你们可以直接复制这里的使用 或者在码云仓库点击这里跳转 3.2.1、pom 依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.2.2/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.lyk/groupIdartifactIdspringboot-word-finger/artifactIdversion0.0.1-SNAPSHOT/versionnamespringboot-word-finger/namedescriptionspringboot-word-finger/descriptionpropertiesjava.version17/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.jsoup/groupIdartifactIdjsoup/artifactIdversion1.11.2/version/dependencydependencygroupIdorg.apache.poi/groupIdartifactIdpoi/artifactIdversion4.1.0/version/dependencydependencygroupIdorg.apache.poi/groupIdartifactIdpoi-scratchpad/artifactIdversion4.1.0/version/dependencydependencygroupIdorg.apache.poi/groupIdartifactIdpoi-ooxml/artifactIdversion4.1.0/version/dependencydependencygroupIdorg.apache.poi/groupIdartifactIdpoi-ooxml-schemas/artifactIdversion4.1.0/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-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 完事~ 拿去好好享用吧~