当前位置: 首页 > news >正文

网站建设及推广服务公司三亚旅游攻略

网站建设及推广服务公司,三亚旅游攻略,白城网站建设哪家好,网站如何维护在 Java 中使用 Apache POI 为 Word 文档添加水印 在日常办公中,我们经常需要给 Word 文档添加水印,以标明文件的机密性或归属权。本文将介绍如何使用 Apache POI 库在 Java 中给 Word 文档添加水印。 技术栈 Apache POI:用于操作 Word 文…

在 Java 中使用 Apache POI 为 Word 文档添加水印

在日常办公中,我们经常需要给 Word 文档添加水印,以标明文件的机密性或归属权。本文将介绍如何使用 Apache POI 库在 Java 中给 Word 文档添加水印。

技术栈
  • Apache POI:用于操作 Word 文档(.docx
  • VML(矢量标记语言):用于绘制水印文本
实现思路
  1. 读取 Word 文档
  2. 在页眉中插入水印
  3. 处理水印样式,如字体、颜色、透明度等
  4. 生成新文件并保存
代码实现

以下是一个完整的 WordWatermarkUtils 工具类,它支持向 .docx 文件中添加水印。

public class WordWatermarkUtils {private String customText; // 水印文字private String fontName = "微软雅黑"; // 字体private int fontSize = 14; // 字体大小private String fontColor = "#616161"; // 字体颜色private String styleRotation = "0"; // 旋转角度public WordWatermarkUtils(String customText) {this.customText = customText;}public void addWatermarkToDoc(XWPFDocument doc) {XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);CTP ctp = header.createParagraph().getCTP();CTR ctr = ctp.addNewR();CTGroup group = CTGroup.Factory.newInstance();CTShape shape = group.addNewShape();shape.setStyle(getShapeStyle());shape.setFillcolor(fontColor);shape.addNewTextpath().setString(customText);ctr.addNewPict().set(group);}private String getShapeStyle() {return "position:absolute;width:300pt;height:50pt;rotation:" + styleRotation + ";fill-opacity:0.3";}
}
如何使用
try (FileInputStream fis = new FileInputStream("input.docx");FileOutputStream fos = new FileOutputStream("output.docx")) {XWPFDocument doc = new XWPFDocument(fis);WordWatermarkUtils watermark = new WordWatermarkUtils("机密文件");watermark.addWatermarkToDoc(doc);doc.write(fos);
}
完整代码
package com.demo;import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import weaver.general.BaseBean;import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.UUID;/*** 微软office Word 水印机.*/
public class WordWatermarkUtils {private String customText; // 水印文字private String fontName = "微软雅黑"; // word字体private int fontSize = 14; // 字体大小private String fontColor = "#616161"; // 字体颜色private int widthPerWord = 3; // 一个字平均长度,单位pt,用于:计算文本占用的长度(文本总个数*单字长度)private String styleTop = "10pt"; // 与顶部的间距private String styleRotation = "0"; // 文本旋转角度,如果不需要旋转水印,保持为 0private String source; // 源文件路径private String dest = "D:\\WEAVER\\doc_tmp"; // 临时文件存储路径BaseBean bean = new BaseBean();public WordWatermarkUtils(String customText, String sourcePath) {customText = customText + repeatString(" ", 8); // 水印文字之间使用8个空格分隔this.customText = repeatString(customText, 1); // 一行水印重复水印文字次数this.source = sourcePath;}/*** 【核心方法】将输入流中的docx文档加载添加水印后输出到输出流中.** @param inputStream  docx文档输入流* @param //outputStream 添加水印后docx文档的输出流*/public String makeSlopeWaterMark(InputStream inputStream, String filename) throws IOException {// 创建临时文件Path tempFile = createTempFile(inputStream);if (tempFile == null || !Files.exists(tempFile) || Files.size(tempFile) == 0) {throw new RuntimeException("-------- 输入文件为空或者无法被创建");}Path sourcePath = Paths.get(this.source);  // 获取源文件路径Path destinationDir = Paths.get(this.dest); // 将原文件复制到临时目标文件夹路径// 确保目标文件夹存在if (!Files.exists(destinationDir)) {try {Files.createDirectories(destinationDir);} catch (IOException e) {throw new RuntimeException("-------- 无法创建目标文件夹: " + e);}}String unescapedFilenameString = StringEscapeUtils.unescapeHtml4(filename);// 转义字符复原String tmpFileName = unescapedFilenameString.substring(0, unescapedFilenameString.lastIndexOf(".")) + "_watermark.docx";Path tmpPath = destinationDir.resolve(tmpFileName); // 临时文件路径Files.copy(sourcePath, tmpPath, StandardCopyOption.REPLACE_EXISTING);bean.writeLog("-------- 通用合同右上角水印原文件复制成功并加上后缀 .docx: " + tmpPath);try (BufferedInputStream buffIn = new BufferedInputStream(Files.newInputStream(tempFile));FileOutputStream fileOutputStream = new FileOutputStream(tmpPath.toFile())) {// 加载文档XWPFDocument doc = loadDocXDocument(buffIn, fileOutputStream);if (doc == null) {throw new RuntimeException("-------- 加载文档失败");}// 添加水印try {// 遍历文档,添加水印for (int lineIndex = -10; lineIndex < 10; lineIndex++) {styleTop = 200 * lineIndex + "pt";waterMarkDocXDocument(doc);}// 写出添加水印后的文档doc.write(fileOutputStream);// 关闭doc.close();buffIn.close();fileOutputStream.close();return tmpPath.toString();} catch (Exception e) {throw new RuntimeException("-------- 水印操作失败: " + e);}} catch (Exception e) {throw new RuntimeException("-------- 操作失败!" + e);} finally {// 删除原始文件// deleteFile(sourcePath);// 重命名临时文件为原文件名// try {//     Files.move(tmpPath, sourcePath, StandardCopyOption.REPLACE_EXISTING);// } catch (IOException e) {//     throw new RuntimeException("-------- 重命名失败: " + e);// }// 删除临时文件deleteFile(tempFile);}}/*** 为文档添加水印<br />* 实现参考了{@link org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy# getWatermarkParagraph(String, int)}** @param doc 需要被处理的docx文档对象*/private void waterMarkDocXDocument(XWPFDocument doc) {int size = doc.getHeaderList().size();if (size == 0) {addWatermarkToHeader(doc);} else {// 遍历所有的节(Section)for (Object header : doc.getHeaderList()) {// 保留原有内容for (Object paragraph : ((XWPFHeader) header).getParagraphs()) {// 保持原有段落内容((XWPFParagraph)paragraph).getText();}// 在页眉上添加水印(具体代码见上文)addWatermarkToHeader((XWPFHeader)header);}}}/*** 页眉存在其他内容* @param header*/private void addWatermarkToHeader(XWPFHeader header) {int size = header.getParagraphs().size();if (size == 0) {header.createParagraph();}CTP ctp = header.getParagraphArray(0).getCTP();byte[] rsidr = ctp.getRsidR();byte[] rsidrdefault = ctp.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()); // 设置形状样式(旋转,位置,相对路径等参数)shape.setFillcolor(fontColor);shape.setStroked(STTrueFalse.FALSE); // 字体设置为实心CTTextPath shapeTextPath = shape.addNewTextpath(); // 绘制文本的路径shapeTextPath.setStyle("font-family:" + fontName + ";font-size:" + fontSize + "pt"); // 设置文本字体与大小shapeTextPath.setString(customText);CTPicture pict = ctr.addNewPict();pict.set(group);}/*** 页眉不存在其他内容* @param doc*/private void addWatermarkToHeader(XWPFDocument doc) {XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT); // 如果之前已经创建过 DEFAULT 的Header,将会复用之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()); // 设置形状样式(旋转,位置,相对路径等参数)shape.setFillcolor(fontColor);shape.setStroked(STTrueFalse.FALSE); // 字体设置为实心CTTextPath shapeTextPath = shape.addNewTextpath(); // 绘制文本的路径shapeTextPath.setStyle("font-family:" + fontName + ";font-size:" + fontSize + "pt"); // 设置文本字体与大小shapeTextPath.setString(customText);CTPicture pict = ctr.addNewPict();pict.set(group);}/*** 构建Shape的样式参数.** @return*/private String getShapeStyle() {StringBuilder sb = new StringBuilder();sb.append("position: ").append("absolute"); // 文本path绘制的定位方式sb.append(";width: ").append(customText.length() * widthPerWord).append("pt"); // 计算文本占用的长度(文本总个数*单字长度)sb.append(";height: ").append(fontSize).append("pt"); // 字体高度sb.append(";z-index: ").append("-251654144");// 控制层级sb.append(";mso-wrap-edited: ").append("f");sb.append(";margin-top: ").append(30);// 距离页面顶部10ptsb.append(";left: ").append("auto"); // 防止左对齐sb.append(";margin-right: ").append(30); // 距离页面右侧10ptsb.append(";mso-position-horizontal-relative: ").append("page");// 水平基准为页面sb.append(";mso-position-vertical-relative: ").append("page");// 垂直基准为页面sb.append(";mso-position-horizontal: ").append("right"); // // 水平居右//sb.append(";mso-position-vertical: ").append("bottom"); // 设置水印在底部sb.append(";mso-position-vertical: ").append("other"); // 垂直居上sb.append(";rotation: ").append(styleRotation);// 设置文本旋转角度sb.append(";fill-opacity: ").append(0.6); // 设置水印的透明度为 60%return sb.toString();}/*** 加载docx格式的word文档.** @param inputStream* @param outputStream* @return*/private XWPFDocument loadDocXDocument(InputStream inputStream, OutputStream outputStream) {XWPFDocument doc;try {doc = new XWPFDocument(inputStream);} catch (Exception e) {throw new RuntimeException("文档加载失败!!");}return doc;}/*** 创建临时文件.** @param inputStream docx文档输入流*/private Path createTempFile(InputStream inputStream) {Path tempFilePath = null;inputStream = (inputStream == null) ? new ByteArrayInputStream(new byte[0]) : inputStream; // 如果传入了null输入流,转换成空数组流BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);bufferedInputStream.mark(0); // 输入流头部打上Mark(方便重读)// 创建临时文件try {if (inputStream == null || inputStream.available() == 0) {throw new RuntimeException("输入流为空或为 null.");}String uuid = UUID.randomUUID().toString();tempFilePath = Files.createTempFile("dapeng_" + uuid, ".docx");// 向临时文件写入数据try (OutputStream tempout = Files.newOutputStream(tempFilePath)) {IOUtils.copy(inputStream, tempout);} catch (Exception e) { // 如果拷贝异常,删除临时文件deleteFile(tempFilePath);throw new RuntimeException("写入临时文件时出错.", e);}inputStream.close();} catch (Exception e) {// 这里表示创建临时文件失败tempFilePath = null;}return tempFilePath;}/*** 删除指定path的文件.** @param path*/private void deleteFile(Path path) {if (path != null && Files.exists(path)) {try {Files.deleteIfExists(path);} catch (IOException e) {bean.writeLog("-------- 删除文件失败: " + path + " " + e);}}}/*** 将指定字符串重复多次 (适配Java 1.8).*/private String repeatString(String pattern, int repeats) {StringBuilder buffer = new StringBuilder(pattern.length() * repeats);for (int i = 0; i < repeats; i++) {buffer.append(pattern);}return buffer.toString();}
}
总结

使用 Apache POI 和 VML,我们可以轻松地在 Word 文档中添加水印。该方法适用于各种办公场景,如合同文件、内部文档等。如果你有更复杂的需求,如图片水印或动态水印,也可以扩展此方法。

希望本文对你有所帮助,欢迎交流讨论!

http://www.yayakq.cn/news/523412/

相关文章:

  • 济南网站建设哪个好还有河北城乡和住房建设厅网站吗
  • wordpress模板建站工地建筑劳务公司招工平台
  • 石家庄建设厅网站wordpress 知道创宇
  • 菏泽建设局网站个人备案的网站能做什么
  • 温州做网站哪里好怎么选择网站建设公司
  • 营销型网站哪家好Apache Wordpress伪静态处理
  • 团购模板网站高端网站开发制作
  • 可以做头像的网站有哪些wordpress flatsome
  • 外网网站建设调研报告企业网站制作素材
  • 网站建设 51下拉平台肉部网站建设包括哪些
  • 网站建设的流程该怎么确定给微商做网站
  • 在哪网站开发软件从哪些方面做好网站的seo
  • 邮箱网易企业邮箱中国seo谁最厉害
  • wordpress付费插件网站哪种语言做网站好
  • 摄影网站下载aspaccess做网站
  • wordpress ecommerce theme南安seo快速排名
  • 局域网建设网站如何访问开发网站公司如何运营
  • 网站建设太难了企业管理系统论文
  • asp网站例子礼品册兑换 网站建设
  • 雅安市建设局网站百度投诉中心人工电话
  • 网站建设做的好处天津优化网站
  • 西八里庄网站建设dns网站建设
  • dream8网站建设及设计天津七七一网站建设有限公司怎么样
  • 对网站建设好学吗中国建设部网站
  • 贵州建设项目门户网站网站型销售怎么做的
  • 成都世迅网站建设c2c商业模式有哪些
  • 辽宁地矿建设集团有限公司网站网站进入百度观察期
  • 网站建设基本情况英文站 wordpress
  • 网站开发从哪里学起成都网站建设思乐科技
  • 网站搭建教程视频企信网查不到公司怎么办