引言
在企业信息化办公中,文档的安全与版权保护至关重要。无论是内部流转的“机密”文件,还是对外发布的“初稿”样本,水印(Watermark) 都是最直观、成本最低的防护手段。
对于 Java 开发者而言,操作 Word 文档(.doc / .docx)往往是一件头疼的事。虽然 Apache POI 提供了底层支持,但其复杂的 API 常常让简单的格式调整变得异常艰难。今天,我们将探讨如何利用 Spire.Doc for Java 库,通过寥寥数行代码,实现专业级的水印添加功能。
一、 为什么选择 Spire.Doc for Java?
在 Java 生态中,处理 Word 的工具不少,但 Spire.Doc 脱颖而出主要基于以下几点:
- 独立性:无需在服务器上安装 Microsoft Word。
- 高保真度:转换 PDF 或打印时,水印位置不偏移。
- API 直观:将复杂的水印对象(VML 形状)封装成了简单的属性设置。
- 功能全面:支持文本平铺、图片透明度调整及多节(Section)独立设置。
二、 准备工作
首先,在你的 pom.xml 中引入必要的依赖。
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc</artifactId>
<version>14.3.1</version>
</dependency>
</dependencies>
三、 核心功能实现
1. 添加艺术文本水印
文本水印是最常见的需求。Spire.Doc 允许我们自定义字体、颜色、倾斜角度以及是否平铺。
import com.spire.doc.*;
import com.spire.doc.documents.WatermarkLayout;
import java.awt.*;
public class TextWatermark {
public static void main(String[] args) {
Document document = new Document();
document.loadFromFile("input.docx");
TextWatermark txtWatermark = new TextWatermark();
txtWatermark.setText("机密文件 - 禁止外传");
txtWatermark.setFontSize(45);
txtWatermark.setColor(new Color(255, 0, 0, 100)); // 使用半透明红色
txtWatermark.setLayout(WatermarkLayout.Diagonal);
document.setWatermark(txtWatermark);
document.saveToFile("TextWatermark.docx", FileFormat.Docx_2013);
}
}
2. 添加图片水印
图片水印通常用于添加公司 Logo。关键点在于缩放和冲蚀(Washout)效果,冲蚀能自动降低图片亮度和对比度,使其看起来更像背景。
import com.spire.doc.*;
public class ImageWatermark {
public static void main(String[] args) {
Document document = new Document();
document.loadFromFile("input.docx");
PictureWatermark picture = new PictureWatermark();
picture.setPicture("logo.png");
picture.setScaling(120);
picture.isWashout(true); // 设置冲蚀效果
document.setWatermark(picture);
document.saveToFile("ImageWatermark.docx", FileFormat.Docx_2013);
}
}
四、 进阶技巧:动态全屏平铺水印
标准的 Word 水印通常只在页面正中央显示一个。如果为了防截屏,我们需要实现全屏平铺(Tiled Watermark)。 由于 Word 本身对“平铺文本”的原生支持有限,最佳做法是利用**页眉(Header)**插入多个文本形状。通过 deepClone() 方法,我们可以高效地复用同一个形状模板并铺满全页。
示例代码:
import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.ShapeObject;
import java.awt.*;
public class WordWatermark {
public static void main(String[] args) {
// 加载示例文档
Document doc = new Document();
doc.loadFromFile("Sample.docx");
// 创建水印母版形状
ShapeObject shape = new ShapeObject(doc, ShapeType.Text_Plain_Text);
shape.setWidth(60);
shape.setHeight(20);
shape.setRotation(315);
shape.getWordArt().setFontFamily("宋体");
shape.getWordArt().setText("内部使用");
shape.setFillColor(new Color(192, 192, 192, 150)); // 设置半透明灰色
shape.setLineStyle(ShapeLineStyle.Single);
shape.setStrokeWeight(1);
// 遍历文档的所有 Section
for (int n = 0; n < doc.getSections().getCount(); n++) {
Section section = doc.getSections().get(n);
HeaderFooter header = section.getHeadersFooters().getHeader();
Paragraph paragraph = header.getParagraphs().getCount() > 0
? header.getParagraphs().get(0)
: header.addParagraph();
// 双重循环控制平铺的行数和列数
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3; j++) {
// 核心:克隆母版并设置网格化位置
ShapeObject clonedShape = (ShapeObject) shape.deepClone();
clonedShape.setVerticalPosition(50 + 150 * i);
clonedShape.setHorizontalPosition(20 + 160 * j);
paragraph.getChildObjects().add(clonedShape);
}
}
}
doc.saveToFile("result.docx", FileFormat.Docx_2013);
}
}
五、 常见问题与解决方案 (FAQ)
- 为什么水印在转 PDF 后消失了?
通常是因为添加层级不对。使用document.setWatermark()最稳妥。若手动添加 Shape,需确保设置VerticalOrigin.Page属性。 - 如何只给特定页面加水印?
Word 水印是基于节(Section)的。你可以使用document.getSections().get(index)获取特定节并仅操作该节的页眉。 - 性能优化建议
处理长文档时,请务必参考第四点中的deepClone()方式,避免重复通过构造函数创建新对象,这能大幅节省内存消耗。
六、 企业级应用场景
在实际生产中,我们可以结合后端业务逻辑动态生成水印:
- 动态用户信息:从 Session 获取当前登录人的姓名。
- 内容构造:拼接
"User: " + empName + " | " + LocalDate.now()。 - 流处理:使用
document.saveToStream()将生成的带水印文档直接推送到前端,实现无痕的安全下载。
结语
使用 Java 为 Word 添加水印不再是一项复杂的工程。借助 Spire.Doc,开发者可以将精力从底层的 VML/XML 结构中解脱出来,专注于业务逻辑的实现。