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

springboot实现合同生成

项目:若依前后端分离项目

用户上传合同docx,用户填写占位符,实现生成docx。

docx转pdf,pdf再转图片

代码不全,但是关键代码基本都在

依赖:

        <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.9.1</version></dependency><dependency><groupId>org.docx4j</groupId><artifactId>docx4j</artifactId><version>6.1.0</version></dependency><dependency><groupId>org.docx4j</groupId><artifactId>docx4j-export-fo</artifactId><version>6.1.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.21</version></dependency><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.29</version></dependency>
上传合同,占位符为{{$.}}

新增合同的时候解析占位符

public int insertAxjfContractTemplate(AxjfContractTemplate axjfContractTemplate){axjfContractTemplate.setCreateTime(DateUtils.getNowDate());String fileUrl = axjfContractTemplate.getFileUrl();Set<String> fillFields;fileUrl = fileUrl.replace(Constants.RESOURCE_PREFIX, "");try {fillFields = extractPlaceholders(profile+fileUrl);} catch (Exception e) {throw new ServiceException("合同模板解析失败!");}axjfContractTemplate.setTemplateParams(JSON.toJSONString(fillFields));axjfContractTemplate.setUserId(SecurityUtils.getUserId());return axjfContractTemplateMapper.insertAxjfContractTemplate(axjfContractTemplate);}public static Set<String> extractPlaceholders(String filePath) throws Exception {Set<String> placeholders = new HashSet<>();FileInputStream fis = new FileInputStream(filePath);XWPFDocument doc = new XWPFDocument(fis);Pattern pattern = Pattern.compile("\\{\\$\\.(.+?)}}");for (XWPFParagraph paragraph : doc.getParagraphs()) {Matcher matcher = pattern.matcher(paragraph.getText());while (matcher.find()) {placeholders.add(matcher.group(1));}}for (XWPFTable table : doc.getTables()) {table.getRows().forEach(row ->row.getTableCells().forEach(cell -> {Matcher matcher = pattern.matcher(cell.getText());while (matcher.find()) {placeholders.add(matcher.group(1));}}));}doc.close();return placeholders;}

上传合同后,用户进行合同生成

