diff --git a/jero-boot-base/jero-boot-base-core/pom.xml b/jero-boot-base/jero-boot-base-core/pom.xml index 1ccfaceb..5914a0d4 100644 --- a/jero-boot-base/jero-boot-base-core/pom.xml +++ b/jero-boot-base/jero-boot-base-core/pom.xml @@ -276,6 +276,10 @@ p6spy p6spy + + org.apache.pdfbox + pdfbox + \ No newline at end of file diff --git a/jero-boot-module-system/src/main/java/com/jero/modules/system/controller/CommonController.java b/jero-boot-module-system/src/main/java/com/jero/modules/system/controller/CommonController.java index a4285d31..b0a40b6b 100644 --- a/jero-boot-module-system/src/main/java/com/jero/modules/system/controller/CommonController.java +++ b/jero-boot-module-system/src/main/java/com/jero/modules/system/controller/CommonController.java @@ -1,5 +1,6 @@ package com.jero.modules.system.controller; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -9,6 +10,7 @@ import com.jero.common.system.vo.LoginUser; import com.jero.common.util.*; import com.jero.modules.oss.entity.OSSFile; import com.jero.modules.oss.service.IOSSFileService; +import com.jero.modules.system.util.SysWaterMarkUtil; import lombok.extern.slf4j.Slf4j; import com.jero.common.api.vo.Result; import com.jero.common.constant.CommonConstant; @@ -74,6 +76,8 @@ public class CommonController { */ @Value(value="${jero.fileSuffixLimits}") private String[] fileSuffixLimits; + @Resource + private SysWaterMarkUtil sysWaterMarkUtil; /** * @Author 政辉 @@ -227,6 +231,10 @@ public class CommonController { fileName = ossFile.getFileName(); inputStream = MinioUtil.getMinioFile(MinioUtil.getBucketName(), url); } + //pdf加水印 + if ("pdf".equalsIgnoreCase(FileUtil.extName(fileName))) { + inputStream = sysWaterMarkUtil.addWatermarkToPdf(inputStream); + } response.addHeader("Content-Disposition", "attachment;fileName=" + new String(fileName.getBytes("UTF-8"),"iso-8859-1")); response.setContentType("application/force-download");// 设置强制下载不打开 if (type == null) { @@ -264,9 +272,8 @@ public class CommonController { ossFileService.updateAndPush(ossFile); } } catch (IOException e) { - log.error("预览文件失败" + e.getMessage()); + log.error("预览文件失败" + e); response.setStatus(404); - e.printStackTrace(); } finally { if (inputStream != null) { try { @@ -402,7 +409,10 @@ public class CommonController { fileName = ossFile.getFileName(); inputStream = MinioUtil.getMinioFile(MinioUtil.getBucketName(), url); } - + //pdf加水印 + if ("pdf".equalsIgnoreCase(FileUtil.extName(fileName))) { + inputStream = sysWaterMarkUtil.addWatermarkToPdf(inputStream); + } ossFileService.updateById(ossFile); LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); //if (loginUser.getIsCompanyUser()) { @@ -449,9 +459,8 @@ public class CommonController { ossFileService.updateAndPush(ossFile); } } catch (IOException e) { - log.error("预览文件失败" + e.getMessage()); + log.error("预览文件失败" + e); response.setStatus(404); - e.printStackTrace(); } finally { if (inputStream != null) { try { diff --git a/jero-boot-module-system/src/main/java/com/jero/modules/system/util/SysWaterMarkUtil.java b/jero-boot-module-system/src/main/java/com/jero/modules/system/util/SysWaterMarkUtil.java new file mode 100644 index 00000000..42a98d6e --- /dev/null +++ b/jero-boot-module-system/src/main/java/com/jero/modules/system/util/SysWaterMarkUtil.java @@ -0,0 +1,153 @@ +package com.jero.modules.system.util; + +import com.jero.common.system.vo.LoginUser; +import com.jero.common.util.DateUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType0Font; +import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; +import org.apache.pdfbox.pdmodel.graphics.state.RenderingMode; +import org.apache.pdfbox.util.Matrix; +import org.apache.shiro.SecurityUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; + +import java.awt.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 水印工具类 + * + * @author CaiHaohan + */ +@Component +@Slf4j +public class SysWaterMarkUtil { + + @Value("${watermark.font-size}") + private float fontSize; + + @Value("${watermark.color.r}") + private int r; + + @Value("${watermark.color.g}") + private int g; + + @Value("${watermark.color.b}") + private int b; + + @Value("${watermark.color.a}") + private int a; + + @Value("${watermark.lineNumPerPage}") + private int lineNumPerPage; + + @Value("${watermark.columnNumPerPage}") + private int columnNumPerPage; + + @Value("${watermark.degree}") + private int degree; + + @Value("${watermark.margin.left}") + private float marginLeft; + + @Value("${watermark.margin.top}") + private float marginTop; + @Value("${watermark.dateFormat}") + private String dateFormat; + + + public List getWaterMarkConfig() { + LoginUser loginUser = UserUtils.getLoginUser(); + + Date curDate = new Date(); + String cudDateStr = DateUtils.date2Str(curDate, new SimpleDateFormat(dateFormat)); + List result = new ArrayList<>(); + if (loginUser == null) { + result.add("汽车标准化工作平台 "); + }else { + result.add("汽车标准化工作平台 " + loginUser.getRealname()); + } + + result.add(cudDateStr); + return result; + } + + public synchronized InputStream addWatermarkToPdf(InputStream inputStream) throws IOException { + List watermarkText = getWaterMarkConfig(); + PDDocument document = PDDocument.load(inputStream); + document.setAllSecurityToBeRemoved(true); + // 加载水印字体 + ClassPathResource fontResource = new ClassPathResource("fonts/SourceHanSerif-VF.ttf"); + PDType0Font font = PDType0Font.load(document, fontResource.getInputStream()); + + // 设置水印颜色和透明度 + Color color = new Color(r, g, b, a); + PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState(); + graphicsState.setNonStrokingAlphaConstant(0.4f); + graphicsState.setStrokingAlphaConstant(0.4f); + + // 遍历每一页并添加水印 + for (PDPage page : document.getPages()) { + // 获取页面尺寸以计算水印位置和大小 + PDRectangle pageSize = page.getMediaBox(); + float pageWidth = pageSize.getWidth(); + float pageHeight = pageSize.getHeight(); + + // 根据页面宽度动态调整字体大小 + float dynamicFontSize = pageWidth * (this.fontSize / 595); // 假设基准页面宽度为595单位 + + float xStep = pageWidth / columnNumPerPage; + float yStep = pageHeight / lineNumPerPage; + float rotationInRadians = (float) Math.toRadians(degree); + + // 行间距,设为字体大小的一半 + float lineSpacing = dynamicFontSize / 2; + + // 计算两行文本的总高度 + float totalTextHeight = (dynamicFontSize + lineSpacing) * (watermarkText.size() - 1); + + for (float xPosition = pageSize.getLowerLeftX() + marginLeft; xPosition <= pageWidth - marginLeft; xPosition += xStep) { + for (float yPosition = pageSize.getLowerLeftY() + marginTop; yPosition <= pageHeight - marginTop; yPosition += yStep) { + try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) { + contentStream.setGraphicsStateParameters(graphicsState); + contentStream.setNonStrokingColor(color); + + float textYPosition = yPosition + (totalTextHeight / 2); + + for (String line : watermarkText) { + contentStream.beginText(); + contentStream.setFont(font, dynamicFontSize); + contentStream.setRenderingMode(RenderingMode.FILL); + contentStream.setTextMatrix(Matrix.getRotateInstance(rotationInRadians, xPosition, textYPosition)); + contentStream.showText(line); + contentStream.endText(); + + // 更新文本的Y坐标,为下一行准备 + textYPosition -= (dynamicFontSize + lineSpacing); + } + } + } + } + } + + // 创建一个临时的ByteArrayOutputStream保存修改过的PDF + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + document.save(baos); + document.close(); + + // 将ByteArrayOutputStream转换为ByteArrayInputStream以供返回 + return new ByteArrayInputStream(baos.toByteArray()); + } +} diff --git a/jero-boot-module-system/src/main/java/com/jero/modules/system/util/UserUtils.java b/jero-boot-module-system/src/main/java/com/jero/modules/system/util/UserUtils.java new file mode 100644 index 00000000..96c5ae83 --- /dev/null +++ b/jero-boot-module-system/src/main/java/com/jero/modules/system/util/UserUtils.java @@ -0,0 +1,36 @@ +package com.jero.modules.system.util; + +import com.jero.common.system.vo.LoginUser; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.UnavailableSecurityManagerException; +import org.apache.shiro.session.InvalidSessionException; + +public class UserUtils { + + /** + * 获取当前登录用户ID + * + */ + public static String getUserId() { + String userId = null; + try { + LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); + if(sysUser!=null){ + userId = sysUser.getId(); + } + } catch (UnavailableSecurityManagerException e) { + e.printStackTrace(); + } catch (InvalidSessionException e) { + e.printStackTrace(); + } + return userId; + } + + /** + * 获取当前登录用户 + * + */ + public static LoginUser getLoginUser() { + return (LoginUser) SecurityUtils.getSubject().getPrincipal(); + } +} diff --git a/jero-boot-module-system/src/main/resources/fonts/SourceHanSerif-VF.ttf b/jero-boot-module-system/src/main/resources/fonts/SourceHanSerif-VF.ttf new file mode 100644 index 00000000..021fc0db Binary files /dev/null and b/jero-boot-module-system/src/main/resources/fonts/SourceHanSerif-VF.ttf differ diff --git a/jero-boot-single-startup/src/main/resources/application-dev.yml b/jero-boot-single-startup/src/main/resources/application-dev.yml index 61e50750..6bf405e9 100644 --- a/jero-boot-single-startup/src/main/resources/application-dev.yml +++ b/jero-boot-single-startup/src/main/resources/application-dev.yml @@ -363,4 +363,26 @@ template: #入会申请表word applicationWord: E:\\biao_zhun_suo\\template\\applicationWord.docx #模版目录 - templatePath: D:\\hzwl\\income_payments\\income_payments_managerment\\template\\ \ No newline at end of file + templatePath: D:\\hzwl\\income_payments\\income_payments_managerment\\template\\ + +# 水印配置项 +watermark: + font-size: 13.0 + # 每页几行 + lineNumPerPage: 8 + # 每页几列 + columnNumPerPage: 3 + # 倾斜角度 + degree: 30 + # 颜色 + color: + r: 180 + g: 180 + b: 180 + a: 1 + # 页边距 + margin: + top: 100 + left: 60 + # 日期格式 + dateFormat: yyyy-MM-dd HH:mm:ss \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6f5249e8..6dd3a345 100644 --- a/pom.xml +++ b/pom.xml @@ -278,6 +278,11 @@ p6spy 3.9.1 + + org.apache.pdfbox + pdfbox + 2.0.27 +