使用Apache POI添加Word文字水印:createWatermark未显示斜灰文本
解决Apache POI
createWatermark 水印样式不生效的问题 我之前也踩过这个坑!createWatermark 方法看似省心,但在不同POI版本、不同Word文档格式(.doc vs .docx)下经常会出现斜体灰色样式不显示的情况,甚至连水印本身都可能失踪。下面是几个我亲测有效的解决思路:
1. 先排查版本和文档格式兼容性
- 如果你用的是POI 3.x版本,对.docx格式的水印支持非常有限,
createWatermark生成的样式几乎都会失效,建议直接升级到POI 4.x及以上版本(目前稳定版是5.x)。 - 如果你处理的是旧版.doc格式(HWPF),
createWatermark的行为本来就不稳定,别纠结默认方法,直接看下面的手动实现方案。
2. 手动构建自定义样式的水印(最可靠)
默认的createWatermark 会硬编码一些样式,但很多时候没正确应用到文档里。不如手动创建页眉段落,精细控制字体样式和位置:
import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; // 假设你已经创建了XWPFDocument实例 XWPFDocument doc = new XWPFDocument(); // 获取或创建页眉页脚策略 XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy(); if (headerFooterPolicy == null) { headerFooterPolicy = doc.createHeaderFooterPolicy(); } XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT); // 创建水印专用段落 XWPFParagraph watermarkPara = header.createParagraph(); watermarkPara.setAlignment(ParagraphAlignment.CENTER); // 水平居中 // 设置段落垂直居中(让水印在页眉区域居中显示) CTP ctp = watermarkPara.getCTP(); CTPPr ppr = ctp.getPPr() != null ? ctp.getPPr() : ctp.addNewPPr(); CTVerticalJc verticalJc = ppr.addNewVerticalJc(); verticalJc.setVal(STVerticalJc.CENTER); // 创建文本运行并设置样式 XWPFRun run = watermarkPara.createRun(); run.setText("Watermark"); run.setItalic(true); // 斜体 run.setColor("808080"); // 灰色(RGB值) run.setFontSize(48); // 大字号更像水印 run.setTextPosition(180); // 调整垂直位置,避免和页眉内容重叠 // 可选:添加文字旋转效果(模拟传统水印的倾斜) CTText ctText = run.getCTR().getTArray(0); CTRPr rPr = run.getCTR().getRPr() != null ? run.getCTR().getRPr() : run.getCTR().addNewRPr(); CTTextEffect textEffect = rPr.addNewTextEffect(); textEffect.setRot("15"); // 旋转15度,可根据需要调整
这个方法能完全掌控水印的样式,几乎不会出现样式丢失的问题。
3. 针对.doc格式的特殊处理
如果是处理旧版.doc(HWPF)文档,需要用形状来实现水印:
import org.apache.poi.hwpf.usermodel.*; import org.apache.poi.hwpf.usermodel.ShapeTypes; HWPFDocument doc = new HWPFDocument(); HeaderStories headerStories = doc.getHeaderStories(); Range headerRange = headerStories.getHeader(); // 创建文本框形状作为水印容器 Shape watermarkShape = new Shape(doc, ShapeTypes.TEXT_BOX); watermarkShape.setHorizontalPosition(250); // 水平位置 watermarkShape.setVerticalPosition(200); // 垂直位置 watermarkShape.setWidth(500); watermarkShape.setHeight(150); watermarkShape.setRotation(30); // 倾斜30度 // 向形状中添加水印文本 Paragraph shapePara = watermarkShape.addNewParagraph(); CharacterRun cr = shapePara.addNewCharacterRun(); cr.setText("Watermark"); cr.setItalic(true); cr.setColor("808080"); cr.setFontSize(24); // 将形状插入页眉 headerRange.insertAfter(watermarkShape);
4. 验证文档的打开方式
有时候水印在WPS中显示正常,但在Microsoft Word里异常,反之亦然。建议用Microsoft Word打开生成的文档进行验证,因为POI是针对Word格式标准开发的,第三方软件的解析可能存在差异。
如果还是不行,检查一下你的Maven/Gradle依赖,确保poi和poi-ooxml的版本一致,避免依赖冲突导致的奇怪问题。
内容的提问来源于stack exchange,提问作者user2223296




