PDF 预览下载功能完美实现

pdf 从后端接口获取的是instream  输入流,想要在前端下载,需要写到输入流

ServletOutputStream 中 该类继承了OutputStream 
public abstract class ServletOutputStream extends OutputStream {
    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");

    protected ServletOutputStream() {
    }

放到

HttpServletResponse 返回给前端 ,上完整代码
public static void sendPostDownLoadPdf(HttpServletResponse response, String url) throws IOException {
        // 创建默认的httpClient实例.
        CloseableHttpClient httpclient = HttpClients.createDefault();
        // 创建httpGet
        HttpGet httpGet = new HttpGet(url);
        try {
            // 设置请求头参数
            CloseableHttpResponse httpResponse = httpclient.execute(httpGet);
            // 获取第三方接口放在Response中的文件名
            org.apache.http.Header[] headers =  httpResponse.getHeaders("content-disposition");
            // 字符集编码
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType("application/octet-stream");
            if (headers != null && headers.length > 0) {
                String contentDispositionValue = headers[0].getValue();
                // 设置文件名,这里没用加密文件名,可以自己设置
                response.addHeader("Content-Disposition", URLEncoder.encode(contentDispositionValue,"UTF-8"));
            }
            HttpEntity entity = httpResponse.getEntity();
            //获取输入流
            InputStream inputStream = entity.getContent();

            // 输出文件
            ServletOutputStream outputStream = response.getOutputStream();

            try {
                byte[] oBuff = new byte[1024];
                int iSize;
                while (-1 != (iSize = inputStream.read(oBuff))) {
                    outputStream.write(oBuff, 0, iSize);
                }
                outputStream.flush();
            } finally {
                IOUtils.close(outputStream);
                IOUtils.close(inputStream);
            }
            outputStream.close();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

前端实现 :下载

.then((res) => {
              if (res) {
                let temp = res.headers["content-disposition"]
                  .split(";")[1]
                  .split("=")[1];
                   //对文件名乱码转义--【Node.js】使用iconv-lite解决中文乱码
                let iconv = require("iconv-lite");
                let fileName = iconv.decode(temp, "gbk");
                let type = decodeURIComponent(res.headers["content-type"]); // const xlsx = 'application/vnd.ms-excel'
                // console.log(type);
                const blob = new Blob([res.data], {
                  type: "application/vnd.ms-excel;charset=UTF-8",
                });
                // console.log(blob);
                const blobUrl = window.URL.createObjectURL(blob);
                let a = document.createElement("a"); // 转换完成,创建一个a标签用于下载
                 a .style.display = 'none'
                // 设置href属性为文件路径,download属性可以设置文件名称 
                a.href = blobUrl;
                a.download = fileName;
                document.body.appendChild(a);
                a.click();
                Window.URL.revokeObjectURL(blobUrl);
                a.remove();
              } else {
                this.$message.error("导出失败");
              }
            });

后端展示 

这里需要介绍我们项目的特殊性, 首先 我们是移动端h5 ,并且展示pdf 的方不能有多余的框框,

vue 展示 pdf 不能用 img 标签 因为不支持, 使用 

1,<iframe src="${pageContext.request.contextPath}/admin/indexs/images/resume.pdf" width="800px" height="2400px"></iframe>

可以,由于我们项目原因不允许使用。。。。。。

2,vue-pdf  可以,但是他预览之后有多余的框框,我们设计说了不行,不好看,也不知道什么审美。。。

3,杀手锏

后端将pdf 转 img ... 这个相对来说比较麻烦

首先了解这个类

ImageIO jdk 8 的提供里这样的方法
public static boolean write(RenderedImage im,
                            String formatName,
                            OutputStream output) throws IOException {
}有兴趣的同学可以看源码 就是 将inputStream 装 byte[] 然后传入 outPutstrem 流,和后缀文件名png/jpg;;等

直接上代码

 public static void sendPostViewLoadPdf(HttpServletResponse response, String url) throws IOException {
        // 创建默认的httpClient实例.
        CloseableHttpClient httpclient = HttpClients.createDefault();
        // 创建httpGet
        HttpGet httpGet = new HttpGet(url);
        try {
            // 设置请求头参数
            CloseableHttpResponse httpResponse = httpclient.execute(httpGet);
            // 字符集编码
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType("image/png");
            response.addHeader("Content-Disposition", URLEncoder.encode("电子发票.png","UTF-8"));
            HttpEntity entity = httpResponse.getEntity();
            //获取输入流
            InputStream inputStream = entity.getContent();

            // 输出文件
            ServletOutputStream outputStream = response.getOutputStream();

            try {
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = -1;
                while((len = inputStream.read(buffer)) != -1){
                    outStream.write(buffer, 0, len);
                }
                outStream.close();
                PdfUtils.pdf2Image(outStream.toByteArray(), outputStream, "PNG");
                outputStream.flush();
            } finally {
                IOUtils.close(outputStream);
                IOUtils.close(inputStream);
            }
            outputStream.close();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

// 这里是pdf转图片的代码,先要对pdf 长宽处理。。。

public static boolean pdf2Image(final byte[] content, final OutputStream output, final String ext) {
        if (null == content ) {
            return false;
        }

        int width = 0;
        int[] singleImgRGB;
        int shiftHeight = 0;

        try (PDDocument pdDocument = PDDocument.load(content)) {
            PDFRenderer renderer = new PDFRenderer(pdDocument);

            BufferedImage imageResult = null;
            for (int i = 0, len = pdDocument.getNumberOfPages(); i < len; i++) {
                BufferedImage image = renderer.renderImageWithDPI(i, 128, ImageType.RGB);

                int imageHeight = image.getHeight();
                int imageWidth = image.getWidth();
                //计算高度和偏移量
                if (i == 0) {
                    //使用第一张图片宽度;
                    width = imageWidth;
                    //保存每页图片的像素值
                    imageResult = new BufferedImage(width, imageHeight * len, BufferedImage.TYPE_INT_RGB);
                } else {
                    // 计算偏移高度
                    shiftHeight += imageHeight;
                }
                singleImgRGB = image.getRGB(0, 0, width, imageHeight, null, 0, width);
                // 写入流中
                imageResult.setRGB(0, shiftHeight, width, imageHeight, singleImgRGB, 0, width);

                return ImageIO.write(imageResult, CheckUtils.isNotBlank(ext) ? ext.toUpperCase() : "PNG", output);
            }
        } catch (Exception e) {
        }

        return false;
    }

前端就会接收到img 的流 他 在转 base64 就可以用 img 标签显示了。打完收工。。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值