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

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.xdnf.cn/news/19019.html

相关文章:

  • C++ SNIFE
  • JVM之【运行时数据区】
  • Nginx访问限制学习笔记
  • 论文学习日志——忆阻器与神经网络——part1
  • 基于XiaothinkT6语言模型的文本相似度计算:轻量方案实现文本匹配与去重
  • AT_abc403_f [ABC403F] Shortest One Formula
  • 阿里云docker搭建的mysql无法访问
  • Docker化性能监控平台搭建:JMeter+InfluxDB+Grafana全攻略
  • GRPO算法:告别PPO内存炸弹,无需价值函数,用组内排名代替绝对评分
  • NUMA架构
  • Java大厂面试全解析:从Spring Boot到微服务架构实战
  • 矩阵初等变换的几何含义
  • 【LeetCode】动态规划——542.01 矩阵
  • 系统设计(数据库/微服务)
  • 计算机网络的发展演进历程
  • 2 梯度下降算法
  • 英伟达 Spectrum-XGS:重构 AI 基础设施,开启跨域超级工厂时代
  • 氯化钕:以稀土之力引领科技创新
  • Spring AI 入门指南:三步将AI集成到Spring Boot应用
  • Java大厂面试实战:从Spring Boot到微服务架构的全链路技术剖析
  • MySQL 面试题系列(四)
  • Mysql——日志
  • 力扣hot100:搜索旋转排序数组和寻找旋转排序数组中的最小值(33,153)
  • TikTok广告投放革命:指纹云手机如何实现智能群控与降本增效
  • Mac中修改Word的Normal.dotm文件
  • CSS实现内凹圆角边框技巧(高频)
  • 绿算技术解密金融科技安全:高性能计算与存储驱动金融防火墙新时代
  • 【拥抱AI】一起学卷积神经网络(CNN)
  • 一天推荐一款实用的手柄零件————线性霍尔
  • Zynq开发实践(FPGA之verilog仿真)