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

实现在线预览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.dtcms.com/a/274338.html

相关文章:

  • PDF 转图助手 PDF2JPG 绿色版:免安装直接用,急处理文件的救急小天使
  • 电力分析仪的“双语对话”:CCLinkIE与Modbus TCP的无缝连接
  • 【Unity游戏存档系统】
  • 爬虫练习1
  • 【环境配置】KAG - Windows 安装部署
  • 7.11文件和异常
  • kafka kraft模式升级metadata.version
  • JVM--监控和故障处理工具
  • Oracle 高可用性与安全性
  • SpringCloud【OpenFeign】
  • 数据治理(管理)能力评估——解读2024数据治理与数据管理能力成熟度评估模型【附全文阅读】
  • 10款主流报销管理平台对比及推荐
  • Linux操作系统之进程间通信:命名管道
  • Linux编程练习题1:打印图形
  • python学习DataFrame数据结构
  • 制作一款打飞机游戏79:道具拾取系统
  • c++设计模式:简单工厂模式
  • C++STL-list
  • 游戏的程序员会不会偷偷改自己账号的数据?
  • 线性回归的从零开始实现(详解部分疑问)
  • 【三】ObservableCollection 与 List 的区别
  • RK3566/RK3568 Android11 CAN开发(内核配置+测试验证+安卓app开发)
  • 2025 年第十五届 APMCM 亚太地区大学生数学建模竞赛C题 基于Quantum Boosting的二分类模型问题
  • 5G标准学习笔记15 --CSI-RS测量
  • 【龙泽科技】新能源汽车维护与动力蓄电池检测仿真教学软件【吉利几何G6】
  • 深入理解C语言内存空间、函数指针(三)(重点是函数指针)
  • Redis 主从复制及哨兵模式模拟部署
  • 3.检查函数 if (!CheckStart()) return 的妙用 C#例子
  • PBR渲染
  • 【网络安全】理解安全事件的“三分法”流程:应对警报的第一道防线