| | |
| | | import java.io.*; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import com.itextpdf.text.*; |
| | | import com.itextpdf.text.pdf.*; |
| | |
| | | private com.nq.service.IUserService iUserService; |
| | | |
| | | @Override |
| | | |
| | | // 在generateAgreementPdf方法中修改返回逻辑 |
| | | public ServerResponse generateAgreementPdf(HttpServletRequest request) { |
| | | try { |
| | | User user = iUserService.getCurrentUser(request); |
| | | user = (User) iUserService.findByUserId(user.getId()).getData(); |
| | | if (user == null) { |
| | | return ServerResponse.createByErrorMsg("用户未登录"); |
| | | } |
| | |
| | | } |
| | | |
| | | // 检查是否已生成PDF |
| | | String pdfDir = PropertiesUtil.getProperty("agreement.pdf.dir", System.getProperty("user.dir") + "/agreement_pdf"); |
| | | String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir"); |
| | | |
| | | File dir = new File(pdfDir); |
| | | if (!dir.exists()) { |
| | | dir.mkdirs(); |
| | |
| | | |
| | | String pdfFileName = "agreement_" + 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()) { |
| | | return ServerResponse.createBySuccess(pdfFileName); |
| | | log.info("PDF文件已存在,删除后重新生成: {}", pdfFile.getAbsolutePath()); |
| | | boolean deleted = pdfFile.delete(); |
| | | if (!deleted) { |
| | | log.warn("删除旧PDF文件失败: {}", pdfFile.getAbsolutePath()); |
| | | } |
| | | } |
| | | |
| | | // 获取模板文件路径 |
| | | String templatePath = this.getClass().getResource("/templates").getPath(); |
| | | if (templatePath.startsWith("/") && System.getProperty("os.name").toLowerCase().contains("windows")) { |
| | | templatePath = templatePath.substring(1); |
| | | } |
| | | templatePath = templatePath.replaceAll("%20", " "); |
| | | if (templatePath.contains("file:")) { |
| | | templatePath = templatePath.substring(templatePath.indexOf("file:") + 5); |
| | | } |
| | | if (templatePath.contains("!")) { |
| | | templatePath = templatePath.substring(0, templatePath.indexOf("!")); |
| | | } |
| | | |
| | | // 使用PDF模板文件 |
| | | File pdfTemplate = new File(templatePath, "中原证券股票分成协议(电子正式版).pdf"); |
| | | if (!pdfTemplate.exists()) { |
| | | // 从资源中读取PDF模板文件 |
| | | File pdfTemplate = getTemplateFile("中原证券股票分成协议(电子正式版).pdf"); |
| | | if (pdfTemplate == null || !pdfTemplate.exists()) { |
| | | return ServerResponse.createByErrorMsg("PDF模板文件不存在"); |
| | | } |
| | | |
| | | // 从PDF模板生成新的PDF,替换占位符 |
| | | generatePdfFromTemplate(pdfTemplate, pdfFile, user); |
| | | |
| | | return ServerResponse.createBySuccess(pdfFileName); |
| | | return ServerResponse.createBySuccess(pdfUrl); |
| | | } catch (Exception e) { |
| | | log.error("生成用户协议PDF失败", e); |
| | | return ServerResponse.createByErrorMsg("生成PDF失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | public static void main(String[] args) { |
| | | generateAgreementPdf11(); |
| | | } |
| | | |
| | | public static void generateAgreementPdf11() { |
| | | try { |
| | | |
| | | // 检查是否已生成PDF |
| | | String pdfDir = PropertiesUtil.getProperty("agreement.pdf.dir", System.getProperty("user.dir") + "/agreement_pdf"); |
| | | File dir = new File(pdfDir); |
| | | if (!dir.exists()) { |
| | | dir.mkdirs(); |
| | | } |
| | | |
| | | String pdfFileName = "agreement_111.pdf"; |
| | | File pdfFile = new File(dir, pdfFileName); |
| | | |
| | | // 获取模板文件路径 |
| | | String templatePath = "D:/work/A-stock/src/main/resources/templates"; |
| | | if (templatePath.startsWith("/") && System.getProperty("os.name").toLowerCase().contains("windows")) { |
| | | templatePath = templatePath.substring(1); |
| | | } |
| | | templatePath = templatePath.replaceAll("%20", " "); |
| | | if (templatePath.contains("file:")) { |
| | | templatePath = templatePath.substring(templatePath.indexOf("file:") + 5); |
| | | } |
| | | if (templatePath.contains("!")) { |
| | | templatePath = templatePath.substring(0, templatePath.indexOf("!")); |
| | | } |
| | | |
| | | // 使用PDF模板文件 |
| | | File pdfTemplate = new File(templatePath, "中原证券股票分成协议(电子正式版).pdf"); |
| | | if (!pdfTemplate.exists()) { |
| | | System.out.println("PDF模板文件不存在"); |
| | | } |
| | | |
| | | // 从PDF模板生成新的PDF,替换占位符 |
| | | generatePdfFromTemplate1(pdfTemplate, pdfFile); |
| | | |
| | | |
| | | } catch (Exception e) { |
| | | log.error("生成用户协议PDF失败", e); |
| | | |
| | | } |
| | | } |
| | | public static void generatePdfFromTemplate1(File templatePdf, File outputPdf) throws Exception { |
| | | 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); |
| | | Font font = new Font(baseFont, 12, Font.NORMAL); |
| | | // Font boldFont = new Font(baseFont, 12, Font.BOLD); |
| | | // BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); |
| | | // Font font = new Font(baseFont, 5, Font.BOLD); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); |
| | | String currentDate = sdf.format(new Date()); |
| | | |
| | | // 准备替换的数据 |
| | | String realName = "陈大雷"; |
| | | String idCard = "433123198802456635"; |
| | | String address = "广东省清远市三八街道明星之城18栋2单元1506"; |
| | | |
| | | // 获取PDF页数 |
| | | int pageCount = reader.getNumberOfPages(); |
| | | |
| | | // 在每一页上查找并替换占位符 |
| | | for (int pageNum = 1; pageNum <= pageCount; pageNum++) { |
| | | PdfContentByte canvas = stamper.getOverContent(pageNum); |
| | | Rectangle pageSize = reader.getPageSize(pageNum); |
| | | |
| | | // 提取PDF文本查找占位符位置 |
| | | String pageText = PdfTextExtractor.getTextFromPage(reader, pageNum, new SimpleTextExtractionStrategy()); |
| | | |
| | | // 在PDF上查找并替换占位符 |
| | | replacePlaceholdersInPdf1(canvas, pageSize, pageText, realName, idCard, address, currentDate, font,pageNum); |
| | | // 添加签名 |
| | | if(pageNum == 3){ |
| | | // 添加签名 |
| | | addHeaderImageToPdf(canvas, templatePdf.getParent(), pageSize); |
| | | } |
| | | } |
| | | |
| | | stamper.close(); |
| | | reader.close(); |
| | | } |
| | | |
| | | /** |
| | | * 在PDF上替换占位符(使用文本覆盖方式) |
| | | */ |
| | | public static void replacePlaceholdersInPdf1(PdfContentByte canvas, Rectangle pageSize, String pageText, |
| | | String realName, String idCard, String address, |
| | | String currentDate, Font font,int pageNum) throws Exception { |
| | | // 查找占位符在文本中的位置,然后估算在PDF中的坐标 |
| | | // 由于PDF坐标系统复杂,这里使用固定位置替换 |
| | | // 实际使用时需要根据PDF模板的具体布局调整坐标 |
| | | |
| | | float margin = 50; |
| | | float lineHeight = 14; |
| | | float startY = pageSize.getHeight() - 194; |
| | | |
| | | if(pageNum == 1){ |
| | | replacePlaceholder1(canvas, "", realName, margin + 75, startY, 0, font); |
| | | startY -= lineHeight; |
| | | |
| | | replacePlaceholder1(canvas, "", address, margin + 75, startY-2, 0, font); |
| | | startY -= lineHeight; |
| | | |
| | | replacePlaceholder1(canvas, "", idCard, margin + 95, startY-2, 0, font); |
| | | } |
| | | if(pageNum == 3){ |
| | | replacePlaceholder1(canvas, "", currentDate, margin + 60, startY+32, 0, font); |
| | | replacePlaceholder1(canvas, "", currentDate, margin + 60, startY, 0, font); |
| | | } |
| | | |
| | | // if (pageText.contains("${jcurrentDate}")) { |
| | | // replacePlaceholder1(canvas, "${jcurrentDate}", currentDate, margin + 100, startY, 150, font); |
| | | // startY -= lineHeight; |
| | | // } |
| | | // |
| | | // if (pageText.contains("${ucurrentDate}")) { |
| | | // replacePlaceholder1(canvas, "${ucurrentDate}", currentDate, margin + 100, startY, 300, font); |
| | | // } |
| | | } |
| | | |
| | | /** |
| | | * 在PDF左上角添加图片 |
| | | */ |
| | | public static void addHeaderImageToPdf(PdfContentByte canvas, String templatePath, Rectangle pageSize) throws Exception { |
| | | // 获取图片路径 |
| | | String imagePath = templatePath + File.separator + "zczq.png"; |
| | | File imageFile = new File(imagePath); |
| | | // 如果使用相对路径找不到,尝试从resources获取 |
| | | if (!imageFile.exists()) { |
| | | String resourcePath = "D:/work/A-stock/src/main/resources/templates"; |
| | | if (resourcePath.startsWith("/") && System.getProperty("os.name").toLowerCase().contains("windows")) { |
| | | resourcePath = resourcePath.substring(1); |
| | | } |
| | | resourcePath = resourcePath.replaceAll("%20", " "); |
| | | if (resourcePath.contains("file:")) { |
| | | resourcePath = resourcePath.substring(resourcePath.indexOf("file:") + 5); |
| | | } |
| | | if (resourcePath.contains("!")) { |
| | | resourcePath = resourcePath.substring(0, resourcePath.indexOf("!")); |
| | | } |
| | | imageFile = new File(resourcePath); |
| | | } |
| | | |
| | | if (imageFile.exists()) { |
| | | Image image = Image.getInstance(imageFile.getAbsolutePath()); |
| | | // 设置图片大小 |
| | | image.scaleToFit(100, 100); |
| | | // 设置图片位置(左上角) |
| | | image.setAbsolutePosition(370, pageSize.getHeight() - 194); |
| | | canvas.addImage(image); |
| | | } else { |
| | | log.warn("未找到图片文件: {}", imagePath); |
| | | } |
| | | } |
| | | /** |
| | | * 替换单个占位符 |
| | | */ |
| | | public static void replacePlaceholder1(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(); |
| | | |
| | | // 添加新文本 |
| | | ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, |
| | | new Phrase(value, font), x, y, 0); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从PDF模板生成新的PDF,替换占位符 |
| | | */ |
| | | private void generatePdfFromTemplate(File templatePdf, File outputPdf, User user) throws Exception { |
| | | PdfReader reader = new PdfReader(new FileInputStream(templatePdf)); |
| | | PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputPdf)); |
| | | 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); |
| | | Font font = new Font(baseFont, 12, Font.NORMAL); |
| | | Font boldFont = new Font(baseFont, 12, Font.BOLD); |
| | | // 设置中文字体 |
| | | BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); |
| | | Font font = new Font(baseFont, 12, Font.NORMAL); |
| | | Font boldFont = new Font(baseFont, 12, Font.BOLD); |
| | | |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); |
| | | String currentDate = sdf.format(new Date()); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); |
| | | String currentDate = sdf.format(new Date()); |
| | | |
| | | // 准备替换的数据 |
| | | String realName = user.getRealName() != null ? user.getRealName() : ""; |
| | | String idCard = user.getIdCard() != null ? user.getIdCard() : ""; |
| | | String address = user.getRegAddress() != null ? user.getRegAddress() : ""; |
| | | // 准备替换的数据 |
| | | 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页数 |
| | | int pageCount = reader.getNumberOfPages(); |
| | | // 获取PDF页数 |
| | | int pageCount = reader.getNumberOfPages(); |
| | | log.info("PDF模板页数: {}", pageCount); |
| | | |
| | | // 在每一页上查找并替换占位符 |
| | | for (int pageNum = 1; pageNum <= pageCount; pageNum++) { |
| | | PdfContentByte canvas = stamper.getOverContent(pageNum); |
| | | Rectangle pageSize = reader.getPageSize(pageNum); |
| | | // 在每一页上查找并替换占位符 |
| | | for (int pageNum = 1; pageNum <= pageCount; pageNum++) { |
| | | PdfContentByte canvas = stamper.getOverContent(pageNum); |
| | | Rectangle pageSize = reader.getPageSize(pageNum); |
| | | |
| | | // 提取PDF文本查找占位符位置 |
| | | String pageText = PdfTextExtractor.getTextFromPage(reader, pageNum, new SimpleTextExtractionStrategy()); |
| | | // 提取PDF文本查找占位符位置 |
| | | String pageText = PdfTextExtractor.getTextFromPage(reader, pageNum, new SimpleTextExtractionStrategy()); |
| | | |
| | | // 在PDF上查找并替换占位符 |
| | | replacePlaceholdersInPdf(canvas, pageSize, pageText, realName, idCard, address, currentDate, font,pageNum); |
| | | // 在PDF上查找并替换占位符 |
| | | replacePlaceholdersInPdf(canvas, pageSize, pageText, realName, idCard, address, currentDate, font, pageNum); |
| | | log.info("已处理PDF第{}页", pageNum); |
| | | } |
| | | |
| | | stamper.close(); |
| | | stamper = null; |
| | | reader.close(); |
| | | reader = null; |
| | | fos.close(); |
| | | fos = null; |
| | | |
| | | // 验证生成的文件 |
| | | if (outputPdf.exists()) { |
| | | long fileSize = outputPdf.length(); |
| | | log.info("PDF生成完成,文件路径: {}, 文件大小: {} 字节", outputPdf.getAbsolutePath(), fileSize); |
| | | if (fileSize == 0) { |
| | | throw new Exception("生成的PDF文件大小为0"); |
| | | } |
| | | } else { |
| | | throw new Exception("PDF文件生成失败,文件不存在"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("生成PDF失败", e); |
| | | throw e; |
| | | } finally { |
| | | if (stamper != null) { |
| | | try { |
| | | stamper.close(); |
| | | } catch (Exception e) { |
| | | log.error("关闭stamper失败", e); |
| | | } |
| | | } |
| | | if (reader != null) { |
| | | try { |
| | | reader.close(); |
| | | } catch (Exception e) { |
| | | log.error("关闭reader失败", e); |
| | | } |
| | | } |
| | | if (fos != null) { |
| | | try { |
| | | fos.close(); |
| | | } catch (Exception e) { |
| | | log.error("关闭输出流失败", e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | stamper.close(); |
| | | reader.close(); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | @Override |
| | | public void viewAgreementPdf(HttpServletRequest request, HttpServletResponse response) { |
| | | FileInputStream fis = null; |
| | | OutputStream os = null; |
| | | try { |
| | | User user = iUserService.getCurrentUser(request); |
| | | if (user == null) { |
| | |
| | | return; |
| | | } |
| | | |
| | | String pdfDir = PropertiesUtil.getProperty("agreement.pdf.dir", System.getProperty("user.dir") + "/agreement_pdf"); |
| | | String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir"); |
| | | String pdfFileName = "agreement_" + user.getId() + ".pdf"; |
| | | File pdfFile = new File(pdfDir, pdfFileName); |
| | | |
| | | log.info("查看PDF文件,路径: {}, 是否存在: {}, 文件大小: {}", |
| | | pdfFile.getAbsolutePath(), pdfFile.exists(), |
| | | pdfFile.exists() ? pdfFile.length() : 0); |
| | | |
| | | if (!pdfFile.exists()) { |
| | | response.sendError(HttpServletResponse.SC_NOT_FOUND, "协议文件不存在,请先生成协议"); |
| | | return; |
| | | } |
| | | |
| | | long fileLength = pdfFile.length(); |
| | | if (fileLength == 0) { |
| | | log.error("PDF文件大小为0: {}", pdfFile.getAbsolutePath()); |
| | | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "PDF文件为空"); |
| | | return; |
| | | } |
| | | |
| | | // 验证PDF文件头 |
| | | FileInputStream checkFis = new FileInputStream(pdfFile); |
| | | byte[] header = new byte[4]; |
| | | checkFis.read(header); |
| | | checkFis.close(); |
| | | String headerStr = new String(header); |
| | | if (!headerStr.startsWith("%PDF")) { |
| | | log.error("文件不是有效的PDF格式,文件头: {}", headerStr); |
| | | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "PDF文件格式错误"); |
| | | return; |
| | | } |
| | | log.info("PDF文件头验证通过: {}", headerStr); |
| | | |
| | | response.setContentType("application/pdf"); |
| | | response.setHeader("Content-Disposition", "inline; filename=" + pdfFileName); |
| | | response.setHeader("Content-Disposition", "inline; filename=\"" + |
| | | new String(pdfFileName.getBytes("UTF-8"), "ISO-8859-1") + "\""); |
| | | response.setContentLengthLong(fileLength); |
| | | response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); |
| | | response.setHeader("Pragma", "no-cache"); |
| | | response.setDateHeader("Expires", 0); |
| | | |
| | | FileInputStream fis = new FileInputStream(pdfFile); |
| | | OutputStream os = response.getOutputStream(); |
| | | fis = new FileInputStream(pdfFile); |
| | | os = response.getOutputStream(); |
| | | |
| | | byte[] buffer = new byte[8192]; |
| | | int bytesRead; |
| | | long totalBytes = 0; |
| | | while ((bytesRead = fis.read(buffer)) != -1) { |
| | | os.write(buffer, 0, bytesRead); |
| | | totalBytes += bytesRead; |
| | | } |
| | | |
| | | log.info("PDF文件传输完成,总字节数: {}", totalBytes); |
| | | os.flush(); |
| | | } 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); |
| | | } |
| | | } finally { |
| | | if (fis != null) { |
| | | try { |
| | | fis.close(); |
| | | } catch (IOException e) { |
| | | log.error("关闭文件流失败", e); |
| | | } |
| | | } |
| | | if (os != null) { |
| | | try { |
| | | os.close(); |
| | | } catch (IOException e) { |
| | | log.error("关闭输出流失败", e); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public ServerResponse saveAgreementSignature(MultipartFile signatureFile, HttpServletRequest request) { |
| | | try { |
| | | User user = iUserService.getCurrentUser(request); |
| | | if (user == null) { |
| | | return ServerResponse.createByErrorMsg("用户未登录"); |
| | | } |
| | | |
| | | if (signatureFile == null || signatureFile.isEmpty()) { |
| | | return ServerResponse.createByErrorMsg("签名图片不能为空"); |
| | | } |
| | | |
| | | // 保存签名图片到本地 |
| | | String signatureDir = PropertiesUtil.getProperty("loca.pdf.dir"); |
| | | File dir = new File(signatureDir); |
| | | if (!dir.exists()) { |
| | | dir.mkdirs(); |
| | | } |
| | | |
| | | String signatureFileName = "signature_" + user.getId() + ".png"; |
| | | File signatureFileLocal = new File(dir, signatureFileName); |
| | | |
| | | signatureFile.transferTo(signatureFileLocal); |
| | | |
| | | log.info("用户{}的签名图片已保存: {}", user.getId(), signatureFileLocal.getAbsolutePath()); |
| | | |
| | | // 重新生成PDF并插入签名图片 |
| | | String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir"); |
| | | String pdfFileName = "agreement_" + user.getId() + ".pdf"; |
| | | File pdfFile = new File(pdfDir, pdfFileName); |
| | | |
| | | if (pdfFile.exists()) { |
| | | // 在PDF第三页插入签名图片 |
| | | addSignatureToPdf(pdfFile, signatureFileLocal, user); |
| | | |
| | | // 构建PDF访问地址 |
| | | String pdfUrl = PropertiesUtil.getProperty("pdf.server.http.prefix") + "/agreement_" + user.getId() + ".pdf"; |
| | | |
| | | // 更新用户表的签合同标记(保存PDF地址) |
| | | iUserService.updateSignedContract(user.getId(),pdfUrl); |
| | | } |
| | | return ServerResponse.createBySuccessMsg("签名保存成功"); |
| | | } catch (Exception e) { |
| | | log.error("保存用户协议签名失败", e); |
| | | return ServerResponse.createByErrorMsg("保存签名失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 在PDF第三页插入签名图片 |
| | | */ |
| | | private void addSignatureToPdf(File pdfFile, File signatureImage, User user) throws Exception { |
| | | PdfReader reader = new PdfReader(new FileInputStream(pdfFile)); |
| | | File tempPdf = new File(pdfFile.getParent(), "temp_" + pdfFile.getName()); |
| | | 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()); |
| | | // 设置图片大小(根据实际需要调整) |
| | | image.scaleToFit(100, 100); |
| | | // 设置图片位置(使用与addHeaderImageToPdf相同的坐标) |
| | | image.setAbsolutePosition(370, pageSize.getHeight() - 194); |
| | | canvas.addImage(image); |
| | | log.info("签名图片已插入到PDF第三页,位置: (370, {})", pageSize.getHeight() - 194); |
| | | } |
| | | } |
| | | |
| | | stamper.close(); |
| | | reader.close(); |
| | | |
| | | // 替换原PDF文件 |
| | | if (tempPdf.exists()) { |
| | | pdfFile.delete(); |
| | | tempPdf.renameTo(pdfFile); |
| | | log.info("PDF文件已更新,签名图片已插入"); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public ServerResponse generateAgreementContractPdf(HttpServletRequest request) { |
| | | try { |
| | | User user = iUserService.getCurrentUser(request); |
| | | user = (User) iUserService.findByUserId(user.getId()).getData(); |
| | | if (user == null) { |
| | | return ServerResponse.createByErrorMsg("用户未登录"); |
| | | } |
| | | |
| | | if (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()) || StringUtils.isBlank(user.getRegAddress())) { |
| | | return ServerResponse.createByErrorMsg("用户信息不完整,请先完成实名认证"); |
| | | } |
| | | |
| | | String pdfDir = PropertiesUtil.getProperty("loca.pdf.dir"); |
| | | File dir = new File(pdfDir); |
| | | if (!dir.exists()) { |
| | | dir.mkdirs(); |
| | | } |
| | | |
| | | String pdfFileName = "contract_" + 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(); |
| | | if (!deleted) { |
| | | log.warn("删除旧PDF文件失败: {}", pdfFile.getAbsolutePath()); |
| | | } |
| | | } |
| | | |
| | | // 从资源中读取PDF模板文件 |
| | | File pdfTemplate = getTemplateFile("中原证券商业核心信息保密协议.pdf"); |
| | | if (pdfTemplate == null || !pdfTemplate.exists()) { |
| | | return ServerResponse.createByErrorMsg("PDF模板文件不存在"); |
| | | } |
| | | |
| | | generateContractPdfFromTemplate(pdfTemplate, pdfFile, user); |
| | | |
| | | return ServerResponse.createBySuccess(pdfUrl); |
| | | } catch (Exception e) { |
| | | log.error("生成用户合同PDF失败", e); |
| | | return ServerResponse.createByErrorMsg("生成PDF失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void viewAgreementContractPdf(HttpServletRequest request, HttpServletResponse response) { |
| | | FileInputStream fis = null; |
| | | OutputStream os = null; |
| | | try { |
| | | User user = iUserService.getCurrentUser(request); |
| | | if (user == null) { |
| | | response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "用户未登录"); |
| | | 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; |
| | | } |
| | | |
| | | long fileLength = pdfFile.length(); |
| | | if (fileLength == 0) { |
| | | log.error("PDF文件大小为0: {}", pdfFile.getAbsolutePath()); |
| | | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "PDF文件为空"); |
| | | return; |
| | | } |
| | | |
| | | FileInputStream checkFis = new FileInputStream(pdfFile); |
| | | byte[] header = new byte[4]; |
| | | checkFis.read(header); |
| | | checkFis.close(); |
| | | String headerStr = new String(header); |
| | | if (!headerStr.startsWith("%PDF")) { |
| | | log.error("文件不是有效的PDF格式,文件头: {}", headerStr); |
| | | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "PDF文件格式错误"); |
| | | return; |
| | | } |
| | | |
| | | response.setContentType("application/pdf"); |
| | | response.setHeader("Content-Disposition", "inline; filename=\"" + |
| | | new String(pdfFileName.getBytes("UTF-8"), "ISO-8859-1") + "\""); |
| | | response.setContentLengthLong(fileLength); |
| | | response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); |
| | | |
| | | fis = new FileInputStream(pdfFile); |
| | | os = response.getOutputStream(); |
| | | byte[] buffer = new byte[4096]; |
| | | int bytesRead; |
| | | while ((bytesRead = fis.read(buffer)) != -1) { |
| | | os.write(buffer, 0, bytesRead); |
| | | } |
| | | |
| | | fis.close(); |
| | | os.flush(); |
| | | os.close(); |
| | | } catch (Exception e) { |
| | | log.error("查看用户协议PDF失败", e); |
| | | log.error("查看用户合同PDF失败", e); |
| | | try { |
| | | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "查看PDF失败"); |
| | | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "查看PDF失败: " + e.getMessage()); |
| | | } catch (IOException ex) { |
| | | log.error("发送错误响应失败", ex); |
| | | } |
| | | } finally { |
| | | if (fis != null) { |
| | | try { |
| | | fis.close(); |
| | | } catch (IOException e) { |
| | | log.error("关闭文件流失败", e); |
| | | } |
| | | } |
| | | if (os != null) { |
| | | try { |
| | | os.close(); |
| | | } catch (IOException e) { |
| | | log.error("关闭输出流失败", e); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public ServerResponse saveAgreementContractSignature(MultipartFile signatureFile, HttpServletRequest request) { |
| | | try { |
| | | User user = iUserService.getCurrentUser(request); |
| | | if (user == null) { |
| | | return ServerResponse.createByErrorMsg("用户未登录"); |
| | | } |
| | | |
| | | if (signatureFile == null || signatureFile.isEmpty()) { |
| | | return ServerResponse.createByErrorMsg("签名图片不能为空"); |
| | | } |
| | | |
| | | String signatureDir = PropertiesUtil.getProperty("loca.pdf.dir"); |
| | | File dir = new File(signatureDir); |
| | | if (!dir.exists()) { |
| | | dir.mkdirs(); |
| | | } |
| | | |
| | | String signatureFileName = "contract_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"; |
| | | File pdfFile = new File(pdfDir, pdfFileName); |
| | | |
| | | if (pdfFile.exists()) { |
| | | addSignatureToContractPdf(pdfFile, signatureFileLocal, user); |
| | | |
| | | String pdfUrl = PropertiesUtil.getProperty("pdf.server.http.prefix") + "/contract_" + user.getId() + ".pdf"; |
| | | |
| | | iUserService.updateSignedAgreement(user.getId(), pdfUrl); |
| | | } |
| | | |
| | | return ServerResponse.createBySuccessMsg("签名保存成功"); |
| | | } catch (Exception e) { |
| | | log.error("保存用户合同签名失败", e); |
| | | return ServerResponse.createByErrorMsg("保存签名失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | private void generateContractPdfFromTemplate(File templatePdf, File outputPdf, User user) throws Exception { |
| | | 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); |
| | | 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++) { |
| | | PdfContentByte canvas = stamper.getOverContent(pageNum); |
| | | Rectangle pageSize = reader.getPageSize(pageNum); |
| | | |
| | | replacePlaceholdersInContractPdf(canvas, pageSize, currentDate, font, pageNum); |
| | | } |
| | | |
| | | stamper.close(); |
| | | reader.close(); |
| | | } |
| | | |
| | | private void replacePlaceholdersInContractPdf(PdfContentByte canvas, Rectangle pageSize, String currentDate, Font font, int pageNum) throws Exception { |
| | | float margin = 50; |
| | | float startY = pageSize.getHeight() - 364; |
| | | if(pageNum == 2){ |
| | | replacePlaceholder(canvas, "", currentDate, margin + 320, startY, 0, font); |
| | | } |
| | | } |
| | | |
| | | private void addSignatureToContractPdf(File pdfFile, File signatureImage, User user) throws Exception { |
| | | PdfReader reader = new PdfReader(new FileInputStream(pdfFile)); |
| | | File tempPdf = new File(pdfFile.getParent(), "temp_" + pdfFile.getName()); |
| | | 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); |
| | | image.setAbsolutePosition(435, pageSize.getHeight() - 288); |
| | | canvas.addImage(image); |
| | | log.info("签名图片已插入到合同PDF第二页"); |
| | | } |
| | | } |
| | | |
| | | stamper.close(); |
| | | reader.close(); |
| | | |
| | | if (tempPdf.exists()) { |
| | | pdfFile.delete(); |
| | | tempPdf.renameTo(pdfFile); |
| | | log.info("合同PDF文件已更新,签名图片已插入"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 从固定目录获取模板文件 |
| | | */ |
| | | private File getTemplateFile(String templateFileName) { |
| | | try { |
| | | String templateDir = PropertiesUtil.getProperty("pdf.template.dir"); |
| | | if (StringUtils.isBlank(templateDir)) { |
| | | 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) { |
| | | log.error("获取模板文件失败: {}", templateFileName, e); |
| | | return null; |
| | | } |
| | | } |
| | | } |