@Overridepublic Map<String,String> insertAxjfContractRecord(AxjfContractRecord axjfContractRecord){axjfContractRecord.setCreateTime(DateUtils.getNowDate());axjfContractRecord.setUserId(SecurityUtils.getUserId());String fileUrl;String picUrl;try {fileUrl = handlerCreateContracr(axjfContractRecord);picUrl = handlerCreatePic(fileUrl.replace(Constants.RESOURCE_PREFIX, ""));} catch (Exception e) {e.printStackTrace();throw new ServiceException("生成失败!请稍后再试!");}axjfContractRecord.setDocxUrl(fileUrl);axjfContractRecord.setImgUrl(picUrl);threadPoolTaskExecutor.execute(() -> axjfContractRecordMapper.insertAxjfContractRecord(axjfContractRecord));Map<String, String> map = new HashMap<>();map.put("docxFileUrl",fileUrl);map.put("picUrl", picUrl);return map;}// word转pdf、pdf转图片private String handlerCreatePic(String fileUrl) throws Exception {WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File(uploadBasePath + fileUrl));FOSettings foSettings = Docx4J.createFOSettings();foSettings.setWmlPackage(wordMLPackage);foSettings.setApacheFopMime("application/pdf"); // 指定输出类型Mapper fontMapper = new IdentityPlusMapper();String fontsDir = "Fonts";String[] fontFiles = {"simsun.ttc","CALIBRI.ttf"};for (String fontFile : fontFiles) {URL fontUrl = this.getClass().getClassLoader().getResource(fontsDir + "/" + fontFile);if (fontUrl != null) {String fontName = fontFile.split("\\.")[0];PhysicalFonts.addPhysicalFonts(fontName, fontUrl);fontMapper.put(fontName, PhysicalFonts.get(fontName));}}wordMLPackage.setFontMapper(fontMapper);ByteArrayOutputStream baos = new ByteArrayOutputStream();Docx4J.toFO(foSettings, baos, Docx4J.FLAG_EXPORT_PREFER_XSL);byte[] pdfBytes = baos.toByteArray();String newFile = "/contract/record/" + DateUtils.datePath() + "/" + IdUtils.fastUUID() + "_" + "合同图片.png";try (PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes))) {PDFRenderer pdfRenderer = new PDFRenderer(document);List<BufferedImage> images = new ArrayList<>();int totalHeight = 0;int maxWidth = 0;for (int page = 0; page < document.getNumberOfPages(); page++) {BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 200);images.add(bim);totalHeight += bim.getHeight();maxWidth = Math.max(maxWidth, bim.getWidth());}BufferedImage longImage = new BufferedImage(maxWidth, totalHeight, BufferedImage.TYPE_INT_RGB);Graphics2D g2d = longImage.createGraphics();int currentHeight = 0;for (BufferedImage img : images) {g2d.drawImage(img, 0, currentHeight, null);currentHeight += img.getHeight();}g2d.dispose();String outputPath = uploadBasePath + newFile;ImageIO.write(longImage, "png", new File(outputPath));}return Constants.RESOURCE_PREFIX + newFile;}// 填充wordprivate String handlerCreateContracr(AxjfContractRecord axjfContractRecord) throws IOException {AxjfContractTemplate axjfContractTemplate = axjfContractTemplateMapper.selectAxjfContractTemplateById(axjfContractRecord.getTemplateId());if (null == axjfContractTemplate){throw new ServiceException("合同模板不存在!刷新页面后重试");}String templateFile = axjfContractTemplate.getFileUrl();String newFile =  "/contract/record/" + DateUtils.datePath() + "/" + IdUtils.fastUUID()+ "_"+ axjfContractTemplate.getTitle() + ".docx";// 上传文件路径String outputPath = uploadBasePath + newFile;File outFile = new File(outputPath);File parentDir = outFile.getParentFile();if (!parentDir.exists()) {boolean created = parentDir.mkdirs();if (!created) throw new RuntimeException("无法创建目录:" + parentDir.getAbsolutePath());}templateFile = uploadBasePath + templateFile.replace(Constants.RESOURCE_PREFIX, "");try (FileInputStream fis = new FileInputStream(templateFile);XWPFDocument document = new XWPFDocument(fis);FileOutputStream fos = new FileOutputStream(outFile)) {// 遍历段落for (XWPFParagraph paragraph : document.getParagraphs()) {for (XWPFRun run : paragraph.getRuns()) {String text = run.getText(0);if (text != null) {for (Map.Entry<String, String> entry : axjfContractRecord.getTemplateParams().entrySet()) {String key = "{{$." + entry.getKey() + "}}";if (text.contains(key)) {text = text.replace(key, entry.getValue());}}run.setText(text, 0);}}}document.getTables().forEach(table -> table.getRows().forEach(row ->row.getTableCells().forEach(cell ->cell.getParagraphs().forEach(paragraph ->paragraph.getRuns().forEach(run -> {String text = run.getText(0);if (text != null) {for (Map.Entry<String, String> entry : axjfContractRecord.getTemplateParams().entrySet()) {String key = "{{$." + entry.getKey() + "}}";if (text.contains(key)) {text = text.replace(key, entry.getValue());}}run.setText(text, 0);}})))));document.write(fos);}return Constants.RESOURCE_PREFIX + newFile;}

http://www.dtcms.com/a/351869.html

相关文章:

  • Odoo 企业版用户手册[新版] 前言 00.3-企业版功能模块全景图
  • C语言 指针
  • 消防设施安全员证核心考点:消防设施操作与维护高频知识点汇总
  • 聊聊测试覆盖率与测试质量之间的关系
  • 使用powerquery处理数据,取时间或者日期之前的
  • conda环境--相关记录
  • THM TryHack3M Subscribe WP
  • 科技信息差(8.26)
  • 亚马逊云科技免费套餐新政解析与实战:数据分析与可视化平台
  • Slice-100K:推动AI驱动的CAD与3D打印创新的多模态数据集
  • Mysql 判断查询条件索引是否生效步骤,使用说明,示例演示
  • 集成电路学习:什么是ResNet深度残差网络
  • Redis高级篇:在Nginx、Redis、Tomcat(JVM)各环节添加缓存以实现多级缓存
  • Docker-Docker思想
  • 软考-系统架构设计师 计算机系统基础知识详细讲解
  • 今日科技热点 | AI加速变革,量子计算商用化,5G应用新机遇
  • IDEA插件推荐
  • 【prism】Prism 弹窗在 ViewModel 中控制大小的实践总结
  • 工业自动化系统架构-(规划调度执行与协调)
  • 《Java反射与动态代理详解:从原理到实践》
  • 如何让Windows桌面井井有条?
  • 模型解释性:使用 SHAPASH 在贷款被拒原因的解释性(三)
  • Java大厂面试实战:从Spring Boot到微服务架构的深度剖析
  • 【公告】模式更改
  • 县域创新升级:直面瓶颈,重塑成果转化路径
  • 缺少fuser导致oracle自动补丁失败
  • 【第三章】软件测试缺陷管理:从判断到回归的全流程实践指南​
  • 【Erdas实验教程】030:遥感图像光谱增强(彩色IHS变换)
  • 【内网渗透】CVE-2025-21420 利用cleanmgr本地提权
  • Tesseract OCR之基线拟合和单词检测