From 9d65dd091154a0301076549e031e15017898c2ee Mon Sep 17 00:00:00 2001
From: peter <14100000001@qq.com>
Date: Sun, 11 Jan 2026 14:07:02 +0800
Subject: [PATCH] 签章
---
src/main/java/com/nq/service/impl/UserAgreementServiceImpl.java | 498 ++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 345 insertions(+), 153 deletions(-)
diff --git a/src/main/java/com/nq/service/impl/UserAgreementServiceImpl.java b/src/main/java/com/nq/service/impl/UserAgreementServiceImpl.java
index 7a78c5c..3dbd397 100644
--- a/src/main/java/com/nq/service/impl/UserAgreementServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/UserAgreementServiceImpl.java
@@ -31,6 +31,9 @@
import java.util.List;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.GraphicsEnvironment;
import com.nq.pojo.ContractImage;
import com.nq.dao.ContractImageMapper;
import com.alibaba.fastjson.JSON;
@@ -68,11 +71,8 @@
dir.mkdirs();
}
- String pdfFileName = "agreement_" + user.getId() + ".pdf";
+ String pdfFileName = "contract_" + user.getId() + ".pdf";
File pdfFile = new File(dir, pdfFileName);
-
- // 构建完整的PDF访问URL
- String pdfUrl = PropertiesUtil.getProperty("pdf.server.http.prefix") + "/agreement_" + user.getId() + ".pdf";
// 如果PDF已存在,删除后重新生成,确保数据是最新的
if (pdfFile.exists()) {
@@ -94,32 +94,36 @@
// 将PDF转换为图片并返回图片路径数组
List<String> imageUrls = convertPdfToImages(pdfFile, "contract", user.getId());
-
+
return ServerResponse.createBySuccess(imageUrls);
} catch (Exception e) {
log.error("生成用户协议PDF失败", e);
return ServerResponse.createByErrorMsg("生成PDF失败:" + e.getMessage());
}
}
+
/**
* 从PDF模板生成新的PDF,替换占位符
*/
private void generatePdfFromTemplate(File templatePdf, File outputPdf, User user) throws Exception {
- log.info("开始生成PDF,模板路径: {}, 输出路径: {}, 用户: {}",
- templatePdf.getAbsolutePath(), outputPdf.getAbsolutePath(), user.getId());
-
+ log.info("开始生成PDF,模板路径: {}, 输出路径: {}, 用户: {}",
+ templatePdf.getAbsolutePath(), outputPdf.getAbsolutePath(), user.getId());
+
PdfReader reader = null;
PdfStamper stamper = null;
FileOutputStream fos = null;
-
+
try {
reader = new PdfReader(new FileInputStream(templatePdf));
fos = new FileOutputStream(outputPdf);
stamper = new PdfStamper(reader, fos);
- // 设置中文字体
- BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
+ // 设置中文字体,使用EMBEDDED确保字体嵌入PDF,避免转图片时乱码
+ // 使用itext-asian库提供的中文字体,必须使用EMBEDDED模式
+ BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
Font font = new Font(baseFont, 12, Font.NORMAL);
+
+ log.info("中文字体已加载: {}", baseFont.getPostscriptFontName());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
String currentDate = sdf.format(new Date());
@@ -128,7 +132,7 @@
String realName = user.getRealName() != null ? user.getRealName() : "";
String idCard = user.getIdCard() != null ? user.getIdCard() : "";
String address = user.getRegAddress() != null ? user.getRegAddress() : "";
-
+
log.info("PDF生成数据 - 姓名: {}, 身份证: {}, 地址: {}", realName, idCard, address);
// 获取PDF页数
@@ -154,7 +158,7 @@
reader = null;
fos.close();
fos = null;
-
+
// 验证生成的文件
if (outputPdf.exists()) {
long fileSize = outputPdf.length();
@@ -194,83 +198,277 @@
}
/**
- * 在PDF上替换占位符(使用文本覆盖方式)
+ * 在PDF上替换占位符(使用透明背景图片方式)
*/
private void replacePlaceholdersInPdf(PdfContentByte canvas, Rectangle pageSize, String pageText,
- String realName, String idCard, String address,
- String currentDate, Font font,int pageNum) throws Exception {
- // 查找占位符在文本中的位置,然后估算在PDF中的坐标
- // 由于PDF坐标系统复杂,这里使用固定位置替换
- // 实际使用时需要根据PDF模板的具体布局调整坐标
+ String realName, String idCard, String address,
+ String currentDate, Font font,int pageNum) throws Exception {
float margin = 50;
float lineHeight = 14;
- float startY = pageSize.getHeight() - 194;
+ float startY = pageSize.getHeight() - 204;
if(pageNum == 1){
- replacePlaceholder(canvas, "", realName, margin + 75, startY, 0, font);
+ // 生成透明背景的姓名图片并插入
+ File nameImage = createTextImage(realName, font);
+ insertImageToPdf(canvas, nameImage, margin + 75, startY);
startY -= lineHeight;
- replacePlaceholder(canvas, "", address, margin + 75, startY-2, 0, font);
+ // 生成透明背景的地址图片并插入
+ File addressImage = createTextImage(address, font);
+ insertImageToPdf(canvas, addressImage, margin + 75, startY-2);
startY -= lineHeight;
- replacePlaceholder(canvas, "", idCard, margin + 95, startY-2, 0, font);
+ // 生成透明背景的身份证号图片并插入
+ File idCardImage = createTextImage(idCard, font);
+ insertImageToPdf(canvas, idCardImage, margin + 95, startY-2);
}
if(pageNum == 3){
- replacePlaceholder(canvas, "", currentDate, margin + 60, startY+32, 0, font);
- replacePlaceholder(canvas, "", currentDate, margin + 60, startY, 0, font);
+ // 生成透明背景的日期图片并插入
+ File dateImage1 = createTextImage(currentDate, font);
+ insertImageToPdf(canvas, dateImage1, margin + 60, startY+32);
+
+ File dateImage2 = createTextImage(currentDate, font);
+ insertImageToPdf(canvas, dateImage2, margin + 60, startY);
}
-
}
/**
- * 替换单个占位符
+ * 从资源文件加载字体
*/
- private void replacePlaceholder(PdfContentByte canvas, String placeholder, String value,
- float x, float y, float width, Font font) {
- // 添加白色背景覆盖占位符区域
- canvas.saveState();
- canvas.setColorFill(BaseColor.WHITE);
- canvas.rectangle(x - 5, y - 15, width, 20);
- canvas.fill();
- canvas.restoreState();
+ private java.awt.Font loadFontFromResource(String fontPath, int size) {
+ try {
+ InputStream fontStream = this.getClass().getClassLoader().getResourceAsStream(fontPath);
+ if (fontStream != null) {
+ java.awt.Font font = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, fontStream);
+ font = font.deriveFont(java.awt.Font.PLAIN, size);
+ fontStream.close();
+ log.info("成功从资源文件加载字体: {}", fontPath);
+ return font;
+ }
+ } catch (Exception e) {
+ log.warn("从资源文件加载字体失败: {}, 错误: {}", fontPath, e.getMessage());
+ }
+ return null;
+ }
- // 添加新文本
- ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
- new Phrase(value, font), x, y, 0);
+ /**
+ * 从系统字体目录加载字体文件
+ */
+ private java.awt.Font loadFontFromFile(String fontPath, int size) {
+ try {
+ File fontFile = new File(fontPath);
+ if (fontFile.exists()) {
+ java.awt.Font font = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, fontFile);
+ font = font.deriveFont(java.awt.Font.PLAIN, size);
+ log.info("成功从文件加载字体: {}", fontPath);
+ return font;
+ }
+ } catch (Exception e) {
+ log.warn("从文件加载字体失败: {}, 错误: {}", fontPath, e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * 获取可用的中文字体
+ */
+ private java.awt.Font getChineseFont(int size) {
+ // 1. 优先从资源文件加载字体(如果项目中有字体文件)
+ java.awt.Font font = loadFontFromResource("fonts/simsun.ttf", size);
+ if (font != null) return font;
+
+ font = loadFontFromResource("fonts/simhei.ttf", size);
+ if (font != null) return font;
+
+ // 2. 从系统字体目录加载(Linux常见字体路径)
+ String[] systemFontPaths = {
+ "/usr/share/fonts/chinese/simsun.ttf", // CentOS/RHEL
+ "/usr/share/fonts/truetype/wqy/wqy-microhei.ttf", // 文泉驿
+ "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc", // Noto字体
+ "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", // DejaVu
+ "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf", // Liberation
+ "/usr/share/fonts/chinese/SimSun.ttf",
+ "/usr/share/fonts/chinese/SimHei.ttf",
+ "/usr/share/fonts/truetype/arphic/uming.ttc", // 文鼎字体
+ "/usr/share/fonts/truetype/arphic/ukai.ttc"
+ };
+
+ for (String fontPath : systemFontPaths) {
+ font = loadFontFromFile(fontPath, size);
+ if (font != null) return font;
+ }
+
+ // 3. 按优先级尝试加载系统已安装的字体
+ String[] fontNames = {
+ "SimSun", // 宋体 (Windows)
+ "SimHei", // 黑体 (Windows)
+ "Microsoft YaHei", // 微软雅黑 (Windows)
+ "STSong", // 华文宋体
+ "STHeiti", // 华文黑体
+ "WenQuanYi Micro Hei", // 文泉驿微米黑 (Linux)
+ "WenQuanYi Zen Hei", // 文泉驿正黑 (Linux)
+ "Noto Sans CJK SC", // Noto字体 (Linux)
+ "Droid Sans Fallback", // Android字体 (Linux)
+ "AR PL UMing CN", // 文鼎字体 (Linux)
+ "AR PL UKai CN" // 文鼎字体 (Linux)
+ };
+
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ String[] availableFonts = ge.getAvailableFontFamilyNames();
+
+ // 查找可用的中文字体
+ for (String fontName : fontNames) {
+ for (String availableFont : availableFonts) {
+ if (availableFont.equals(fontName)) {
+ try {
+ font = new java.awt.Font(fontName, java.awt.Font.PLAIN, size);
+ log.info("成功加载系统字体: {}", fontName);
+ return font;
+ } catch (Exception e) {
+ log.warn("加载字体{}失败: {}", fontName, e.getMessage());
+ }
+ }
+ }
+ }
+
+ // 如果找不到中文字体,尝试使用逻辑字体
+ log.warn("未找到可用的中文字体,使用SERIF逻辑字体,可能出现乱码");
+ return new java.awt.Font(java.awt.Font.SERIF, java.awt.Font.PLAIN, size);
+ }
+
+ /**
+ * 创建透明背景的文本图片
+ */
+ private File createTextImage(String text, Font font) throws Exception {
+ if (StringUtils.isBlank(text)) {
+ text = "";
+ }
+
+ // 创建临时文件
+ String tempDir = PropertiesUtil.getProperty("loca.pdf.dir");
+ File dir = new File(tempDir);
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+
+ String tempFileName = "text_" + System.currentTimeMillis() + "_" + Thread.currentThread().getId() + ".png";
+ File imageFile = new File(dir, tempFileName);
+
+ // 创建透明背景的BufferedImage (TYPE_INT_ARGB 默认透明)
+ BufferedImage image = new BufferedImage(500, 50, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g2d = image.createGraphics();
+
+ // 启用透明背景支持
+ g2d.setComposite(java.awt.AlphaComposite.SrcOver);
+
+ // 设置高质量渲染
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
+
+ // 使用可用的中文字体
+ java.awt.Font awtFont = getChineseFont(12);
+ g2d.setFont(awtFont);
+
+ // 使用深黑色,RGB(0, 0, 0) 完全不透明
+ g2d.setColor(new Color(0, 0, 0, 255));
+
+ // 绘制文本
+ FontMetrics fm = g2d.getFontMetrics();
+ int textWidth = fm.stringWidth(text);
+ int textHeight = fm.getHeight();
+
+ // 调整图片大小以适应文本
+ if (textWidth > 0 && textHeight > 0) {
+ // TYPE_INT_ARGB 类型默认透明背景,不需要清除
+ BufferedImage resizedImage = new BufferedImage(textWidth + 20, textHeight + 10, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g2dResized = resizedImage.createGraphics();
+
+ // 启用透明背景支持
+ g2dResized.setComposite(java.awt.AlphaComposite.SrcOver);
+
+ // 设置高质量渲染
+ g2dResized.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2dResized.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
+ g2dResized.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g2dResized.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
+
+ // 使用相同的中文字体
+ g2dResized.setFont(awtFont);
+ // 使用深黑色,RGB(0, 0, 0) 完全不透明
+ g2dResized.setColor(new Color(0, 0, 0, 255));
+
+ // 绘制文本
+ g2dResized.drawString(text, 10, textHeight);
+ g2dResized.dispose();
+
+ // 保存图片
+ ImageIO.write(resizedImage, "PNG", imageFile);
+ image = resizedImage;
+ } else {
+ // 如果文本为空,创建一个小的透明图片
+ BufferedImage emptyImage = new BufferedImage(50, 20, BufferedImage.TYPE_INT_ARGB);
+ ImageIO.write(emptyImage, "PNG", imageFile);
+ image = emptyImage;
+ }
+
+ g2d.dispose();
+
+ log.info("已创建透明背景文本图片: {}, 文本: {}", imageFile.getAbsolutePath(), text);
+ return imageFile;
+ }
+
+ /**
+ * 将图片插入到PDF指定位置
+ */
+ private void insertImageToPdf(PdfContentByte canvas, File imageFile, float x, float y) throws Exception {
+ if (imageFile == null || !imageFile.exists()) {
+ log.warn("图片文件不存在: {}", imageFile);
+ return;
+ }
+
+ try {
+ Image image = Image.getInstance(imageFile.getAbsolutePath());
+ image.setAbsolutePosition(x, y);
+ canvas.addImage(image);
+ log.info("图片已插入到PDF,位置: ({}, {})", x, y);
+
+ // 删除临时图片文件
+ try {
+ imageFile.delete();
+ } catch (Exception e) {
+ log.warn("删除临时图片文件失败: {}", imageFile.getAbsolutePath(), e);
+ }
+ } catch (Exception e) {
+ log.error("插入图片到PDF失败: {}", imageFile.getAbsolutePath(), e);
+ throw e;
+ }
}
@Override
- public void viewAgreementPdf(HttpServletRequest request, HttpServletResponse response) {
+ public ServerResponse viewAgreementPdf(HttpServletRequest request) {
try {
User user = iUserService.getCurrentUser(request);
if (user == null) {
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "用户未登录");
- return;
+ return ServerResponse.createByErrorMsg("用户未登录");
}
- String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir");
- String pdfFileName = "agreement_" + user.getId() + ".pdf";
- File pdfFile = new File(pdfDir, pdfFileName);
-
- if (!pdfFile.exists()) {
- response.sendError(HttpServletResponse.SC_NOT_FOUND, "协议文件不存在,请先生成协议");
- return;
- }
-
- List<String> imageUrls = convertPdfToImages(pdfFile, "contract", user.getId());
+ // 从数据库查询已签名的图片
+ List<ContractImage> contractImages = contractImageMapper.selectByUserIdAndType(user.getId(), "contract");
+ List<String> imageUrls = new ArrayList<>();
- response.setContentType("application/json;charset=UTF-8");
- response.getWriter().write(JSON.toJSONString(ServerResponse.createBySuccess(imageUrls)));
- response.getWriter().flush();
+ if (contractImages != null && !contractImages.isEmpty()) {
+ for (ContractImage image : contractImages) {
+ imageUrls.add(image.getAddress());
+ }
+ log.info("从数据库查询到用户{}的{}张已签名合同图片", user.getId(), imageUrls.size());
+ }
+
+ return ServerResponse.createBySuccess(imageUrls);
} catch (Exception e) {
log.error("查看用户协议PDF失败", e);
- try {
- if (!response.isCommitted()) {
- response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "查看PDF失败: " + e.getMessage());
- }
- } catch (IOException ex) {
- log.error("发送错误响应失败", ex);
- }
+ return ServerResponse.createByErrorMsg("查看PDF失败: " + e.getMessage());
}
}
@@ -294,40 +492,27 @@
String signatureFileName = "signature_" + user.getId() + ".png";
File signatureFileLocal = new File(dir, signatureFileName);
-
+
signatureFile.transferTo(signatureFileLocal);
-
+
log.info("用户{}的签名图片已保存: {}", user.getId(), signatureFileLocal.getAbsolutePath());
-
+
String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir");
- String pdfFileName = "agreement_" + user.getId() + ".pdf";
+ String pdfFileName = "contract_" + user.getId() + ".pdf";
File pdfFile = new File(pdfDir, pdfFileName);
-
+ //删之前的图片
+ deleteFilesWithPattern(pdfDir,"contract_" + user.getId());
if (pdfFile.exists()) {
addSignatureToPdf(pdfFile, signatureFileLocal, user);
-
List<String> imageUrls = convertPdfToImages(pdfFile, "contract", user.getId());
-
- String imagePrefix = PropertiesUtil.getProperty("pdf.server.http.prefix");
- long timestamp = System.currentTimeMillis();
-
- for (int i = 0; i < imageUrls.size(); i++) {
- String imageName;
- if (i == 0) {
- imageName = "contract_" + timestamp + ".png";
- } else {
- imageName = "contract_" + timestamp + "_" + (i + 1) + ".png";
- }
- String imagePath = imagePrefix + "/" + imageName;
-
+ for(String imageUrl : imageUrls) {
ContractImage contractImage = new ContractImage();
contractImage.setUserId(user.getId());
contractImage.setContractType("contract");
- contractImage.setAddress(imagePath);
+ contractImage.setAddress(imageUrl);
contractImage.setAddTime(new Date());
contractImageMapper.insert(contractImage);
}
-
iUserService.updateSignedContract(user.getId(), "Y");
}
return ServerResponse.createBySuccessMsg("签名保存成功");
@@ -346,12 +531,12 @@
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tempPdf));
int pageCount = reader.getNumberOfPages();
-
+
// 在第三页插入签名图片
if (pageCount >= 3) {
PdfContentByte canvas = stamper.getOverContent(3);
Rectangle pageSize = reader.getPageSize(3);
-
+
// 添加签名图片
if (signatureImage.exists()) {
Image image = Image.getInstance(signatureImage.getAbsolutePath());
@@ -366,7 +551,7 @@
stamper.close();
reader.close();
-
+
// 替换原PDF文件
if (tempPdf.exists()) {
pdfFile.delete();
@@ -384,7 +569,7 @@
return ServerResponse.createByErrorMsg("用户未登录");
}
- if (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()) || StringUtils.isBlank(user.getRegAddress())) {
+ if (user.getIsActive()!=2 || StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()) || StringUtils.isBlank(user.getRegAddress())) {
return ServerResponse.createByErrorMsg("用户信息不完整,请先完成实名认证");
}
@@ -394,10 +579,8 @@
dir.mkdirs();
}
- String pdfFileName = "contract_" + user.getId() + ".pdf";
+ String pdfFileName = "agreement_" + user.getId() + ".pdf";
File pdfFile = new File(dir, pdfFileName);
-
- String pdfUrl = PropertiesUtil.getProperty("pdf.server.http.prefix") + "/contract_" + user.getId() + ".pdf";
if (pdfFile.exists()) {
boolean deleted = pdfFile.delete();
@@ -416,7 +599,7 @@
// 将PDF转换为图片并返回图片路径数组
List<String> imageUrls = convertPdfToImages(pdfFile, "agreement", user.getId());
-
+
return ServerResponse.createBySuccess(imageUrls);
} catch (Exception e) {
log.error("生成用户合同PDF失败", e);
@@ -433,17 +616,17 @@
return;
}
- String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir");
- String pdfFileName = "contract_" + user.getId() + ".pdf";
- File pdfFile = new File(pdfDir, pdfFileName);
-
- if (!pdfFile.exists()) {
- response.sendError(HttpServletResponse.SC_NOT_FOUND, "合同文件不存在,请先生成合同");
- return;
+ // 从数据库查询已签名的图片
+ List<ContractImage> contractImages = contractImageMapper.selectByUserIdAndType(user.getId(), "agreement");
+ List<String> imageUrls = new ArrayList<>();
+
+ if (contractImages != null && !contractImages.isEmpty()) {
+ for (ContractImage image : contractImages) {
+ imageUrls.add(image.getAddress());
+ }
+ log.info("从数据库查询到用户{}的{}张已签名保密协议图片", user.getId(), imageUrls.size());
}
- List<String> imageUrls = convertPdfToImages(pdfFile, "agreement", user.getId());
-
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(ServerResponse.createBySuccess(imageUrls)));
response.getWriter().flush();
@@ -477,45 +660,33 @@
dir.mkdirs();
}
- String signatureFileName = "contract_signature_" + user.getId() + ".png";
+ String signatureFileName = "agreement_signature_" + user.getId() + ".png";
File signatureFileLocal = new File(dir, signatureFileName);
-
+
signatureFile.transferTo(signatureFileLocal);
-
+
log.info("用户{}的合同签名图片已保存: {}", user.getId(), signatureFileLocal.getAbsolutePath());
-
+
String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir");
- String pdfFileName = "contract_" + user.getId() + ".pdf";
+ String pdfFileName = "agreement_" + user.getId() + ".pdf";
File pdfFile = new File(pdfDir, pdfFileName);
-
+ //删之前的图片
+ deleteFilesWithPattern(pdfDir,"agreement_" + user.getId());
if (pdfFile.exists()) {
addSignatureToContractPdf(pdfFile, signatureFileLocal, user);
-
+
List<String> imageUrls = convertPdfToImages(pdfFile, "agreement", user.getId());
-
- String imagePrefix = PropertiesUtil.getProperty("pdf.server.http.prefix");
- long timestamp = System.currentTimeMillis();
-
- for (int i = 0; i < imageUrls.size(); i++) {
- String imageName;
- if (i == 0) {
- imageName = "agreement_" + timestamp + ".png";
- } else {
- imageName = "agreement_" + timestamp + "_" + (i + 1) + ".png";
- }
- String imagePath = imagePrefix + "/" + imageName;
-
+ for (String imageUrl : imageUrls) {
ContractImage contractImage = new ContractImage();
contractImage.setUserId(user.getId());
contractImage.setContractType("agreement");
- contractImage.setAddress(imagePath);
+ contractImage.setAddress(imageUrl);
contractImage.setAddTime(new Date());
contractImageMapper.insert(contractImage);
}
-
iUserService.updateSignedAgreement(user.getId(), "Y");
}
-
+
return ServerResponse.createBySuccessMsg("签名保存成功");
} catch (Exception e) {
log.error("保存用户合同签名失败", e);
@@ -527,11 +698,12 @@
PdfReader reader = new PdfReader(new FileInputStream(templatePdf));
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputPdf));
- BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
+ // 设置中文字体,使用EMBEDDED确保字体嵌入PDF,避免转图片时乱码
+ BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
Font font = new Font(baseFont, 12, Font.NORMAL);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
String currentDate = sdf.format(new Date());
-
+
int pageCount = reader.getNumberOfPages();
for (int pageNum = 1; pageNum <= pageCount; pageNum++) {
@@ -547,9 +719,11 @@
private void replacePlaceholdersInContractPdf(PdfContentByte canvas, Rectangle pageSize, String currentDate, Font font, int pageNum) throws Exception {
float margin = 50;
- float startY = pageSize.getHeight() - 364;
+ float startY = pageSize.getHeight() - 374;
if(pageNum == 2){
- replacePlaceholder(canvas, "", currentDate, margin + 320, startY, 0, font);
+ // 生成透明背景的日期图片并插入
+ File dateImage = createTextImage(currentDate, font);
+ insertImageToPdf(canvas, dateImage, margin + 320, startY);
}
}
@@ -559,11 +733,11 @@
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tempPdf));
int pageCount = reader.getNumberOfPages();
-
+
if (pageCount >= 2) {
PdfContentByte canvas = stamper.getOverContent(2);
Rectangle pageSize = reader.getPageSize(2);
-
+
if (signatureImage.exists()) {
Image image = Image.getInstance(signatureImage.getAbsolutePath());
image.scaleToFit(100, 100);
@@ -575,7 +749,7 @@
stamper.close();
reader.close();
-
+
if (tempPdf.exists()) {
pdfFile.delete();
tempPdf.renameTo(pdfFile);
@@ -593,19 +767,19 @@
log.error("PDF模板目录配置不存在: pdf.template.dir");
return null;
}
-
+
File dir = new File(templateDir);
if (!dir.exists()) {
log.error("PDF模板目录不存在: {}", templateDir);
return null;
}
-
+
File templateFile = new File(dir, templateFileName);
if (!templateFile.exists()) {
log.error("PDF模板文件不存在: {}", templateFile.getAbsolutePath());
return null;
}
-
+
log.info("使用模板文件: {}", templateFile.getAbsolutePath());
return templateFile;
} catch (Exception e) {
@@ -613,7 +787,6 @@
return null;
}
}
-
/**
* 将PDF转换为图片
*/
@@ -621,37 +794,37 @@
List<String> imageUrls = new ArrayList<>();
String imagePrefix = PropertiesUtil.getProperty("pdf.server.http.prefix");
String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir");
-
+
long timestamp = System.currentTimeMillis();
PDDocument document = null;
try {
document = PDDocument.load(pdfFile);
-
+
// 创建PDFRenderer,使用高质量渲染
PDFRenderer pdfRenderer = new PDFRenderer(document);
-
+
int pageCount = document.getNumberOfPages();
log.info("PDF总页数: {}", pageCount);
-
+
for (int page = 0; page < pageCount; page++) {
// 使用RGB模式渲染,DPI设置为300确保文字清晰
// ImageType.RGB可以更好地处理中文字体
BufferedImage image = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
-
+
// 对图片进行优化处理,确保文字清晰
BufferedImage optimizedImage = optimizeImage(image);
-
- String imageFileName = contractType + "_" + timestamp + ".png";
+
+ String imageFileName = contractType + "_" +userId +"_" + timestamp + ".png";
if (page > 0) {
- imageFileName = contractType + "_" + timestamp + "_" + (page + 1) + ".png";
+ imageFileName = contractType+ "_" + userId + "_" + timestamp + "_" + (page + 1) + ".png";
}
File imageFile = new File(pdfDir, imageFileName);
-
+
ImageIO.write(optimizedImage, "png", imageFile);
-
- String imageUrl = imagePrefix + "/imgs/" + imageFileName;
+
+ String imageUrl = imagePrefix + "/" + imageFileName;
imageUrls.add(imageUrl);
-
+
log.info("PDF第{}页已转换为图片: {}", page + 1, imageUrl);
}
} finally {
@@ -659,30 +832,30 @@
document.close();
}
}
-
+
return imageUrls;
}
-
+
/**
* 优化图片,确保文字清晰
*/
private BufferedImage optimizeImage(BufferedImage originalImage) {
int width = originalImage.getWidth();
int height = originalImage.getHeight();
-
+
BufferedImage optimizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = optimizedImage.createGraphics();
-
+
// 设置高质量渲染
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-
+
g2d.drawImage(originalImage, 0, 0, null);
g2d.dispose();
-
+
return optimizedImage;
}
@@ -699,7 +872,7 @@
for (ContractImage image : images) {
imageUrls.add(image.getAddress());
}
-
+
return ServerResponse.createBySuccess(imageUrls);
} catch (Exception e) {
log.error("查询合同图片列表失败", e);
@@ -720,11 +893,30 @@
for (ContractImage image : images) {
imageUrls.add(image.getAddress());
}
-
+
return ServerResponse.createBySuccess(imageUrls);
} catch (Exception e) {
log.error("查询保密协议图片列表失败", e);
return ServerResponse.createByErrorMsg("查询失败:" + e.getMessage());
}
}
+
+ public void deleteFilesWithPattern(String dirPath, String userId) {
+ File directory = new File(dirPath);
+ if (!directory.exists() || !directory.isDirectory()) {
+ System.out.println("目录不存在或路径错误: " + dirPath);
+ return;
+ }
+
+ File[] files = directory.listFiles((dir, name) -> name.contains(userId + "_"));
+ if (files != null) {
+ for (File file : files) {
+ if (file.delete()) {
+ System.out.println("已删除文件: " + file.getName());
+ } else {
+ System.out.println("删除失败: " + file.getName());
+ }
+ }
+ }
+ }
}
--
Gitblit v1.9.3