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

web应用水印实现方案

为 Web 项目添加水印主要有前端纯 JS 实现(最常用)、后端生成水印图片、后端 PDF 水印(针对文档下载) 三种主流方案,以下是详细实现:
 

方案一:前端 JS 动态生成水印(推荐,无后端依赖)

 
这是最常用的方案,直接在浏览器端通过 JS 生成水印,性能好、不占用后端资源,支持动态内容(如用户名、时间)。
 
实现代码(通用版):
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>Web水印示例</title><style>/* 水印容器样式,固定定位覆盖整个页面 */.watermark-container {position: fixed;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none; /* 不影响页面元素交互 */z-index: 9999; /* 确保水印在最上层 */opacity: 0.15; /* 水印透明度,可调整 */}</style>
</head>
<body><h1>Java Web项目水印示例</h1><script>/*** 生成页面水印* @param {String} text 水印文字(如用户名、公司名称)* @param {Object} options 配置项(可选)*/function createWatermark(text = "默认水印", options = {}) {// 默认配置const config = {fontSize: options.fontSize || 16, // 字体大小fontFamily: options.fontFamily || "Microsoft Yahei", // 字体rotate: options.rotate || -20, // 旋转角度(负数向左旋转)color: options.color || "#000000", // 字体颜色spacing: options.spacing || 100, // 水印间距
            };// 创建canvas元素生成水印const canvas = document.createElement("canvas");const ctx = canvas.getContext("2d");// 设置canvas尺寸(单个水印单元)canvas.width = config.spacing;canvas.height = config.spacing;// 绘制水印文字ctx.font = `${config.fontSize}px ${config.fontFamily}`;ctx.fillStyle = config.color;ctx.textAlign = "center";ctx.textBaseline = "middle";ctx.rotate((config.rotate * Math.PI) / 180); // 角度转弧度ctx.fillText(text, canvas.width / 2, canvas.height / 2);// 创建水印容器并添加到页面let watermark = document.querySelector(".watermark-container");if (!watermark) {watermark = document.createElement("div");watermark.className = "watermark-container";document.body.appendChild(watermark);}// 设置水印背景(重复平铺)watermark.style.backgroundImage = `url(${canvas.toDataURL("image/png")})`;}// ========== 调用示例 ==========// 1. 固定文字水印createWatermark("XX公司 2026-02-09");// 2. 动态获取后端传递的用户信息(Java后端通过模板渲染传递)// const userName = [[${user.name}]]; // Freemarker/Thymeleaf模板语法// createWatermark(`${userName} 禁止复制`, { fontSize: 14, rotate: -15 });</script>
</body>
</html>

关键说明:

 
  • pointer-events: none 确保水印不遮挡页面元素的点击 / 输入事件
  • canvas.toDataURL() 将画布转为 base64 图片,作为背景平铺实现水印效果
  • 可通过 Java 模板引擎(Thymeleaf/Freemarker)将后端的用户信息、时间等动态传递到前端
 

方案二:后端生成水印图片(Java 实现)

 
适合需要统一水印样式、前端无法修改的场景,后端生成水印图片后返回给前端使用。
 
Java 后端代码(生成水印图片):
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;/*** Java后端生成水印图片工具类*/
public class WatermarkUtils {/*** 生成水印图片并返回Base64编码* @param text 水印文字* @param width 水印单元宽度* @param height 水印单元高度* @return Base64编码的图片字符串*/public static String generateWatermarkImage(String text, int width, int height) {// 创建画布BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);Graphics2D g2d = image.createGraphics();// 设置透明背景image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);g2d.dispose();g2d = image.createGraphics();// 设置水印样式g2d.setColor(new Color(0, 0, 0, 38)); // 黑色,透明度15%(0-255)g2d.setFont(new Font("微软雅黑", Font.PLAIN, 16));g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);// 旋转文字g2d.rotate(Math.toRadians(-20), width / 2, height / 2);// 计算文字位置(居中)FontRenderContext frc = g2d.getFontRenderContext();AffineTransform affinetransform = new AffineTransform();Font font = g2d.getFont();java.awt.font.TextLayout textLayout = new java.awt.font.TextLayout(text, font, frc);float textWidth = textLayout.getAdvance();float textHeight = textLayout.getAscent() - textLayout.getDescent();int x = (width - (int) textWidth) / 2;int y = (height + (int) textHeight) / 2;// 绘制文字
        g2d.drawString(text, x, y);g2d.dispose();// 转为Base64try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {ImageIO.write(image, "png", baos);return "data:image/png;base64," + Base64.getEncoder().encodeToString(baos.toByteArray());} catch (IOException e) {throw new RuntimeException("生成水印图片失败", e);}}// 测试示例public static void main(String[] args) {String watermarkBase64 = generateWatermarkImage("XX公司 内部文档", 200, 200);System.out.println(watermarkBase64); // 前端可直接使用该Base64作为背景图
    }
}

前端使用方式:

// 从Java后端接口获取水印图片Base64
fetch("/api/watermark").then(res => res.json()).then(data => {const watermark = document.createElement("div");watermark.className = "watermark-container";watermark.style.backgroundImage = `url(${data.base64})`;document.body.appendChild(watermark);});

方案三:PDF 文档水印(后端生成)

 
如果你的 Web 项目需要为下载的 PDF 文档添加水印,可使用 iText 库实现:
 
