【若依前后端分离】前端vue页面查看服务器本地的PDF

后端实现:

使用FileSystemResource包装文件,以便Spring MVC可以处理该资源

创建HttpHeaders对象以设置响应头

设置Content-Disposition头,使得浏览器以内联方式显示PDF(即在浏览器中直接打开)

设置Content-Type为application/pdf,指示响应体是一个PDF文件

构建并返回带有指定头信息和PDF资源的ResponseEntity,状态码为200 OK

后端java代码 :

java 复制代码
package com.hm.wms.pdf.controller;

import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.springframework.core.io.*;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;

/**
 * @author zy
 */
@RestController
@RequestMapping("/file")
public class PdfController {
 
//可以系统配置文件路径代替代码中的"E:/cs/"

    /**
     * 展示PDF文件
     * 测试路径:本地E:/cs/cs.pdf 对应http://ip:端口/file/showPdf/文件名
     * @param pdfName 文件名
     * @return 响应实体,包含PDF文件的资源
     */
    @GetMapping("/showPdf/{pdfName}")
    public ResponseEntity<FileSystemResource> showPdf(@PathVariable("pdfName") String pdfName) {
        if (!pdfName.endsWith(".pdf")) {
            throw new RuntimeException("读取pdf文件失败,扩展名错误");
        }
        // 使用sanitizePath方法确保传入的pdfName路径安全,防止路径遍历等安全问题
        String safeFilePath = sanitizePath("E:/cs/", pdfName);

        // 根据处理后的安全路径创建File对象
        File file = new File(safeFilePath);

        // 检查文件是否存在并且是一个标准文件,若不满足条件则抛出异常
        if (!file.exists() || !file.isFile()) {
            throw new RuntimeException("文件未找到");
        }

        // 使用FileSystemResource包装文件,以便Spring MVC可以处理该资源
        FileSystemResource resource = new FileSystemResource(file);

        // 创建HttpHeaders对象以设置响应头
        HttpHeaders headers = new HttpHeaders();

        // 设置Content-Disposition头,使得浏览器以内联方式显示PDF(即在浏览器中直接打开)
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=" + resource.getFilename());

        // 设置Content-Type为application/pdf,指示响应体是一个PDF文件
        headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PDF_VALUE);

        // 构建并返回带有指定头信息和PDF资源的ResponseEntity,状态码为200 OK
        return ResponseEntity.ok()
        .headers(headers)
        .body(resource);
    }

    /**
     * 确保路径安全,防止路径遍历攻击。
     *
     * @param baseDir  基础目录
     * @param filePath 文件路径
     * @return 安全的文件路径
     */
    private String sanitizePath(String baseDir, String filePath) {
        // 确保filePath不会导致路径遍历,这里简单示例为拼接,实际应用中应使用更严格的安全策略
        if (!filePath.startsWith("/") && !filePath.contains("..")) {
            return baseDir + filePath;
        }
        throw new IllegalArgumentException("非法的文件路径");
    }
}

测试:

启动后端,打开浏览器输入http://ip:端口/file/showPdf/文件名,修改为自己的ip端口和文件名称(其他内容自己修改),若打开pdf文件则说明成功了!

例图:

前端实现1: dialog中预览pdf

想要在页面dialog中打开pdf文件进行预览查看

安装依赖:npm vue-pdf --save

全部vue代码:可自己修改样式

javascript 复制代码
<template>
  <el-dialog :title="title1" :visible.sync="openDetail" append-to-body>
    <div>
      <pdf 
        :src="pdfSrc" 
        :page="currentPage" 
        @num-pages="onNumPagesLoaded"
        @page-rendered="pageRendered"
      ></pdf>
      <div class="pagination">
        <button :disabled="currentPage === 1" @click="previousPage">上一页</button>
        <span>{{ currentPage }} / {{ numPages }}</span>
        <button :disabled="currentPage === numPages" @click="nextPage">下一页</button>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import Pdf from 'vue-pdf';

