SpringBoot+PDF.js实现按需分片加载预览(包含可运行示例源码)

SpringBoot+PDF.js实现按需分片加载预览

  • 前言
  • 分片加载的效果
  • 前端项目
    • 前端项目结构
    • 前端核心代码
    • 前端项目运行
  • 后端项目
    • 后端项目结构
    • 后端核心代码
    • 后端项目运行
  • 项目运行效果
    • 首次访问
    • 分片加载
  • 项目源码

前言

本文的解决方案旨在解决大体积PDF在线浏览加载缓慢、影响用户体验的难题。通过利用分片加载技术,前端请求时附带range及读取大小信息,后端据此返回相应的PDF文件流。这种方式有效地减轻了服务器和浏览器的负担,提升了加载速度和用户体验。同时解决了首次加载全部分片导致浏览器内存不足的问题。

技术栈:Spring Boot、Vue和pdf.js。

分片加载的效果

在这里插入图片描述

前端项目

前端项目结构

在这里插入图片描述

image-20240223172511041

前端核心代码

index.vue

<template><div class="pdf"><iframe:src="`/static/pdf/web/viewer.html?file=${encodeURIComponent(src)}`"frameborder="0"style="width: 100%; height: calc(100vh)"></iframe></div>
</template><script>
import baseUrl from "@/api/baseurl.js";
export default {data() {return {baseUrl: baseUrl.baseUrl,src: "",loading: false,};},created() {},methods: {getPdfCode: function () {this.loading = true;// 这里是请求分片的接口,看情况修改this.src = `http://localhost:8181/v1/pdf/load`;},},mounted() {this.$nextTick(() => {this.getPdfCode();});},
};
</script><style lang="scss" scoped></style>

image-20240224132317559

前端项目运行

首先确保vue需要的运行环境已经安装(nodejs),我使用的版本:12.18.2,然后使用vscode打开项目,在终端输入命令:

npm install
npm run serve

image-20240223173450002

后端项目

后端项目结构

本示例只是一个简单的springboot项目,核心文件PDFController.java用于分片加载接口,CORSFilter.java为跨域配置

image-20240224132650175

后端核心代码

这段代码实现了使用 PDF.js 进行分片加载 PDF 文件的功能。下面是代码的主要实现思路:

  1. 首先,通过 ResourceUtils.getFile 方法获取类路径下的 PDF 文件,并将其读取为字节数组 pdfData
  2. 然后,判断文件大小是否小于指定的阈值(1MB),如果小于阈值,则直接将整个文件作为响应返回。修改了小体积pdf小于分片大小时无法访问的bug
  3. 如果文件大小超过阈值,就根据请求头中的 Range 字段判断是否为断点续传请求。
  4. 如果是首次请求或者没有 Range 字段,则返回整个文件的字节范围,并设置响应状态为 SC_OK(响应码200)。
  5. 如果是断点续传请求,则解析 Range 字段获取请求的起始位置和结束位置,并根据这些位置从文件中读取相应的字节进行响应。
  6. 在响应头中设置 Accept-RangesContent-Range 属性,告知客户端服务器支持分片加载,并指定本次返回的文件范围。
  7. 最后,设置响应的内容类型为 application/octet-stream,内容长度为本次返回的字节数,然后刷新输出流,将数据返回给客户端。

这样,客户端就可以使用 PDF.js 来分片加载显示 PDF 文件了。

PDFController.java

/**
/*** pdf分片加载的后端实现** @param response* @param request* @throws FileNotFoundException*/
@GetMapping("/load")
public void loadPDFByPage(HttpServletResponse response, HttpServletRequest request) throws FileNotFoundException {// 获取pdf文件,建议pdf大小超过20mb以上File pdf = ResourceUtils.getFile("classpath:需要分片加载的pdf.pdf");byte[] pdfData = new byte[0];try {pdfData = FileUtils.readFileToByteArray(pdf);} catch (IOException e) {throw new RuntimeException(e);}// 以下为pdf分片的代码try (InputStream is = new ByteArrayInputStream(pdfData);BufferedInputStream bis = new BufferedInputStream(is);OutputStream os = response.getOutputStream();BufferedOutputStream bos = new BufferedOutputStream(os)) {// 下载的字节范围int startByte, endByte, totalByte;// 获取文件总大小int fileSize = pdfData.length;int minSize = 1024 * 1024;// 如果文件小于1 MB,直接返回数据,不需要进行分片if (fileSize < minSize) {// 直接返回整个文件response.setStatus(HttpServletResponse.SC_OK);response.setContentType("application/octet-stream");response.setContentLength(fileSize);bos.write(pdfData);return;}// 根据HTTP请求头的Range字段判断是否为断点续传if (request == null || request.getHeader("range") == null) {// 如果是首次请求,返回全部字节范围 bytes 0-7285040/7285041totalByte = is.available();startByte = 0;endByte = totalByte - 1;response.setStatus(HttpServletResponse.SC_OK);} else {// 断点续传逻辑String[] range = request.getHeader("range").replaceAll("[^0-9\\-]", "").split("-");// 文件总大小totalByte = is.available();// 下载起始位置startByte = Integer.parseInt(range[0]);// 下载结束位置endByte = range.length > 1 ? Integer.parseInt(range[1]) : totalByte - 1;// 跳过输入流中指定的起始位置bis.skip(startByte);// 表示服务器成功处理了部分 GET 请求,返回了客户端请求的部分数据。response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);int bytesRead, length = endByte - startByte + 1;byte[] buffer = new byte[1024 * 64];while ((bytesRead = bis.read(buffer, 0, Math.min(buffer.length, length))) != -1 && length > 0) {bos.write(buffer, 0, bytesRead);length -= bytesRead;}}// 表明服务器支持分片加载response.setHeader("Accept-Ranges", "bytes");// Content-Range: bytes 0-65535/408244,表明此次返回的文件范围response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + totalByte);// 告知浏览器这是一个字节流,浏览器处理字节流的默认方式就是下载response.setContentType("application/octet-stream");// 表明该文件的所有字节大小response.setContentLength(endByte - startByte + 1);// 需要设置此属性,否则浏览器默认不会读取到响应头中的Accept-Ranges属性,// 因此会认为服务器端不支持分片,所以会直接全文下载response.setHeader("Access-Control-Expose-Headers", "Accept-Ranges,Content-Range");// 第一次请求直接刷新输出流,返回响应response.flushBuffer();} catch (IOException e) {e.printStackTrace();}
}

CORSFilter.java 通用的跨域配置

package com.example.pdfload.filter;import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class CORSFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletResponse response1 = (HttpServletResponse) response;response1.addHeader("Access-Control-Allow-Credentials", "true");response1.addHeader("Access-Control-Allow-Origin", "*");response1.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");response1.addHeader("Access-Control-Allow-Headers","range,Accept-Ranges,Content-Range,Content-Type," +"X-CAF-Authorization-Token,sessionToken,X-TOKEN,Cache-Control,If-Modified-Since");if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {response.getWriter().println("ok");return;}chain.doFilter(request, response);}@Overridepublic void destroy() {}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}
}

后端项目运行

image-20240224133652301

项目运行效果

image-20240224134625354

首次访问

首次访问返回状态码200,返回响应信息如下:

image-20240224135153313

 // 表明服务器支持分片加载response.setHeader("Accept-Ranges", "bytes");// Content-Range: bytes 0-65535/408244,表明此次返回的文件范围response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + totalByte);// 告知浏览器这是一个字节流,浏览器处理字节流的默认方式就是下载response.setContentType("application/octet-stream");// 表明该文件的所有字节大小response.setContentLength(endByte - startByte + 1);// 需要设置此属性,否则浏览器默认不会读取到响应头中的Accept-Ranges属性,// 因此会认为服务器端不支持分片,所以会直接全文下载response.setHeader("Access-Control-Expose-Headers", "Accept-Ranges,Content-Range");

分片加载

分片加载返回状态码206,返回响应信息如下:

image-20240224135805018

image-20240224140040627

项目源码

image-20240224141259487

链接:https://pan.baidu.com/s/1oD9bUvGfFmfEimXfaKGpXg?pwd=zhou
提取码:zhou

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

什么是IP地址,IP地址详解

在互联网的世界中&#xff0c;每一台连接的设备都需要一个独特的标识&#xff0c;这就是IP地址。IP地址&#xff0c;全称为“Internet Protocol Address”&#xff0c;即互联网协议地址&#xff0c;它是网络中进行数据传输的基础。下面&#xff0c;我们将对IP地址进行详细的解析…

幻兽帕鲁(Palworld 1.4.1)私有服务器搭建(docker版)

文章目录 说明客户端安装服务器部署1Panel安装和配置docker服务初始化设置设置开机自启动设置镜像加速 游戏服务端部署游戏服务端参数可视化配置 Palworld连接服务器问题总结 说明 服务器硬件要求&#xff1a;Linux系统/Window系统&#xff08;x86架构&#xff0c;armbian架构…

Vue+SpringBoot打造社区买菜系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 数据中心模块2.1.2 菜品分类模块2.1.3 菜品档案模块2.1.4 菜品订单模块2.1.5 菜品收藏模块2.1.6 收货地址模块 2.2 可行性分析2.3 用例分析2.4 实体类设计2.4.1 菜品分类模块2.4.2 菜品档案模块2.4.3…

在openEuler中通过KVM可视化安装华为FusionCompute的CNA主机

一、环境说明 在Windows物理主机上通过VMware WorkStation创建一个虚拟机&#xff08;4U4C、16GB内存&#xff0c;400GB磁盘&#xff0c;NAT网络连接&#xff09;&#xff0c;在虚拟机中安装openEuler 22.03 LTS系统&#xff0c;并将该虚拟机作为部署 FusionCompute的服务器&a…

maven3下载地址(含旧版本)

因为现有的3.8版本与IDEA不兼容&#xff0c;我需要下载3.6版本&#xff0c;但是官网的位置非常隐蔽&#xff0c;找了很多资料才看到。故记录一下。Index of /dist/maven/maven-3 选择需要的版本 选择binaries 选择zip文件下载就可以了

Modern C++ std::visit从实践到原理

前言 std::visit 是 C17 中引入的一个模板函数&#xff0c;它用于对给定的 variant、union 类型或任何其他兼容的类型执行一个访问者操作。这个函数为多种可能类型的值提供了一种统一的访问机制。使用 std::visit&#xff0c;你可以编写更通用和灵活的代码&#xff0c;而无需关…

静态时序分析:SDC约束命令set_input_transition详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html DC工具在使用set_drive和set_driving_cell建模输入端口驱动能力时&#xff0c;会自动计算输入端口的转换时间&#xff0c;以及由于电阻或驱动单元带来的额外输入端口延迟。 set_input_tra…

Linux基础知识——命令行模式下命令的执行

文章目录 Linux基础知识——命令行模式下命令的执行开始执行Linux命令Linux基础命令的操作常用Linux命令行操作按键Linux输出错误信息查看 Linux系统在线帮助--help选项man命令info命令其他有用的文件文档百度搜索 文本编辑器&#xff1a;nanonano启动&#xff01; 正确关机方法…

Three.js加载PLY文件

这是官方的例子 three.js webgl - PLY 我在Vue3中使用&#xff0c;测试了好久始终不显示点云数据。在网上查询后发现ply文件要放置在public目录下才行 <el-row><el-button type"primary" class"el-btn" click"IniThree1">PLY</…

【ArcGIS微课1000例】0104:二位面状数据转三维多面体(建筑物按高度拉伸)

文章目录 一、加载数据二、添加高度字段三、三维拉伸显示四、生成三维体数据五、注意事项一、加载数据 打开ArcScene,加载配套实验数据(0104.rar中的二维建筑物矢量数据,订阅专栏,获取专栏所有文章阅读权限及配套数据),如下图所示: 二、添加高度字段 本实验将二维数据…

system_v

共享内存 创建共享内存 key_t ftok(const char *pathname, int proj_id);使用相同的pathname和proj_id可以得到相同的key_t int shmget(key_t key, size_t size, int shmflg);需要使用ftok获取key_t IPC_CREAT——不存在就创建&#xff0c;存在就获取 IPC_EXCL——一般和…

Android---PhotoViewer实现图片预览

PhotoViewer 图片查看器模仿微信朋友圈查看图片的效果。 在 Android 项目中引用 JitPack 库 AGP 8. 根目录的 settings.gradle dependencyResolutionManagement {...repositories {...maven { url https://jitpack.io }} } AGP 8. 根目录如果是 settings.gradle.kts 文件 d…

vue 中实现音视频播放进度条(满足常见开发需求)

由于开发需要&#xff0c;作者封装了一个音视频播放进度条的插件&#xff0c;支持 vue2 及 vue3 &#xff0c;有需要的朋友可联系作者&#xff0c;下面是对该款插件的介绍。 插件默认样式&#x1f447;&#xff08;插件提供了多个配置选项&#xff0c;可根据自身需求进行个性化…

AI误导游戏——LLM的危险幻觉

在当今科技高速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;已成为日常生活和工作中不可或缺的一部分。特别是大语言模型&#xff08;LLM&#xff09;如GPT-4等&#xff0c;它们的智能表现令人惊叹&#xff0c;广泛应用于文本生成、语言翻译、情感分析等多个领域…

5分钟JavaScript快速入门

目录 一.JavaScript基础语法 二.JavaScript的引入方式 三.JavaScript中的数组 四.BOM对象集合 五.DOM对象集合 六.事件监听 使用addEventListener()方法添加事件监听器 使用onX属性直接指定事件处理函数 使用removeEventListener()方法移除事件监听器 一.JavaScript基础…

HL祭记汇

一.写在前面 如果说廿四10天集训&#xff0c;对于我&#xff0c;是完成了从入门&#xff08;虽然可能我比别人入门更早&#xff1f;&#xff09;到准OIer的蜕变&#xff0c;那么&#xff0c;HL7天&#xff0c;可以说是真正成为了OIer&#xff0c;虽然是被小学生、初中生&#…

Linux运维-DHCP服务器

DHCP服务器的配置与管理 项目场景 学校各部门共有180台电脑&#xff0c;除了计算机学院的教师会配置电脑的网络连接&#xff0c;其他部门的老师和工作人员均不会&#xff0c;为了提高网络的管理效率&#xff0c;技术人员决定配置一台DHCP服务器&#xff0c;来提供动态的IP地址…

nginx搭建直播rtmp推流,httpflv拉流环境

背景 工作中发现挺多直播CDN在实现httpflv拉流时都没有使用http chunk编码&#xff0c;而是直接使用no-content-length的做法。所以想自己搭建一个直播CDN支持 http chunk编码。 环境搭建 系统环境 Ubuntu 18.04.4 LTS 软件 nginx-1.18.0 nginx扩展模块 nginx-http-flv-mo…

【前端素材】推荐优质后台管理系统Be admin平台模板(附源码)

一、需求分析 后台管理系统&#xff08;或称作管理后台、管理系统、后台管理平台&#xff09;是一种专门用于管理网站、应用程序或系统后台运营的软件系统。它通常由一系列功能模块组成&#xff0c;为管理员提供了管理、监控和控制网站或应用程序的各个方面的工具和界面。以下…

Linux学习方法-框架学习法——Linux驱动架构的演进

配套视频学习链接&#xff1a;https://www.bilibili.com/video/BV1HE411w7by?p4&vd_sourced488bc722b90657aaa06a1e8647eddfc 目录 Linux驱动演进的过程 Linux驱动的原始架构(Linux V2.4) 平台总线架构(platform) Linux设备树 Linux驱动演进的趋势 Linux驱动演进的过程…