springboot基础(79):通过pdf模板生成文件

文章目录

前言

通过pdf模板生成文件。


本章代码已分享至Gitee: https://gitee.com/lengcz/pdfdemo01

通过pdf模板生成文件

一 . 制作模板

  1. 先使用wps软件制作一个docx文档

  2. 将文件另存为pdf文件

  3. 使用pdf编辑器,编辑表单,(例如福昕PDF阅读器、Adobe Acrobat DC)

不同的pdf编辑器使用方式不同,建议自行学习如何使用pdf编辑器编辑表单

  1. 将修改后的文件保存为template1.pdf文件。

二、编辑代码实现模板生成pdf文件

  1. 引入依赖
xml 复制代码
 <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13.3</version>
        </dependency>
  1. 编写pdf工具类和相关工具
java 复制代码
package com.it2.pdfdemo01.util;

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;

import java.io.*;
import java.util.List;
import java.util.Map;

/**
 * pdf 工具
 */
public class PdfUtil {


    /**
     * 通过pdf模板输出到流
     *
     * @param templateFile 模板
     * @param dataMap      input数据
     * @param picData      image图片
     * @param checkboxMap  checkbox勾选框
     * @param outputStream 输出流
     */
    public static void output(String templateFile, Map<String, Object> dataMap, Map<String, byte[]> picData, Map<String, String> checkboxMap, OutputStream outputStream) {
        OutputStream os = null;
        PdfStamper ps = null;
        PdfReader reader = null;

        try {
            reader = new PdfReader(templateFile);
            ps = new PdfStamper(reader, outputStream);
            AcroFields form = ps.getAcroFields();
            BaseFont bf = BaseFont.createFont("Font/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            form.addSubstitutionFont(bf);
            if (null != dataMap) {
                for (String key : dataMap.keySet()) {
                    form.setField(key, dataMap.get(key).toString());
                }
            }
            ps.setFormFlattening(true);
            if (null != checkboxMap) {
                for (String key : checkboxMap.keySet()) {
                    form.setField(key, checkboxMap.get(key), true);
                }
            }

            PdfStamper stamper = ps;
            if (null != picData) {
                picData.forEach((filedName, imgSrc) -> {
                    List<AcroFields.FieldPosition> fieldPositions = form.getFieldPositions(filedName);
                    for (AcroFields.FieldPosition fieldPosition : fieldPositions) {
                        int pageno = fieldPosition.page;
                        Rectangle signrect = fieldPosition.position;
                        float x = signrect.getLeft();
                        float y = signrect.getBottom();
                        byte[] byteArray = imgSrc;
                        try {
                            Image image = Image.getInstance(byteArray);
                            PdfContentByte under = stamper.getOverContent(pageno);
                            image.scaleToFit(signrect.getWidth(), signrect.getHeight());
                            image.setAbsolutePosition(x, y);
                            under.addImage(image);
                        } catch (BadElementException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (DocumentException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ps.close();
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 通过pdf模板输出到文件
     *
     * @param templateFile 模板
     * @param dataMap      input数据
     * @param picData      image图片
     * @param checkboxMap  checkbox勾选框
     * @param outputFile   输出流
     */
    public static void output(String templateFile, Map<String, Object> dataMap, Map<String, byte[]> picData, Map<String, String> checkboxMap, File outputFile) throws IOException {
        FileOutputStream fos = new FileOutputStream(outputFile);
        try {
            output(templateFile, dataMap, picData, checkboxMap, fos);
        } finally {
            fos.close();
        }
    }

    /**
     * 通过pdf模板输出到文件
     *
     * @param templateFile 模板
     * @param dataMap      input数据
     * @param picData      image图片
     * @param checkboxMap  checkbox勾选框
     * @param filePath     路径
     * @param fileName     文件名
     */
    public static void output(String templateFile, Map<String, Object> dataMap, Map<String, byte[]> picData, Map<String, String> checkboxMap, String filePath, String fileName) throws IOException {
        File file = new File(filePath + File.separator + fileName);
        output(templateFile, dataMap, picData, checkboxMap, file);
    }

}
java 复制代码
package com.it2.pdfdemo01.util;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

/**
 * 图片工具
 */
public class ImageUtil {

    /**
     * 通过图片路径获取byte数组
     *
     * @param url 路径
     * @return
     */
    public static byte[] imageToBytes(String url) {
        ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
        BufferedImage bufferedImage = null;
        try {
            bufferedImage = ImageIO.read(new File(url));
            ImageIO.write(bufferedImage, "jpg", byteOutput);
            return byteOutput.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (byteOutput != null)
                    byteOutput.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

用到的字体文件(幼圆常规,C盘Windows/Fonts目录下

  1. 测试用例并执行,生成了pdf文件。
java 复制代码
 @Test
    public void testPdf() throws IOException {
        String templateFile = "D:\\test3\\template1.pdf";
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("username", "王小鱼");
        dataMap.put("age", "11");
        dataMap.put("address", "深圳市宝安区和林大道");

        Map<String, byte[]> picMap = new HashMap<>();
        byte[] imageToBytes = ImageUtil.imageToBytes("D:\\test3\\dog3.png");
        picMap.put("head", imageToBytes);

        Map<String, String> checkboxMap = new HashMap<>();
        checkboxMap.put("apple", "Yes");
        checkboxMap.put("orange", "Yes");
        checkboxMap.put("peach", "No");

        PdfUtil.output(templateFile, dataMap, picMap, checkboxMap, "D:\\test3", "test1.pdf");
        System.out.println("-------通过模板生成文件结束-------");
    }

三、pdf在线预览和文件下载

java 复制代码
package com.it2.pdfdemo01.controller;

import com.it2.pdfdemo01.util.ImageUtil;
import com.it2.pdfdemo01.util.PdfUtil;
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.IOException;
import java.util.HashMap;
import java.util.Map;


@RestController
@RequestMapping("/pdftest")
public class MyPdfController {

    /**
     * 在线预览pdf
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @GetMapping("/previewPdf")
    public void previewPdf(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String templateFile = "D:\\test3\\template1.pdf";
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("username", "王小鱼");
        dataMap.put("age", "11");
        dataMap.put("address", "深圳市宝安区和林大道");

        Map<String, byte[]> picMap = new HashMap<>();
        byte[] imageToBytes = ImageUtil.imageToBytes("D:\\test3\\dog3.png");
        picMap.put("head", imageToBytes);

        Map<String, String> checkboxMap = new HashMap<>();
        checkboxMap.put("apple", "Yes");
        checkboxMap.put("orange", "Yes");
        checkboxMap.put("peach", "No");

        response.setCharacterEncoding("utf-8");
        response.setContentType("application/pdf");
        String fileName = new String("测试预览pdf文件".getBytes(), "ISO-8859-1");//避免中文乱码
        response.setHeader("Content-Disposition", "inline;filename=".concat(String.valueOf(fileName) + ".pdf"));
        PdfUtil.output(templateFile, dataMap, picMap, checkboxMap, response.getOutputStream());
    }

    /**
     * 下载pdf
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @GetMapping("/downloadPdf")
    public void downloadPdf(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String templateFile = "D:\\test3\\template1.pdf";
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("username", "王小鱼");
        dataMap.put("age", "11");
        dataMap.put("address", "深圳市宝安区和林大道");

        Map<String, byte[]> picMap = new HashMap<>();
        byte[] imageToBytes = ImageUtil.imageToBytes("D:\\test3\\dog3.png");
        picMap.put("head", imageToBytes);

        Map<String, String> checkboxMap = new HashMap<>();
        checkboxMap.put("apple", "Yes");
        checkboxMap.put("orange", "Yes");
        checkboxMap.put("peach", "No");

        response.setCharacterEncoding("utf-8");
        response.setContentType("application/pdf");
        String fileName = new String("测试预览pdf文件".getBytes(), "ISO-8859-1");//避免中文乱码
        response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(fileName) + ".pdf"));
        PdfUtil.output(templateFile, dataMap, picMap, checkboxMap, response.getOutputStream());
    }
}

启动服务器测试

预览和下载的区别,只有细微区别。

扩展问题

android手机浏览器不能在线预览pdf文件,pc浏览器和ios浏览器可以在线预览pdf文件。

解决方案请见: https://lengcz.blog.csdn.net/article/details/132604135

遇到的问题

1. 更换字体为宋体常规

只能是下面这种写法

java 复制代码
//            BaseFont bf = BaseFont.createFont("Font/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); //幼圆常规
            String srcFilePath = PdfUtil.class.getResource("/")+ "Font/simsun.ttc"; //宋体常规
            String templatePath = srcFilePath.substring("file:/".length())+",0";
            BaseFont bf = BaseFont.createFont(templatePath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
相关推荐
千叶寻-36 分钟前
正则表达式
前端·javascript·后端·架构·正则表达式·node.js
小咕聊编程2 小时前
【含文档+源码】基于SpringBoot的过滤协同算法之网上服装商城设计与实现
java·spring boot·后端
追逐时光者8 小时前
推荐 12 款开源美观、简单易用的 WPF UI 控件库,让 WPF 应用界面焕然一新!
后端·.net
Jagger_8 小时前
敏捷开发流程-精简版
前端·后端
苏打水com9 小时前
数据库进阶实战:从性能优化到分布式架构的核心突破
数据库·后端
西瓜er9 小时前
JAVA:Spring Boot 集成 FFmpeg 实现多媒体处理
java·spring boot·ffmpeg
间彧10 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧10 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧10 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧10 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端