You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring中单次返回多张PDF转换生成的图片并在JSP展示

方案1:单请求返回合并雪碧图 + 坐标信息

这是最常用的低请求数实现方案:

  • 处理逻辑:
    1. PDF转成单页图片后,后台把所有图片按垂直/水平方向拼接为一张完整的雪碧图
    2. 同时计算好每一页对应在雪碧图上的x偏移、y偏移、宽度、高度,封装为数组和雪碧图一起返回
    3. 前台JSP拿到数据后,用CSS的background-position属性切分显示每一页的内容
  • 优点:仅需1次请求,兼容所有浏览器,不需要额外改造静态资源映射规则
  • 适用场景:PDF页数不超过20页、单页分辨率不大的场景,整体文件大小不会过高
  • 示例代码片段:
    后台Controller返回结构:
    @GetMapping("/pdf/to-images")
    public Map<String, Object> pdfToImages(@RequestParam String pdfPath) {
        // 1. 调用PDF转图片服务得到每页的BufferedImage
        List<BufferedImage> pages = pdf2ImageService.convert(pdfPath);
        // 2. 拼接雪碧图、计算每页坐标
        Map<String, Object> result = spriteImageService.merge(pages);
        // result中包含spriteBase64(雪碧图Base64编码)、pageCoords(每页坐标数组)两个核心字段
        return result;
    }
    
    前台JSP展示逻辑:
    <c:forEach items="${pageCoords}" var="coord" varStatus="status">
        <div style="width: ${coord.width}px; height: ${coord.height}px; 
                    background: url('data:image/png;base64,${spriteBase64}') 
                    -${coord.x}px -${coord.y}px no-repeat;">
        </div>
    </c:forEach>
    

    注意:如果雪碧图体积超过2M不推荐用Base64,改为直接返回雪碧图二进制流,响应头设置Content-Type: image/png,前台background属性直接填接口地址即可,仍然仅需1次请求。

方案2:多部分(Multipart)响应一次性返回所有图片

  • 处理逻辑:
    1. 后台Controller设置响应类型为multipart/mixed,按顺序把每一页的图片二进制流作为单独的部分写入响应
    2. 每个部分增加自定义Header标注页码、图片大小等元信息
    3. 前台用Fetch API读取响应的多部分内容,逐个转成Object URL赋值给img的src属性
  • 优点:不需要拼接图片,每页图片独立无损耗,适合页数多、单页分辨率大的场景
  • 示例代码片段:
    后台Controller:
    @GetMapping("/pdf/to-images-multipart")
    public void pdfToImagesMultipart(@RequestParam String pdfPath, HttpServletResponse response) throws IOException {
        response.setContentType("multipart/mixed; boundary=PAGE_BOUNDARY");
        List<BufferedImage> pages = pdf2ImageService.convert(pdfPath);
        OutputStream out = response.getOutputStream();
        for (int i = 0; i < pages.size(); i++) {
            out.write(("--PAGE_BOUNDARY\r\n").getBytes());
            out.write(("Content-Type: image/png\r\n").getBytes());
            out.write(("Content-Disposition: form-data; name=\"page\";\r\n\r\n").getBytes());
            ImageIO.write(pages.get(i), "png", out);
            out.write("\r\n".getBytes());
        }
        out.write(("--PAGE_BOUNDARY--\r\n").getBytes());
        out.flush();
    }
    
    前台JS处理逻辑:
    fetch('/pdf/to-images-multipart?pdfPath=xxx.pdf')
      .then(res => res.text())
      .then(data => {
          const parts = data.split('--PAGE_BOUNDARY').filter(p => p.trim() && !p.startsWith('--'));
          parts.forEach((part, index) => {
              const imgBlob = new Blob([part.split('\r\n\r\n')[1]], {type: 'image/png'});
              const imgUrl = URL.createObjectURL(imgBlob);
              document.getElementById(`page-${index}`).src = imgUrl;
          })
      })
    

Base64方案补充说明

你之前查到不推荐Base64的核心原因是Base64编码会比原始二进制文件大33%左右,如果PDF页数多整体体积会大幅增加,加载变慢。如果你的使用场景中PDF基本都在5页以内,单页尺寸不大,直接返回所有页的Base64数组完全可用,不用过度纠结通用最佳实践,符合业务场景的方案就是最优方案。

内容的提问来源于stack exchange,提问作者algiogia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 15:54:10