export default {
  components: {
    pdf: Pdf,
  },
  data() {
    return {
      openDetail: false,
      title1: 'PDF预览',
      pdfSrc: '', // PDF文件的URL
      currentPage: 1, // 当前显示的页码
      numPages: null, // PDF总页数
    };
  },
  methods: {
    fetchPDF() {
       this.pdfSrc = "http://服务器ip:8080/file/showPdf/"+"cs.pdf";
      window.open(this.pdfSrc)
    },
    showDetail() {
      this.fetchPDF();
      this.openDetail = true;
    },
    onNumPagesLoaded(numPages) {
      this.numPages = numPages;
      // 初始加载时尝试渲染第一页
      this.currentPage = 1;
    },
    pageRendered(num) {
      // 页面渲染完成后,更新当前页码
      this.currentPage = num;
    },
    previousPage() {
      if (this.currentPage > 1) {
        this.currentPage--;
      }
    },
    nextPage() {
      if (this.currentPage < this.numPages) {
        this.currentPage++;
      }
    },
  },
};
</script>

结果预览:可点击翻页(可自己拓展滑动翻页)

前端实现2:JS打开新窗口

使用:window.open(url)

可以点击按钮,使用window.open(url)来打开新页面展示pdf文件。

window.open() -打开新窗口
常用于文件、图片预览,或者加载一个新页面。

用法:

window.open(Url, WindowName, [strWindowFeatures]);

解释:
strUrl: 新窗口需要载入的url地址
strWindowName:新的窗口的名字 ,可选。
strWindowFeatures: 新窗口的一些设置,可选。比如是否显示菜单栏,是否可以滚动和缩放窗口大小等。

示例:

window.open("http://www.baidu.com", "myWindow", "width=500,height=400,resizable=yes");

详细可参考文章 :Window的Open方法,弹窗的特征【超详细篇】_window open-CSDN博客

遇到问题:

文件名为中文时,后端控制台异常

遇到的问题与在使用Content-Disposition头部时编码非ASCII字符(比如中文文件名"仓库管理.pdf")有关。错误消息表明,Unicode字符"仓"无法在HTTP头部预期的范围内正确编码。

为了解决这个问题,应该正确地在Content-Disposition头部中编码文件名。

以下是修改showPdf方法以正确处理包含非ASCII字符文件名的步骤:

  1. 确保使用UTF-8编码:使用Spring的UriUtils类中的UriUtils.encode方法,以UTF-8格式正确编码文件名。这将正确处理中文等特殊字符。
  2. 修改Content-Disposition头部:使用UriUtils.encode来设置Content-Disposition头部,以正确编码文件名部分。

以下是修改后的showPdf方法示例:

替换代码即可~

java 复制代码
 HttpHeaders headers = new HttpHeaders();
 headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=" + resource.getFilename());
 headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PDF_VALUE);
    return ResponseEntity.ok()
        .headers(headers)
        .body(resource);

替换为

java 复制代码
   HttpHeaders headers = new HttpHeaders();
   headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename*=UTF-8''" + UriUtils.encode(pdfName, StandardCharsets.UTF_8));
   headers.setContentType(MediaType.APPLICATION_PDF);

    return ResponseEntity.ok()
            .headers(headers)
            .contentLength(file.length())
            .body(resource);

即可!!!

解释:

  • UriUtils.encode:该方法确保文件名中的非ASCII字符根据RFC 6266正确进行百分比编码,从而可以安全地在HTTP头部传输。
  • Content-Disposition头部:filename参数指定了UTF-8编码的文件名。格式为filename=UTF-8''<编码后的文件名>,其中<编码后的文件名>是文件名的UTF-8编码值。这确保了像"仓"这样的字符在头部中得到正确表示。
  • MediaType.APPLICATION_PDF:指定响应体包含PDF文件。

通过正确编码文件名,您可以确保与HTTP标准的兼容性,并避免与无效头部值相关的错误。这种方法应该能够解决您在提供包含中文或其他非ASCII字符文件名的PDF文件时遇到的问题。

解决:报错消失!

小白一枚~

有问题及时纠正,我会认真修改~

相关推荐
你挚爱的强哥3 小时前
✅✅✅【Vue.js】sd.js基于jQuery Ajax最新原生完整版for凯哥API版本
javascript·vue.js·jquery
吾日三省吾码3 小时前
JVM 性能调优
java
y先森4 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy4 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189114 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
弗拉唐4 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
sun0077004 小时前
ubuntu dpkg 删除安装包
运维·服务器·ubuntu
CodeCraft Studio5 小时前
【实用技能】使用 TX Text Control 创建带有嵌入式附件的 PDF 文档
pdf·asp.net·.net
oi775 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器