①. 案例演示:
- ①. pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.1.1</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.1.3</version> </dependency> <!--end--> <!-- https://mvnrepository.com/artifact/com.itextpdf.tool/xmlworker --> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.13</version> </dependency> </dependencies>
②. 测试
package com.xiaozhi.controller.water; import java.awt.FontMetrics; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.util.UUID; import javax.swing.JLabel; import com.itextpdf.text.*; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfGState; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; public class TestWaterPrint { public static void main(String[] args) throws DocumentException, IOException { // 要输出的pdf文件 File desc = new File("src/main/resources/test88.pdf"); //BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("F:/test88.pdf"))); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(desc)); File directory = new File("src/main/resources"); String courseFile = directory.getCanonicalPath()+"\\"+"fbsl.pdf"; System.out.println(courseFile); // 将pdf文件先加水印然后输出 setWatermark(bos, courseFile, "null-admin"); } /** * * @param //bos输出文件的位置 * @param input * 原PDF位置 * @param waterMarkName * 页脚添加水印 * @throws DocumentException * @throws IOException */ public static void setWatermark(BufferedOutputStream bos, String input, String waterMarkName) throws DocumentException, IOException { PdfReader reader = new PdfReader(input); PdfStamper stamper = new PdfStamper(reader, bos); // 获取总页数 +1, 下面从1开始遍历 int total = reader.getNumberOfPages() + 1; // 使用classpath下面的字体库 BaseFont base = null; try { // 内容字体 //base = BaseFont.createFont("C:/WINDOWS/Fonts/simsun.ttc,1", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); base =BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED); // Font fontTitle = new Font(base, 18, Font.BOLD); //Font fontContent = new Font(base, 12, Font.NORMAL); } catch (Exception e) { // 日志处理 e.printStackTrace(); } // 间隔 int interval = 15; // 获取水印文字的高度和宽度 int textH = 0, textW = 0; JLabel label = new JLabel(); label.setText(waterMarkName); FontMetrics metrics = label.getFontMetrics(label.getFont()); textH = metrics.getHeight(); textW = metrics.stringWidth(label.getText()); System.out.println("textH: " + textH); System.out.println("textW: " + textW); // 设置水印透明度 PdfGState gs = new PdfGState(); gs.setFillOpacity(0.8f); gs.setStrokeOpacity(0.8f); Rectangle pageSizeWithRotation = null; PdfContentByte content = null; for (int i = 1; i < total; i++) { // 在内容上方加水印 content = stamper.getOverContent(i); // 在内容下方加水印 //content = stamper.getUnderContent(i); content.saveState(); content.setGState(gs); // 设置字体和字体大小 content.beginText(); // BaseColor baseColor=new BaseColor(225,225,225); // content.setColorFill(baseColor); content.setFontAndSize(base, 20); // 获取每一页的高度、宽度 pageSizeWithRotation = reader.getPageSizeWithRotation(i); float pageHeight = pageSizeWithRotation.getHeight(); float pageWidth = pageSizeWithRotation.getWidth(); // 根据纸张大小多次添加, 水印文字成30度角倾斜 for (int height = interval + textH; height < pageHeight-30; height = height + textH * 4) { if(height>0){ height=height+80; } for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 3) { content.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, 15); } } content.endText(); } // 关流 stamper.close(); reader.close(); } }
③. 生成文件
(这里实现的效果是先通过resource下加载到fbsl.pdf文件,通过代码打上水印,生成一个test99.pdf的文件)
②. 项目实战
- ①. gradle配置文件如下:
compile 'com.itextpdf:itextpdf:5.5.13'
②. 这里实现的效果是,拿取到resourc/pdf下的pdf,加上水印,最后直接通过io进行页面的输出
package com.devplatform.biz.web.controller.biz.operations; import com.devplatform.biz.service.log.LogService; import com.devplatform.common.controller.BaseController; import com.devplatform.org.vo.IPStaffVO; import com.itextpdf.text.BaseColor; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Element; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.swing.*; import java.awt.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @Api(tags = "运营标准相关", value = "运营标准相关") @Slf4j @RestController @RequestMapping(value = "/watermarkPdf") public class TBizOperationPdfController extends BaseController { //操作日志 @Autowired LogService logService; @ApiOperation(value = "运营标准加水印打开pdf", notes = "pdfParams是pdf的名称") @GetMapping("/openPdf.do") public void openPdf(HttpServletResponse response, HttpServletRequest request) { //(1). 获取到当前登录的用户名信息,得到打印水印的名称 IPStaffVO ipStaffVO = this.getCurrentStaff(request);//当前登录人员 String waterMarkName = "";//在pdf下打印水印的名称 String code = ipStaffVO.getOwnerunitid();//获取到店代码 String staffName = ipStaffVO.getStaffname();//名称 String unitUnionName = ipStaffVO.getUnitunionname();//部门名称 //status:1代表特约店 0表示广本 if ("1".equals(ipStaffVO.getStatus())) { //超级管理员status也为1 if("admin".equals(ipStaffVO.getStaffname())){ waterMarkName = "null-" + staffName; }else{ waterMarkName = code + "-" + staffName; } } else { waterMarkName = unitUnionName + "-" + staffName; } //(2). 得到resource下pdf的路径 String pdfName = "/pdf/" + request.getParameter("pdfParams"); InputStream in = null; OutputStream out = null; try { response.setContentType("application/pdf"); in = this.getClass().getResourceAsStream(pdfName); out = response.getOutputStream(); // (3). 将pdf文件先加水印然后输出 setWatermark(out, in, waterMarkName,request,ipStaffVO); byte[] b = new byte[512]; //(4). 在浏览器中打开pdf while ((in.read(b)) != -1) { out.write(b); } } catch (IOException e) { log.error("", e); } finally { //关流 try { out.flush(); } catch (IOException e) { log.error("", e); } try { in.close(); } catch (IOException e) { log.error("", e); } try { out.close(); } catch (IOException e) { log.error("", e); } } } /** * @param //bos输出文件的位置 * @param input 原PDF位置 * @param waterMarkName 页脚添加水印 * @throws DocumentException * @throws IOException */ private void setWatermark(OutputStream bos, InputStream input, String waterMarkName,HttpServletRequest request,IPStaffVO ipStaffVO) { //创建pdf需要的读写流 PdfReader reader=null; PdfStamper stamper=null; try{ reader = new PdfReader(input); stamper = new PdfStamper(reader, bos); // 获取总页数 +1, 下面从1开始遍历 int total = reader.getNumberOfPages() + 1; // 使用classpath下面的字体库 BaseFont base = null; // 内容字体 String name = Thread.currentThread().getContextClassLoader().getResource("fonts/SIMSUN.TTC").getPath() + ",0"; base = BaseFont.createFont(name, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // Font fontTitle = new Font(base, 18, Font.BOLD); //Font fontContent = new Font(base, 12, Font.NORMAL); // 间隔 int interval = 15; // 获取水印文字的高度和宽度 int textH = 0, textW = 0; JLabel label = new JLabel(); label.setText(waterMarkName); FontMetrics metrics = label.getFontMetrics(label.getFont()); textH = metrics.getHeight(); textW = metrics.stringWidth(label.getText()); log.info("textH: " + textH); log.info("textW: " + textW); // 设置水印透明度 PdfGState gs = new PdfGState(); gs.setFillOpacity(0.8f); gs.setStrokeOpacity(0.8f); Rectangle pageSizeWithRotation = null; PdfContentByte content = null; for (int i = 1; i < total; i++) { // 在内容上方加水印 content = stamper.getOverContent(i); content.saveState(); content.setGState(gs); // 设置字体和字体大小 content.beginText(); //设置字体的颜色 BaseColor baseColor=new BaseColor(136,136,136); content.setColorFill(baseColor); content.setFontAndSize(base, 10); // 获取每一页的高度、宽度 pageSizeWithRotation = reader.getPageSizeWithRotation(i); float pageHeight = pageSizeWithRotation.getHeight(); float pageWidth = pageSizeWithRotation.getWidth(); // 根据纸张大小多次添加, 水印文字成15度角倾斜 for (int height = interval + textH; height < pageHeight - 30; height = height + textH * 4) { //这里主要是调节pdf中的y if (height > 0) { height = height + 80; } for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 1) { //这里主要是调节pdf中的x if(width>0){ width=width+80; } content.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, 15); } } content.endText(); } //记录日志 //log(日志信息,ip地址,操作人代码,操作人名称,业务模块,logtype,recordtype) logService.log("打开了有水印的pdf", request.getHeader(HTTP_X_FORWARDED_FOR), ipStaffVO.getStaffid(), ipStaffVO.getStaffname(), "标准运营", "02", "02"); } catch (DocumentException e) { log.error("",e); } catch (IOException e) { log.error("",e); } catch (Exception e) { log.error("",e); } finally { // 关流 try { stamper.close(); } catch (DocumentException e) { log.error("",e); } catch (IOException e) { log.error("",e); } reader.close(); } } }
③. 前台vue对接后台接口
<template> <el-container> <el-header class="query_params query_params_header"> </el-header> <el-main> <table class="hovertable"> <tr> <td @click="showlnp()"> <div class="bk" onmouseover="this.style.backgroundColor='#eef3f7';" onmouseout="this.style.backgroundColor='#fff';"> <div><img :src="lnpImg" alt="理念篇" /></div> <h3>1-理念篇</h3> </div> </td> <td @click="showzzp()"> <div class="bk" onmouseover="this.style.backgroundColor='#eef3f7';" onmouseout="this.style.backgroundColor='#fff';"> <div><img :src="zzpImg" alt="组织篇" /></div> <h3>2-组织篇</h3> </div> </td> <td @click="showhjp()"> <div class="bk" onmouseover="this.style.backgroundColor='#eef3f7';" onmouseout="this.style.backgroundColor='#fff';"> <div><img :src="hjpImg" alt="环境篇" /></div> <h3>3-环境篇</h3> </div> </td> </tr> <!-- 第二行 --> <tr> <td @click="showsjzcp()"> <div class="bk" onmouseover="this.style.backgroundColor='#eef3f7';" onmouseout="this.style.backgroundColor='#fff';"> <div><img :src="sjzcpImg" alt="数据支持篇" /></div> <h3>4-数据支持篇</h3> </div> </td> <td @click="showgljdp()"> <div class="bk" onmouseover="this.style.backgroundColor='#eef3f7';" onmouseout="this.style.backgroundColor='#fff';"> <div><img :src="gljdpImg" alt="管理监督篇" /></div> <h3>5-管理监督篇</h3> </div> </td> <td @click="showkhwxp()"> <div class="bk" onmouseover="this.style.backgroundColor='#eef3f7';" onmouseout="this.style.backgroundColor='#fff';"> <div><img :src="khwxpImg" alt="客户维系篇" /></div> <h3>6-客户维系篇</h3> </div> </td> </tr> </table> </el-main> <el-footer> </el-footer> </el-container> </template> <script> import lnp from "@/views/business/operations/operationquery/img/lnp.jpg" import zzp from "@/views/business/operations/operationquery/img/zzp.jpg" import hjp from "@/views/business/operations/operationquery/img/hjp.jpg" import sjzcp from "@/views/business/operations/operationquery/img/sjzcp.jpg" import gljdp from "@/views/business/operations/operationquery/img/gljdp.jpg" import khwxp from "@/views/business/operations/operationquery/img/khwxp.jpg" import { getToken } from '@/utils/auth' // get token from cookie export default { name: 'standardsManualQuery',//标准运营查询 components: {}, data(){ return{ lnpImg:lnp,//理念篇 zzpImg:zzp,//组织篇 hjpImg:hjp,//环境篇 sjzcpImg:sjzcp,//数据支持篇 gljdpImg:gljdp,//管理监督篇 khwxpImg:khwxp,//客户维系篇 url:''//这里获取到https://ip:端口 } }, methods:{ showlnp(){//理念篇 window.open("/shoa/api/biz/standardsManual/openPdf.do?usertoken="+getToken()+"&&pdfParams=lnp.pdf"); }, showzzp(){//组织篇 window.open("/shoa/api/biz/standardsManual/openPdf.do?usertoken="+getToken()+"&&pdfParams=zzp.pdf"); }, showhjp(){//环境篇 window.open("/shoa/api/biz/standardsManual/openPdf.do?usertoken="+getToken()+"&&pdfParams=hjp.pdf"); }, showsjzcp(){//数据支持篇 window.open("/shoa/api/biz/standardsManual/openPdf.do?usertoken="+getToken()+"&&pdfParams=sjzcp.pdf"); }, showgljdp(){//管理监督篇 window.open("/shoa/api/biz/standardsManual/openPdf.do?usertoken="+getToken()+"&&pdfParams=gljdp.pdf"); }, showkhwxp(){//客户维系篇 window.open("/shoa/api/biz/standardsManual/openPdf.do?usertoken="+getToken()+"&&pdfParams=khwxp.pdf"); } } } </script> <style scoped> .query_params_header{ height:auto !important; } table.hovertable { font-family: verdana,arial,sans-serif; font-size:15px; color:#333333; border-width: 1px; border-color: #999999; border-collapse: collapse; } img{ width: 150px; height: 190px; cursor:pointer; } h3{ color: #3A0088; } .bk { margin: 30px; width: 154px; height: 268px; text-align:center; border:3px solid #cceff5; } </style>