Maven 依赖:
<dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>7.2.5</version>
</dependency>

Java 实现代码:

import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.VerticalAlignment;import java.io.File;
import java.io.IOException;public class PdfWatermarkUtils {public static void addPdfWatermark(String srcPath, String destPath, String watermarkText) throws IOException {PdfDocument pdfDoc = new PdfDocument(new PdfReader(srcPath), new PdfWriter(destPath));Document document = new Document(pdfDoc);int pageCount = pdfDoc.getNumberOfPages();// 为每一页添加水印for (int i = 1; i <= pageCount; i++) {Paragraph watermark = new Paragraph(watermarkText).setFontSize(30).setFontColor(ColorConstants.BLACK, 0.15f) // 透明度15%.setRotationAngle(Math.toRadians(-20)); // 旋转角度// 将水印添加到页面居中位置
            document.showTextAligned(watermark,pdfDoc.getPage(i).getPageSize().getWidth() / 2,pdfDoc.getPageSize().getHeight() / 2,i,TextAlignment.CENTER,VerticalAlignment.MIDDLE,Math.toRadians(-20));}document.close();}// 测试示例public static void main(String[] args) throws IOException {addPdfWatermark("source.pdf", "target.pdf", "XX公司 内部文档 2026-02-09");}
}

增强建议(防篡改 / 防删除)

 
为了防止用户通过浏览器调试工具删除水印,可添加以下增强措施:
// 监听水印元素是否被删除,自动重新生成
function monitorWatermark() {const observer = new MutationObserver((mutations) => {mutations.forEach((mutation) => {if (mutation.removedNodes.length > 0) {for (let node of mutation.removedNodes) {if (node.className === "watermark-container") {createWatermark("XX公司 2026-02-09"); // 重新生成水印break;}}}});});// 监听body的子节点变化
    observer.observe(document.body, {childList: true,subtree: true});
}// 调用监控函数
monitorWatermark();

总结

 
  1. 优先选择前端 JS 方案:无后端依赖、性能高、支持动态内容,适合绝大多数 Web 页面水印场景。
  2. 后端生成水印图片:适合需要严格控制水印样式、防止前端篡改的场景,通过 Java 生成 Base64 图片返回前端使用。
  3. PDF 水印用 iText:针对文档下载场景,后端直接生成带水印的 PDF 文件。
 
核心关键点:前端水印通过 canvas 生成 base64 背景图平铺实现,后端水印可生成图片或直接处理 PDF,根据实际业务场景选择即可。
http://www.jsqmd.com/news/360280/

相关文章:

  • 基于PHP、asp.net、java、Springboot、SSM、vue3的智慧物业管理系统的设计与实现
  • 基于PHP、asp.net、java、Springboot、SSM、vue3的基金预测分析平台的设计与实现
  • 实用指南:Neo4j 版本选型与 Java 技术栈深度解析:Spring Data Neo4j vs Java Driver,如何抉择?
  • 上周热点回顾(2.2
  • 破解人力数据割裂难题 用 HR 系统搭建数据驱动决策体系
  • 智能化 HR 平台能带来什么 企业人力管理效率提升的关键路径
  • 从新能源“质效并重”新阶段,看霍尔电流传感器的关键角色
  • 【Matlab】MATLAB continue跳过循环教程:语法解析、偶数累加案例与实战应用
  • 深入解析主流平台推荐算法:原理、优劣与实战选型
  • 告别灾难性遗忘:持续学习核心算法与工业落地全指南
  • 【安装教程】全网最细 | Windows/Linux双系统CUDA+配套库安装全流程
  • Linux 磁盘管理
  • 多任务学习实战指南:原理、场景与避坑全解析
  • 对象和类(过程性编程和面向对象编程)
  • # 零样本学习实战指南:原理、场景与优化全解析
  • 视频算法(这篇送给11月份那微信发对AI礼貌会给更好的答案的珠。°(°¯᷄◠¯᷅°)°。)
  • 深入浅出:Fine-tune(微调)的核心场景、实战方法与避坑指南
  • 截止当前:还可用的Centos7内核 kernel 的升级仓库地址:elrepo
  • 蜜蜂的天空罗盘:基于ZYNQ的仿生偏振光导航系统解密
  • 【船舶控制】基于matlab模糊偏航的扭矩矢量与主动转向控制系统【含Matlab源码 15093期】
  • 详细介绍:【Docker】docker run
  • Python 单例模式终极指南:从装饰器到元类,寻找最优雅与线程安全的完美方案
  • Python 进阶:解构多重继承的“黑魔法”——深入剖析 MRO 与 C3 线性化算法
  • 构建坚固的 Python 架构:利用抽象基类(ABC)打造不可违背的代码契约
  • MAF快速入门(15)Agent调试利器:DevUI
  • 【船舶控制】模糊偏航的扭矩矢量与主动转向控制系统【含Matlab源码 15093期】
  • 2009-2024年上市公司过度负债水平数据
  • 2000-2024年上市公司价值链升级数据+Stata代码
  • 2026最新|国内可用 Docker 镜像加速源大全(2月持续更新):DockerHub 镜像加速与限速避坑全指南(适配 Windows / macOS / Linux / containerd /
  • 详细介绍:如何在2025年将联系人从iPhone传输到iPhone