PDF.js实现按需加载pdf文件-包含前后端开发源码和详细开发教程

news2024/11/23 15:51:31

PDF.js实现按需加载pdf文件

  • 说明
  • 前言
  • 前端项目
    • 分片加载的效果
    • 前端项目结构
    • 项目运行与访问
  • 后端项目
    • 项目结构
    • 核心代码实现
    • 注意事项
  • 项目源码

说明

本文主要是介绍pdf.js的前后端项目的实现,包含可直接运行的源码。由于本人偏向于后端开发,因此前端的vue方面的demo介绍可能略有不足之处,敬请谅解。可运行源码放在文章末尾处

前言

本文主要是解决大体积pdf在线浏览加载缓慢,影响用户体验的问题。以及实现了分片加载后的,首次加载时自动加载了全部的pdf分片,导致浏览器报出内存不足的问题
技术栈为:SpringBoot、Vue、pdfjs
主要核心思路:前端请求时请求头附带请求范围range及读取大小,后端根据请求头返回相应的pdf文件流

前端项目

分片加载的效果

在这里插入图片描述

前端项目结构

在这里插入图片描述
在这里插入图片描述

项目运行与访问

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

npm install

执行完成后,输入运行命令

npm run serve

在这里插入图片描述

后端项目

项目结构

后端项目是我在学习别的项目时创建,因此在上面临时写了一个分片加载的接口,直接运行即可
在这里插入图片描述

核心代码实现

 package com.zhouquan.controller;

import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

/**
 * @author zhouquan
 * @description todo
 * @date 2022-07-29 10:29
 **/
@RestController
@RequestMapping("/v1/pdf")
public class PDFController {

