实现在线预览pdf功能,后台下载PDF

  <!-- PDF预览模态框 --><n-modalv-model:show="pdfModalVisible"title="投诉统计报告预览":closable="false":mask-closable="false"@positive-click="closePdfModal"positive-text="关闭":width="900":height="1700":content-style="{ padding: 0, height: '170vh' }"><!-- PDF预览区域 --><iframeid="pdf-preview-iframe":src="pdfUrl"style="width: 100%; height: 900px; border: none;"></iframe></n-modal>

// PDF预览模态框状态
const pdfModalVisible = ref(false)
const pdfUrl = ref('')
const pdfFileName = ref('')// 预览并打印PDF
const handlePrint = async () => {try {// 准备参数let data = selectedMonth.value;data = new Date(new Date().getFullYear(), data).toISOString().slice(0, 7);// 显示加载提示window.$message.info('正在加载PDF文件...');// 调用 PDF 导出接口const apiUrl = `/api/manager/cmComplaintStatistics/exportReportPdf?yearMonth=${data}`;const response = await axios.get(apiUrl, {responseType: 'blob',headers: { 'x-token': `Bearer ${ssoClient.getToken()}` }});// 处理 PDF 流const blob = new Blob([response.data], { type: 'application/pdf' });pdfUrl.value = window.URL.createObjectURL(blob);pdfFileName.value = `${data}投诉统计报告.pdf`;// 显示PDF预览模态框pdfModalVisible.value = true;// 隐藏加载提示window.$message.success('PDF加载成功');} catch (error) {window.$message.error('获取PDF文件失败');console.error('接口请求错误:', error);}
};// 打印当前预览的PDF
const printCurrentPdf = () => {const pdfIframe = document.getElementById('pdf-preview-iframe');if (pdfIframe && pdfIframe.contentWindow) {pdfIframe.contentWindow.print();}
};// 下载当前预览的PDF
const downloadCurrentPdf = () => {const link = document.createElement('a');link.href = pdfUrl.value;link.download = pdfFileName.value;document.body.appendChild(link);link.click();document.body.removeChild(link);
};// 关闭PDF预览时释放资源
const closePdfModal = () => {pdfModalVisible.value = false;// 延迟释放URL以避免打印时资源已被回收setTimeout(() => {window.URL.revokeObjectURL(pdfUrl.value);pdfUrl.value = '';}, 3000);
};

后端:

@GetMapping("/exportReportPdf")@ApiOperationSupport(order = 8)@ApiOperation(value = "导出报告 PDF 文档", notes = "正式节点才能导出报告")public void exportReportPdf(@RequestParam String yearMonth, HttpServletResponse response) {try {// 设置 PDF 响应头response.setContentType("application/pdf");response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(yearMonth + "投诉统计报告.pdf", "UTF-8"));// 生成临时文件名String uuid = UUID.randomUUID().toString();String fileName = uuid + ".docx";Path docxPath = Paths.get(pathProperties.getReport(), uuid, fileName);Path pdfPath = Paths.get(pathProperties.getReport(), uuid, fileName + ".pdf");File docxFile = docxPath.toFile();File pdfFile = pdfPath.toFile();// 创建临时目录docxFile.getParentFile().mkdirs();// 生成 Word 文档XWPFTemplate template = getXwpfTemplate(null);try (FileOutputStream fos = new FileOutputStream(docxFile)) {template.write(fos);}// 转换 Word 到 PDFif (docxFile.exists()) {convertWordToPdf(docxFile, pdfFile);}// 将 PDF 文件内容写入响应流if (pdfFile.exists()) {try (InputStream in = new FileInputStream(pdfFile);OutputStream out = response.getOutputStream()) {byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = in.read(buffer)) != -1) {out.write(buffer, 0, bytesRead);}out.flush();} finally {// 可选:删除临时文件(建议在文件使用完毕后异步删除)docxFile.delete();pdfFile.delete();}} else {throw new IOException("PDF 文件生成失败");}} catch (Exception e) {log.error("导出PDF失败", e);try {response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "导出失败:" + e.getMessage());} catch (IOException ex) {log.error("设置响应错误信息失败", ex);}}}private XWPFTemplate getXwpfTemplate(CmComplaintVO cmComplaintVO) throws IOException {Map<String, Object> map = new HashMap<>();// 1. 处理文本参数(保持原有逻辑)map.put("work_order_time",Optional.ofNullable(LocalDateTime.now()).map(time -> time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).orElse(null));// 处理图片的核心代码Resource imageResource = new ClassPathResource("templates/statistic_chart.png");try (InputStream imageStream = imageResource.getInputStream()) {// 1. 将输入流转换为 BufferedImage(直接从流转换,避免中间字节数组)BufferedImage bufferedImage = ImageIO.read(imageStream);if (bufferedImage == null) {throw new IOException("无法解析图片流,可能是图片格式不支持");}// 2. 使用 Pictures.ofBufferedImage() 创建图片对象PictureRenderData pictureData = Pictures.ofBufferedImage(bufferedImage, PictureType.PNG).size(712, 500) // 设置图片宽高(像素).create(); // 创建 PictureRenderDatamap.put("image", pictureData); // 绑定到模板占位符 {{image}}} catch (IOException e) {log.error("处理图片失败", e);// 可选:添加默认图片或抛出友好异常throw new RuntimeException("导出Word失败:图片处理异常", e);}// 3. 编译模板(必须绑定图片渲染策略)PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();Resource templateResource = resolver.getResource("classpath:/templates/cm_statistics.docx");Configure config = Configure.builder().bind("image", new PictureRenderPolicy()) // 绑定图片渲染策略.build();XWPFTemplate template = XWPFTemplate.compile(templateResource.getInputStream(), config).render(map);return template;}/*** 将Word文件转换为PDF文件* @param wordFile Word文件* @param pdfFile PDF文件*/public void convertWordToPdf(File wordFile, File pdfFile) {try (InputStream docxInputStream = new FileInputStream(wordFile);OutputStream outputStream = new FileOutputStream(pdfFile)) {IConverter converter = LocalConverter.builder().build();converter.convert(docxInputStream).as(DocumentType.DOCX).to(outputStream).as(DocumentType.PDF).execute();System.out.println("Word转PDF成功: " + wordFile.getName());} catch (Exception e) {e.printStackTrace();System.err.println("Word转PDF失败: " + wordFile.getName() + ", 错误: " + e.getMessage());} finally {// 删除临时文件if (wordFile.exists()) {wordFile.delete();}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88965.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88965.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为VS格行VS中兴VS波导随身WIFI6怎么选?流量卡OR随身WIFI,长期使用到底谁更香?

在移动互联时代&#xff0c;流量焦虑成为现代人的通病。面对"办流量卡还是随身WiFi"的抉择&#xff0c;许多人陷入两难。本文从实际需求出发&#xff0c;用数据和场景帮你精准决策&#xff0c;尤其这五类人群建议直接选择正规随身WiFi。一、这五类人&#xff0c;随身…

AI网络搜索

作为AI应用程序开发人员在了解函数调用&#xff08;Function Calling&#xff09;特性调用本地函数时可能注意到列表型参数tools中每一个元素都携带有一个type值。而在大多数函数调用示例程序中&#xff0c;这个type值一直被设定为“function”&#xff0c;这意味着它还可能存在…

39.Sentinel微服务流量控制组件

雪崩问题 微服务调用链路中某个服务故障,引起整个链路中的所有微服务都不可用。 解决方案 1.超时处理:设置一个超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止的等待。(只能起到缓解作用,并不能从根本上解决问题) 2.舱壁模式:限定每个业务能使用的线程…

基于hadoop的竞赛网站日志数据分析与可视化(下)

【基于hadoop的竞赛网站日志数据分析与可视化&#xff08;上&#xff09;】讲解了如何用hadoop对数据进行初步处理&#xff0c;本篇主要讲解用python对结果数据进行可视化分析。 ------------------------------------------------------------------------------------------…

Python爬虫打怪升级:数据获取疑难全解析

一、引言 **​​​ 在大数据时代,数据就是价值的源泉。而 Python 爬虫,作为数据获取的得力助手,凭借 Python 简洁的语法和丰富强大的库,在众多领域发挥着重要作用。无论是电商领域的价格监测、市场调研中的数据收集,还是学术研究里的文献获取,Python 爬虫都能大显身手。…

基于R语言的极值统计学及其在相关领域中的实践技术应用

极值统计学就是专门研究自然界和人类社会中很少发生&#xff0c;然而发生之后有着巨大影响的极端现象的统计建模及分析方法&#xff1b;在水文、气象、环境、生态、保险和金融等领域都有着广泛的应用。一&#xff1a;独立假设下的极值统计建模 1.广义极值模型. 2.极小值的处理.…

前端面试十一之TS

TS 是 TypeScript 的缩写&#xff0c;是一种由微软开发的开源编程语言&#xff0c;它是 JavaScript 的一个超集&#xff0c;为 JavaScript 添加了类型系统和对 ES6 的支持。以下是关于 TypeScript 的详细介绍&#xff1a;一、特点类型系统&#xff1a;TypeScript 引入了类型注解…

Excel快捷键

Excel快捷键可以快速提高使用Excel的效率&#xff0c;下面将Excel快捷键进行整理汇总以备不时之需 标注颜色的为需要经常使用并可以显著提高效率的快捷键 Ctrl相关快捷键【Ctrl】【1】 显示【单元格格式】设置窗口,可以设置选中的格式【Ctrl】【2】 应用或取消加粗…

Windows 10/11安装WSL、Ubuntu、Docker Desktop

WSL&#xff0c;Windows Subsystem for Linux&#xff0c;是微软开发的轻量级虚拟机环境&#xff0c;允许用户在 Windows上运行完整的Linux内核和用户空间&#xff0c;适用于Windows的Linux子系统。能实现&#xff1a; 运行原生的Linux命令和程序&#xff08;如apt&#xff0c…

React之旅-06 Ref

当你想让一个组件“记住”一些信息&#xff0c;但又不想这些信息触发新的渲染时&#xff0c;你可以使用 ref。使用 Ref 前&#xff0c;需要导入useRef&#xff0c;代码如下&#xff1a;import { useRef } from react;在您的组件内部&#xff0c;调用 useRef 并将您想要引用的初…

stm32-Modbus主机移植程序理解以及实战

目录一、背景二、代码理解&#xff08;一&#xff09;main()函数例程代码功能遇到的问题解决方式分析&#xff08;二&#xff09;eMBMasterPoll( void )函数例程代码1. 变量声明2. 协议栈状态检查3. 获取事件4. 事件处理&#xff08;switch-case&#xff09;4.1 EV_MASTER_READ…

c++判断文件或目录是否存在

#include<sys/stat.h>#include<fstream>#include<string>#include<stdio.h>#include<stdlib.h>#include<vector>#include<io.h>#include<iostream>bool IsFileGood(string strFileName, book bFile){if(bFile) \\文件{ifstrea…

Java设计模式之行为型模式(命令模式)

一、核心定义与设计思想 命令模式通过对象化请求&#xff0c;将操作的具体实现细节封装在命令对象中&#xff0c;使得调用者&#xff08;Invoker&#xff09;无需直接依赖接收者&#xff08;Receiver&#xff09;&#xff0c;仅需通过命令对象间接调用。这种设计支持以下能力&a…

大数据领域开山鼻祖组件Hadoop核心架构设计

一、Hadoop的整体架构 Hadoop是一个专为大数据设计的架构解决方案&#xff0c;历经多年开发演进&#xff0c;已逐渐发展成为一个庞大且复杂的系统。其内部工作机制融合了分布式理论与具体工程开发的精髓&#xff0c;构成了一个整体架构。 Hadoop最朴素的原理在于&#xff0c;它…

OneCode3.0 VFS分布式文件管理API速查手册

&#x1f4da; 前言&#xff1a;OneCode 3.0微内核引擎架构解析 在云原生与分布式系统日益普及的今天&#xff0c;文件管理系统面临着前所未有的挑战——海量数据存储、跨节点协同、多租户隔离以及弹性扩展等需求推动着传统文件系统向分布式架构演进。OneCode 3.0作为新一代企业…

UI前端与数字孪生结合实践探索:智慧物流的仓储自动化管理系统

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;传统仓储的 “效率黑洞” 与数字孪生的破局当仓库管理员在数万平的库房中…

使用layui的前端框架过程中,无法加载css和js怎么办?

这使用layui的前端框架过程中&#xff0c;无法加载css和js怎么办&#xff1f;里写自定义目录标题已经按要求下载并解压到指定位置了&#xff0c;但是感觉就是无法加载文件后台提示如下&#xff1a;那就我清理缓存当再次观察html页面时&#xff0c;发现页面最开始有两个< htm…

gitlab+TortoiseGit克隆生成ppk方式

1、第一步 2、第二步3、第三步4、第四步&#xff0c;如何使用这个ppk就可以了

VSCode中使用容器及容器编排docker-compose

前面笔者写了一篇博文&#xff1a;使用容器编排对go项目进行部署、调试&#xff0c;介绍了在Goland中如何使用容器&#xff0c;由于Goland的容器配置是可视化的&#xff0c;使用起来非常方便&#xff0c;VSCode中也有一个容器插件&#xff0c;但是笔者一直未使用过&#xff0c;…

深度学习入门:让神经网络变得“深不可测“⚡(二)

深度学习入门&#xff1a;让神经网络变得"深不可测" &#x1f9e0;⚡ 系列课程第二弹&#xff1a;深度学习的奇妙世界 前言&#xff1a;从浅到深的华丽转身 哈喽&#xff0c;各位AI探险家&#xff01;&#x1f44b; 欢迎回到我们的"让机器变聪明"系列课…