【Java】PDF导出、压缩导出及预览

837 阅读2分钟

前言

在实际的项目开发过程中难免会遇到导出PDF的需求,下面就将我在开发中用到的一些导出PDF的案例列举出来,当然这其中也参考了一些文章,我也会一一列举出来供大家阅读。

1.导出PDF

以导出离职证明为例,先附上具体代码:

 public static void exportPdf(String fileName, Map<String,String> resultMap, HttpServletResponse response) throws Exception{
        // 生成导出PDF的文件名称
        fileName = URLEncoder.encode(fileName, "UTF-8");
        // 设置响应头
        response.setContentType("application/pdf;charset=UTF-8");
        response.setHeader("Content-Disposition",
                "attachment;fileName=" + fileName + ".pdf");
        OutputStream out = null;
        ByteArrayOutputStream bos = null;
        PdfStamper stamper = null;
        PdfReader reader = null;
        ClassPathResource resource = new ClassPathResource("resign.pdf");
        InputStream inputStream = resource.getInputStream();
        try {
            // 保存到本地
            // out = new FileOutputStream(fileName);
            // 输出到浏览器端
            out = response.getOutputStream();
            // 读取PDF模板表单
            reader = new PdfReader(inputStream);
            // 字节数组流,用来缓存文件流
            bos = new ByteArrayOutputStream();
            // 根据模板表单生成一个新的PDF
            stamper = new PdfStamper(reader, bos);
            // 获取新生成的PDF表单
            AcroFields form = stamper.getAcroFields();

            ClassPathResource fontSource = new ClassPathResource("simsun.ttc,0");
            // 给表单生成中文字体,这里采用系统字体,不设置的话,中文显示会有问题
            BaseFont font = BaseFont.createFont(fontSource.getFilename(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            form.addSubstitutionFont(font);
            // 装配数据

            // 遍历data,给pdf表单赋值
            for (String key : resultMap.keySet()) {
                // 图片要单独处理
                if ("studentImg".equals(key)) {
                    int pageNo = form.getFieldPositions(key).get(0).page;
                    Rectangle signRect = form.getFieldPositions(key).get(0).position;
                    float x = signRect.getLeft();
                    float y = signRect.getBottom();
                    String studentImage = resultMap.get(key).toString();
                    //根据路径或Url读取图片
                    Image image = Image.getInstance(studentImage);
                    //获取图片页面
                    PdfContentByte under = stamper.getOverContent(pageNo);
                    //图片大小自适应
                    image.scaleToFit(signRect.getWidth(), signRect.getHeight());
                    //添加图片
                    image.setAbsolutePosition(x, y);
                    under.addImage(image);
                }
                // 设置普通文本数据
                else {
                    form.setField(key, resultMap.get(key));
                }
            }
            // 表明该PDF不可修改
            stamper.setFormFlattening(true);
            // 关闭资源
            stamper.close();
            // 将ByteArray字节数组中的流输出到out中(即输出到浏览器)
            Document doc = new Document();
            PdfCopy copy = new PdfCopy(doc, out);
            doc.open();
            PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
            copy.addPage(importPage);
            doc.close();
        } catch (Exception e) {
            log.error("离职证明导出失败:{}", e);
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    // 演示示例
      String fileName ="离职证明";
      Map<String, String> result = new HashMap<>();
      result.put("userName", "小明");
      result.put("sex",  "男");
      result.put("idNumber", "321456581549");
      result.put("hiredate", "2022-01-01");
      result.put("resignedDate", "2022-10-10");
      result.put("position", "产品经理");
      result.put("reason", "个人原因");
      result.put("contractObject", "美团配送");
      PdfUtils.exportPdf(fileName,result,response);

提示:

(1)我们需要把模板文件(resign.pdf)放到项目的resources目录下;

(2)如何制作这个PDF模板文件大家可以参考这篇文章:blog.csdn.net/L28298129/a…

2.导出PDF压缩包

 public static void exportPdfZip(List<Map<String, String>> list, String zipName, String templateName, HttpServletResponse response) throws Exception {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);

        for (Map<String, String> map : list) {
            ByteArrayOutputStream bos = null;
            PdfStamper stamper = null;
            PdfReader reader = null;
            ClassPathResource resource = new ClassPathResource(templateName);
            InputStream inputStream = resource.getInputStream();
            reader = new PdfReader(inputStream);
            bos = new ByteArrayOutputStream();
            stamper = new PdfStamper(reader, bos);
            AcroFields form = stamper.getAcroFields();
            ClassPathResource fontSource = new ClassPathResource("simsun.ttc,0");
            BaseFont font = BaseFont.createFont(fontSource.getFilename(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            form.addSubstitutionFont(font);
            for (String key : map.keySet()) {
                form.setField(key, map.get(key));
            }
            stamper.setFormFlattening(true);
            stamper.close();

            zip.putNextEntry(new ZipEntry(map.get("fileName")));
            byte[] bytes = bos.toByteArray();
            zip.write(bytes, 0, bytes.length);
            zip.flush();
            zip.closeEntry();
        }


        IOUtils.closeQuietly(zip);
        zipName = URLEncoder.encode(zipName, "UTF-8");
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=" + zipName);
        response.addHeader("Content-Length", "" + outputStream.toByteArray().length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.copy(new ByteArrayInputStream(outputStream.toByteArray()), response.getOutputStream());
    }
    
    //调用示例
     List<Map<String, String>> list = new ArrayList<>();
     for(int i=0;i<5;i++){
         Map<String, String> result = new HashMap<>();
         result.put("userName", "小明-"+i);
         result.put("sex",  "男");
         result.put("idNumber", "321456581549");
         result.put("hiredate", "2022-01-01");
         result.put("resignedDate", "2022-10-10");
         result.put("position", "产品经理");
         result.put("reason", "个人原因");
         result.put("contractObject", "美团配送");
         result.put("fileName", result.get("userName") + "-离职证明.pdf");
         list.add(result);
     }
     String fileName = "离职证明压缩包";
     String templateName = "resign.pdf";
     PdfUtils.exportPdfZip(list,fileName,templateName,response);

3. PDF预览

 public static void previewPdf(String fileUrl, HttpServletResponse response) throws Exception{
        URL file = null;
        InputStream inputStream = null;
        String codedFileName = null;
        try {
            codedFileName = URLEncoder.encode("测试" + ".pdf", "UTF-8");
            file = new URL(fileUrl);
            inputStream = new BufferedInputStream(file.openStream());
            BufferedInputStream br = new BufferedInputStream(inputStream);
            byte[] bs = new byte[1024];
            int len = 0;
            response.reset();
            URL u = new URL("file:///" + fileUrl);
            String contentType = u.openConnection().getContentType();
            response.setContentType(contentType);
            response.setHeader("Content-Disposition", "inline;filename="
                    + codedFileName);
            // 文件名应该编码成utf-8,注意:使用时,我们可忽略这句
            OutputStream out = response.getOutputStream();
            while ((len = br.read(bs)) > 0) {
                out.write(bs, 0, len);
            }
            out.flush();
            out.close();
            br.close();
        } catch (Exception e) {
            log.info("预览pdf失败");
        }

    }

4.写在最后

大家也不要忘了导入相关的pom文件

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.2.0</version>
</dependency>

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>


import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.IOUtils;
import org.springframework.core.io.ClassPathResource;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;