    /**
     * pdf分片加载的后端实现
     *
     * @param response
     * @param request
     * @throws FileNotFoundException
     */
    @GetMapping("/load")
    public void loadPDFByPage(HttpServletResponse response, HttpServletRequest request) throws FileNotFoundException {

        File pdf = ResourceUtils.getFile("classpath:泛函分析教程(第2版).pdf");
        try (
                InputStream is = new FileInputStream(pdf);
                BufferedInputStream bis = new BufferedInputStream(is);
                OutputStream os = response.getOutputStream();
                BufferedOutputStream bos = new BufferedOutputStream(os)) {

            // 下载的字节范围
            int startByte, endByte, totalByte;
            if (request != null && request.getHeader("range") != null) {
                // 断点续传
                String[] range = request.getHeader("range").replaceAll("[^0-9\\-]", "").split("-");
                // 文件总大小
                totalByte = is.available();
                // 下载起始位置
                startByte = Integer.parseInt(range[0]);
                // 下载结束位置
                if (range.length > 1) {
                    endByte = Integer.parseInt(range[1]);
                } else {
                    endByte = totalByte - 1;
                }
                // 返回http状态
                response.setStatus(206);
            } else {
                // 正常下载
                // 文件总大小
                totalByte = is.available();
                // 下载起始位置
                startByte = 0;
                // 下载结束位置
                endByte = totalByte - 1;
                // 返回http状态
                response.setHeader("Accept-Ranges", "bytes");
                response.setStatus(200);
            }
            // 需要下载字节数
            int length = endByte - startByte + 1;

            //表明服务器支持分片加载
            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(length);

            //需要设置此属性,否则浏览器默认不会读取到响应头中的Accept-Ranges属性,因此会认为服务器端不支持分片,所以会直接全文下载
            response.setHeader("Access-Control-Expose-Headers", "Accept-Ranges,Content-Range");

            // 响应内容
            bis.skip(startByte);
            int len = 0;
            byte[] buff = new byte[1024 * 64];
            while ((len = bis.read(buff, 0, buff.length)) != -1) {
                if (length <= len) {
                    bos.write(buff, 0, length);
                    break;
                } else {
                    length -= len;
                    bos.write(buff, 0, len);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意事项

1.首次加载返回状态码200,注意以下属性服务器端在响应头中务必要加上
在这里插入图片描述

 //表明服务器支持分片加载
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(length);

//需要设置此属性,否则浏览器默认不会读取到响应头中的Accept-Ranges属性,因此会认为服务器端不支持分片,所以会直接全文下载
response.setHeader("Access-Control-Expose-Headers", "Accept-Ranges,Content-Range");

2.之后每次请求都会返回206,即已经实现分片加载。Content-Range: bytes 0-65535/408244,表明此次返回的文件范围
在这里插入图片描述
在这里插入图片描述

项目源码

前端:

链接:https://pan.baidu.com/s/1nlGWhsB40UB_c25NglbP-g?pwd=jrqj
提取码:jrqj

后端:

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

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

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

相关文章

学习C这么久了,main函数的这三个参数你见过吗?

文章目录 &#x1f490;专栏导读&#x1f490;文章导读&#x1f427;引例1&#x1f427;引例2 &#x1f426;认识环境变量&#x1f514;环境变量的概念&#x1f514;常见的环境变量&#x1f514;和环境变量相关的指令 &#x1f426;main函数的第三个参数&#x1f514;如何通过代…

Django SQL注入漏洞复现 (CVE-2022-28347)

漏洞简介 在Django 2.2 的 2.2.28 之前版本、3.2 的 3.2.13 之前版本和 4.0 的 4.0.4 之前版本中的 QuerySet.deexplain() 中发现了SQL注入问题。这是通过传递一个精心编制的字典&#xff08;带有字典扩展&#xff09;作为**options参数来实现的&#xff0c;并将注入负载放置在…

这个插件厉害!Tapdata 格式的 api 也可以导入了

Tapdata 是干嘛的&#xff0c;大家都知道的吧&#xff1f;我简单介绍一下 Tapdata 是自带 ETL 的实时数据服务平台&#xff0c;通过把企业核心数据实时集中到中央化数据平台的方式并通过 API 或者反向同步方式&#xff0c;为下游的交互式应用、微服务或交互式分析提供新鲜实时的…

js逆向-阿里系某688参数sign分析

声明 本文仅供学习参考&#xff0c;如有侵权可私信本人删除&#xff0c;请勿用于其他途径&#xff0c;违者后果自负&#xff01; 如果觉得文章对你有所帮助&#xff0c;可以给博主点击关注和收藏哦&#xff01; 前言 目标网站&#xff1a;aHR0cHM6Ly93d3cuMTY4OC5jb20v 接…

html访问图片资源403问题

问题&#xff1a;图片403 页面不渲染 单独打开图片链接在浏览器却能正常查看 解决办法&#xff1a; 1.数据库中全局下载该字段链接&#xff0c;将图片存到制定文件夹&#xff0c;在系统内调用 2.检查页面head中的是否有此句“<metaname“referrer” content“no-referre…

网络模型及网络编程

名词解释 OSI&#xff08;Open System Interconnect&#xff09;&#xff0c;即开放式系统互联。 一般都叫OSI参考模型&#xff0c;是ISO&#xff08;国际标准化组织&#xff09;组织在1985年研究的网络互连模型。TCP(Transmission Control Protocol)&#xff0c;传送控制协议…

从永远到永远-ElasticSearch

ElasticSearch 1.概述2.入门1.官方地址2.RESTful3.倒排索引4.http请求操作1.索引操作2.document操作1.基本操作2.多条件查询3.区间查询4.完全匹配5.高亮显示6.聚合查询7.映射关系 5.JAVA API1.index操作2.doc操作1.基础操作2.批量操作3.复杂查询 1.概述 结构化数据、非结构化数…

C/C++函数指针和回调函数

一、函数指针 在讲回调函数之前&#xff0c;我们需要了解函数指针。 我们都知道&#xff0c;C语言的灵魂是指针&#xff0c;我们经常使用整型指针&#xff0c;字符串指针&#xff0c;结构体指针等 int *p1; char *p2; STRUCT *p3; //STRUCT为我们定义的结构体但是好像我们一…

springboot+jsp学生平时作业评价系统idea

课程信息管理功能需求主要是对课程信息的管理,包括课程信息的录入、维护、删除&#xff0c;教师可以根据授课计划设定授课进度。学生信息管理功能需求&#xff0c;主要是对学生的基本信息进行管理&#xff0c;教师可以录入学生信息&#xff0c;并可以对学生信息进行维护和删除。…

linux 串口改为固定

在/etc/udev/rules.d 目录下新建定义规则的文件 1. 文件名要按规范写否则改动无效2. 规则文件必须以.rules 结尾3. 规则文件名称必须遵循 xx-name.rules 格式&#xff08;xx 为数字或字母&#xff0c;name 为规则名称&#xff09;&#xff0c;例如 99-serial-ports.rules。4. 规…

PDM入门指南:一文带你了解PDM的基本知识

上一期&#xff0c;我们聊过PLM&#xff1b;这一期&#xff0c;我们接着聊聊PDM。在介绍之前&#xff0c;先回答之前客户提出的问题&#xff1a;上线PLM/PDM后&#xff0c;还需要e企拆图吗&#xff1f;可能需要&#xff0c;原因放在最后&#xff0c;有需要的朋友可直接跳到最后…

Java经典面试题—— 对比 Hashtable、HashMap、TreeMap 有什么不同?

典型回答 Hashtable、HashMap、TreeMap都是最常见的一些Map实现&#xff0c;是以键值对的形式存储和操作数据的容器类型。 Hashtable是早期Java类库提供的一个哈希表实现&#xff0c;本身是同步的&#xff0c;不支持null键和值&#xff0c;由于同步导致的性能开销&#xff0c…

IP 子网划分详解

文章目录 1 概述1.1 划分目的1.2 划分原则1.3 子网掩码 2 IP 子网划分示例3 网工软考真题3.1 判断网络号和主机号3.2 计算可容纳的主机数 1 概述 IP 子网划分&#xff1a;实际上就是设计 子网掩码 的过程。原因&#xff1a;由于在五类的IP地址中&#xff0c;网络号与主机号的的…

【dfs解决分组问题-两道例题——供佬学会!】(A元素是放在已经存在的组别中,还是再创建一个更好?--小孩子才做选择,dfs直接两种情况都试试)

问题关键就是&#xff1a; 一个点&#xff0c;可能 新开一个组 比 放到已经存在的组 更划算 因为后面的数据&#xff0c;我们遍历之前的点时&#xff0c;并不知道 所以我们应该针对每个点&#xff0c;都应该做出一个选择就是 新开一个元组或者放到之前的元组中&#xff0c;都尝…

SolVES 模型生态系统服务功能社会价值评估(基于多源环境QGIS、PostgreSQL、ArcGIS、Maxent、R语言)

查看原文>>>SolVES 模型生态系统服务功能社会价值评估&#xff08;基于多源环境QGIS、PostgreSQL、ArcGIS、Maxent、R语言&#xff09; 目录 第一章、理论基础与研究热点 第二章、SolVES 4.0 模型运行环境配置 第三章、SolVES 4.0 模型运行 第四章、数据获取与入…

简答题题集

简答题&#xff1a; 1.测试和开发如何配合工作&#xff0c;即测试何时介入测试工作&#xff1f; 测试工作应该覆盖需求分析、概要设计、详细设计、编码等前期阶段&#xff0c;而不应该在系统开发初步完成后才开始。 2.软件测试的对象&#xff1a;正确的依据应该是需求规格说明书…

【Java基础篇】数据类型与变量

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a;Java.SE&#xff0c;本专栏主要讲解运算符&#xff0c;程序逻辑控制&#xff0c;方法的使用&…

SRC漏洞挖掘

SRC目标搜集 文章类的平台 国内漏洞响应平台&#xff08;SRC&#xff09;导航 - 安全客&#xff0c;安全资讯平台 百度搜索 首先得知道SRC厂商的关键字&#xff0c;利用脚本搜集一波。 比如【应急响应中心】就可以作为一个关键字。通过搜索引擎搜索一波&#xff0c;去重&…

【LeetCode: 343. 整数拆分 | 暴力递归=>记忆化搜索=>动态规划 】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

前端三剑客

一.前端是什么&#xff1a; 前端主要是考虑怎样能让用户觉得用起来更舒服&#xff0c;考虑界面布局、交互效果、页面加载速度等等&#xff0c;主要是偏向用户看得见的部分&#xff0c;客户端&#xff08;pc、手机、pad&#xff09;上浏览web。网站的“前端”是与用户直接交互的…