Java后台+PDF.js 实现pdf分页加载的后端实现

14 篇文章 1 订阅
11 篇文章 0 订阅

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

前言:

主要解决大体积pdf在线浏览加载缓慢,影响用户体验的问题
技术栈为:SpringBoot、Vue、pdfjs
主要核心思路:前端请求时请求头附带请求范围range及读取大小,后端根据请求头返回相应的pdf文件流

后端实现

 	@GetMapping("/load")
    public void loadPDFByPage(HttpServletResponse response, HttpServletRequest request,
                              @RequestParam("dataId") long dataId,
                              @RequestParam("archiveSid") String archiveSid) {
        //dataId, archiveSid参数只是为了获取到pdf的File对象          
        File pdf = pdfReadService.getArchive(dataId, archiveSid);

        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,表明此次返回的文件范围
在这里插入图片描述
在这里插入图片描述

遇到的问题

前端的同学在配置完成PDF.js后,调用始终是一个请求加载了全部文件,并未分片加载

首先服务端响应头返回Accept-Ranges: bytes,就表明服务器端支持分片加载,pdf.js就会自动启用分片加载文件的策略。由于浏览器默认只允许js读取以下的响应头,而Accept-Ranges: bytes是不支持的,这就造成pdf.js读取Accept-Ranges时,读到了null值,认为你的服务器不支持分片,故整个文件下载了。

解决方法:在服务端的返回响应头上增加:

'Access-Control-Expose-Headers''Accept-Ranges,Content-Range'

前端实现

我搞后端滴,前端自己看下边的文档
https://www.cnblogs.com/ingrid/articles/15886403.html

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
很高兴为您解答这个问题。以下是一个简单的示例代码,使用Layui和nicePage.js实现JSON自动表格分页: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>HTML表单数据自动分页</title> <link rel="stylesheet" href="//cdn.bootcss.com/layui/2.5.6/css/layui.min.css"> <link rel="stylesheet" href="//cdn.bootcss.com/nicepage/1.2.0/nicepage.css"> </head> <body> <div class="layui-container"> <table id="data_table" class="layui-table"></table> <div id="page"></div> </div> <script src="//cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script src="//cdn.bootcss.com/layui/2.5.6/layui.min.js"></script> <script src="//cdn.bootcss.com/nicepage/1.2.0/jquery.nicepage.js"></script> <script> layui.use('table', function(){ var table = layui.table; // 模拟JSON数据 var data = [ { id: 1, name: '张三', age: 20 }, { id: 2, name: '李四', age: 22 }, { id: 3, name: '王五', age: 25 }, { id: 4, name: '赵六', age: 28 }, { id: 5, name: '陈七', age: 30 }, { id: 6, name: '周八', age: 35 }, { id: 7, name: '吴九', age: 40 }, { id: 8, name: '郑十', age: 50 } ]; // 渲染表格 table.render({ elem: '#data_table', cols: [[ { field: 'id', title: 'ID', width: 80 }, { field: 'name', title: '姓名', width: 120 }, { field: 'age', title: '年龄', width: 80 } ]], data: data }); // 分页 $('#page').nicePage({ pageNo: 1, pageSize: 3, totalRows: data.length, autoLoad: true, callback: function(pageNo, pageSize){ var start = (pageNo - 1) * pageSize; var end = start + pageSize; table.reload('data_table', { data: data.slice(start, end) }); } }); }); </script> </body> </html> ``` 在这个示例中,我们使用Layui的table模块来渲染表格,然后使用nicePage.js实现自动分页。我们首先定义了一个模拟的JSON数据数组,然后使用`table.render()`方法将数据渲染到表格中。接下来,我们使用nicePage.js来创建一个分页控件,并在`callback`回调函数中使用`table.reload()`方法动态加载表格数据。在这个回调函数中,我们根据当前页码和每页显示的行数来计算出要显示的数据的起始和结束位置,然后使用`slice()`方法从原始数据数组中获取相应的数据,并使用`reload()`方法重新加载表格。这样,我们就可以实现自动分页的表格了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

徐州蔡徐坤

又要到饭了兄弟们

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值