目录
- 一、业务背景
- 二、流程概览
- 三、环境准备
- 四、后端代码
- 五、前端代码
- 六、最终效果
- 七、总结
一、业务背景
在实际业务使用中,有些情况下打印功能是由后端组装数据,前端整理数据生成pdf文件。此时如果某个功能需要后端再拿到生成的pdf进行下一步处理就不好实现。
比如后端编程需要拿到pdf文件发给CA厂商进行鉴权,如果在之前基础上增加新的交互逻辑整个流程就变得复杂冗余,于是我们考虑后端直接调用前端获取pdf文件。
二、流程概览
页面点击触发——>后端组装参数调用vue生成PDF——>前端收到请求解析参数绘制PDF——>后端拿到PDF文件进行后续业务处理(CA鉴权等)
其中关键的一点在于后端访问后需要等待多久再生成PDF,如果固定某个时间间隔可能会出现PDF没生成全或者已经生成完成但是还在等待浪费时间。
所以约定了一个属性,当前端页面渲染完成给这个属性打标记,后端读取标记成功后生成PDF。
三、环境准备
该功能需要依赖浏览器,我们以谷歌为例,确认好本地谷歌浏览器版本,下载对应的浏览器驱动。(驱动下载地址:Chrome for Testing availability)
大版本必须一致(139),然后将下载好的驱动放到固定位置,谷歌php浏览器exe位置也需要摘出来,稍后需要在Java代码中配置。
四、后端代码
需要将驱动路径、浏览器路径,前端访问路径进行配置,前端访问路由可自行调整。以下是具体代码,整体流程简单需要调试的配置较多。
private String dllUrl;//存储驱动的根目录,完整路径代码拼接,可自行调整
private String mWebAddress;//存储前端访问页面,后续访问路由代码拼接,可自行调整private String chromePath;//浏览器启动程序完整路径,可自行调整
package com.aikes.util; import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.By; import org.openqa.selenium.Pdf; import org.openqa.selenium.PrintsPage; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.print.PrintOptions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.springframework.beans.factory.annot编程ation.Value; import org.springframework.stereotype.Service; import java.io.File; import java.nio.file.Files; import java.nio.file.Paths; import java.time.Duration; import java.util.Base64; import java.util.Collections; /** * 调用vue页面获取PDF文件 */ @Slf4j @Service public class WebAccessServerUtil { @Value("${dllUrl:D:/DLL}") private String dllUrl; @Value("${webAddress:http://127.0.0.1:8080/mcpc/ui/dist/index.html}") private String mWebAddress; @Value("${chromePath:C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe}") private String chromePath; public boolean getPdfFromWeb(String cPath,String cpk_notification,String cpk_emgency){ log.info("根目录:" + dllUrl); log.info("Web端访问地址:" + mWebAddress); log.info("谷歌浏览器路径:" + chromePath); // 完全禁用WebDriverManager自动下载,手动指定驱动路径(避免版本冲突) System.setProperty("wdm.enabled", "false"); // 手动指定本地ChromeDriver路径(替换为你的实际路径) //驱动版本需要和服务器浏览器版本对应 138.0.7204.158 System.setProperty("webdriver.chrome.driver", dllUrl + File.separator + "chromedriver" + File.separator + "chromedriver.exe"); System.setProperty("webdriver.chrome.bin", chromePath); // 配置浏览器选项(重点修复) ChromeOptions options = new ChromeOptions(); options.addArguments("--headless=new"); // 新版headless模式 options.addArguments("--disable-gpu"); options.addArguments("--no-sandbox"); options.addArguments("--disable-dev-shm-usage"); options.addArguments("--remote-allow-origins=*"); // 允许跨域WebSocket options.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automationphp")); WebDriver driver = new ChromeDriver(options); WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15)); // 最大等待10秒 try { String vuePageUrl = mWebAddress + "#/generatePdfTest?pk_notification=" + cpk_notification + "&pk_emgency=" + cpk_emgency; driver.get(vuePageUrl); // 智能等待:直到页面设置true wait.until(ExpectedConditions.attributeToBe( By.tagName("body"), "data-pdf-ready", "true" )); PrintOptions printOptions = new PrintOptions(); printOptions.setBackground(true); printOptions.setPageRanges("1-5"); // 替换原PDF字节处理代码 Pdf pdf = ((PrintsPage) driver).print(printOptions); String base64Pdf = pdf.getContent(); // 获取Base64编码的PDF内容 byte[] pdfBytes = Base64.getDecoder().decode(base64Pdf); // 解码为原始二进制 Files.write(Paths.get(cPath), pdfBytes); log.info("调用Web端生成PDF文件成功: " + cPath); return true; } catch (Exception e) { log.error("获取Web端PDF文件失败:{}", e.getMessage(), e); return false; } finally { try { driver.quit(); } catch (Exception ignore) { } } } }
五、http://www.devze.com前端代码
前端vue仅供测试使用页面,具体业务使用需要进行美化和数据填充
在路由配置文件增加如下配置,实现路由和文件的绑定
{ path: '/generatePdfTest', name: 'GeneratePDFTest', component: (resolve) => require(['@/components/notificationRecord/MedicalNotificationPdf'], resolve), }
具体pdf生成页面代码如下
<template> <div class="pdf-container"> <h1>{{ title }}</h1> <div v-for="item in items" :key="item.id" class="item"> <p><strong>{{ item.label }}:</strong> {{ item.value }}</p> </div> </div> </template> <script> export default { data() { return { title: '测试通知记录书', items: [] } }, mounted() { try { // 检查路由是否可用(避免this.$route未定义的错误) if (!this.$route) { throw new Error("Vue Router未正确配置"); } const recordId = this.$route.query.id || 'default'; // 模拟数据加载 setTimeout(() => { this.items = [ { id: 1, label: '患者姓名', value: '张三' }, { id: 2, label: '病历号', value: recordId }, { id: 3, label: '诊断结果', value: 'stemi' }, { id: 4, label: '诊断日期', value: '2025-08-12' }, { id: 5, label: '诊断医生', value: '李四' } ]; // 确认body元素存在后再设置属性 if (document.body) { document.body.setAttribute('data-pdf-ready', 'true'); console.log("PDF渲染标记已设置"); // 用于浏览器控制台调试 } else { console.error("body元素不存在,无法设置标记"); } }, 500); } catch (error) { console.error("组件加载错误:", error); } } } </script> <style scoped> /* 样式保持不变 */ .pdf-container { width: 210mm; margin: 0 auto; padding: 20px; font-family: "SimSun"; } .item { margin: 10px 0; } </style>
六、最终效果
页面查看网页PDF
后端调用生成的PDF
七、总结
该功能仅作为“曲线救国”方案,实际业务场景需要尽可能预想到该流程提前设计交互思路,供大家参考学习哈。
到此这篇关于Java调用Vue前端页面生成PDF文件的文章就介绍到这了,更多相关Java调用Vue前端生成PDF文件内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论