说明

先利用Adobe acrobat pro DC对pdf进行表单制作,再通过利用java对模板数据进行填充,并生成新的pdf

使用Adobe acrobat pro DC制作pdf模板表单

下载地址参考:Adobe acrobat pro DC2018解决方案

  1. 打开模板pdf
    在这里插入图片描述
  2. 点击准备表单
    在这里插入图片描述
  3. 添加文本域
    在这里插入图片描述
  4. 设置对应属性
    在这里插入图片描述
    在这里插入图片描述
  5. 保存

使用java生成pdf

  1. 依赖
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.10</version>
</dependency>
<!-- itextpdf的亚洲字体支持 -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>
  1. 生成pdf工具类
import cn.hutool.core.collection.CollUtil;
import com.intellsite.digital.dto.SealPosition;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;

/**
 * desc: pdf 生成工具
 *
 * @author qts
 * @date 2022/3/18 0018
 */
@Slf4j
public class PdfGenerateUtil {

    private PdfGenerateUtil() {
    }

    /**
     * 获取字段对应的坐标信息
     * <p>{@link com.intellsite.digital.dto.SealPosition}</p>中只返回了:页码和x,y坐标
     *
     * @param templatePdfByteArray 模板pdf字节数组
     * @param paramsName           参数名称
     * @return 映射 key:字段名  value:坐标信息
     */
    public static Map<String, SealPosition> getPositions(byte[] templatePdfByteArray, Set<String> paramsName) {
        PdfReader reader = null;
        ByteArrayOutputStream bos = null;
        try {
            Map<String, SealPosition> sealMap = new HashMap<String, SealPosition>();

            //创建书写器,用于往document中书写信息
            // 通过本地文件路径获取资源
            reader = new PdfReader(templatePdfByteArray);
            bos = new ByteArrayOutputStream();
            PdfStamper stamper = new PdfStamper(reader, bos);
            // pdf表单字段
            AcroFields form = stamper.getAcroFields();

            // 通过名字获取位置
            SealPosition sealPosition;
            for (String name : paramsName) {
                List<AcroFields.FieldPosition> positions = form.getFieldPositions(name);
                if (CollUtil.isEmpty(positions)) {
                    sealMap.put(name, null);
                    continue;
                }

                // 页码
                int pageNo = positions.get(0).page;
                // 矩形
                Rectangle rectangle = positions.get(0).position;
                // x/y坐标
                BigDecimal right = new BigDecimal(String.valueOf(rectangle.getRight()));
                BigDecimal left = new BigDecimal(String.valueOf(rectangle.getLeft()));
                BigDecimal top = new BigDecimal(String.valueOf(rectangle.getTop()));
                BigDecimal bottom = new BigDecimal(String.valueOf(rectangle.getBottom()));
                float x = right.subtract(left).divide(new BigDecimal("2"),3,BigDecimal.ROUND_HALF_UP).floatValue();
                float y = top.subtract(bottom).divide(new BigDecimal("2"),3,BigDecimal.ROUND_HALF_UP).floatValue();

                sealPosition = new SealPosition().setPageNum(pageNo).setPosX(x).setPosY(y);
                sealMap.put(name, sealPosition);
            }

            stamper.setFormFlattening(false);
            stamper.close();

            return sealMap;
        } catch (Exception e) {
            log.error("通过模板生成PDF失败", e.getMessage());
            return null;
        } finally {
            try {
                if (null != reader) {
                    reader.close();
                }
                if (null != bos) {
                    bos.close();
                }

            } catch (IOException e) {
                log.error("close resource error", e.getMessage());
            }
        }

    }

    /**
     * 生成填充了模板参数的pdf
     *
     * @param templatePdfInputStream 模板pdf流
     * @param paramsMap            填充参数
     * @return
     */
    public static byte[] generatePdf(InputStream templatePdfInputStream,Map<String, Object> paramsMap) throws IOException {
        byte[] templatePdfByteArray = readBytes(templatePdfInputStream);
        return generatePdf(templatePdfByteArray, paramsMap);
    }

    /**
     * 生成填充了模板参数的pdf
     *
     * @param templatePdfByteArray 模板pdf字节数组
     * @param paramsMap            填充参数
     * @return
     */
    public static byte[] generatePdf(byte[] templatePdfByteArray, Map<String, Object> paramsMap) {

        PdfReader reader = null;
        ByteArrayOutputStream bos = null;
        try {
            //创建书写器,用于往document中书写信息
            // 通过本地文件路径获取资源
            reader = new PdfReader(templatePdfByteArray);
            bos = new ByteArrayOutputStream();
            PdfStamper stamper = new PdfStamper(reader, bos);

            //使用中文字体
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            ArrayList<BaseFont> fontList = new ArrayList<>();
            fontList.add(baseFont);


            AcroFields form = stamper.getAcroFields();
            form.setSubstitutionFonts(fontList);

            for (String fieldName : paramsMap.keySet()) {
                if (paramsMap.get(fieldName) == null) {
                    continue;
                }

                if (fieldName.indexOf("Image") > 0) {
                    String imgPath = paramsMap.get(fieldName).toString();
                    int pageNo = form.getFieldPositions(fieldName).get(0).page;
                    Rectangle rectangle = form.getFieldPositions(fieldName).get(0).position;
                    float x = rectangle.getLeft();
                    float y = rectangle.getTop();
                    //根据路径读取图片
                    Image image = Image.getInstance(imgPath);
                    //获取图片页面
                    PdfContentByte under = stamper.getOverContent(pageNo);
                    //图片大小自适应
                    image.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
                    //添加图片
                    image.setAbsolutePosition(x, y - rectangle.getHeight());
                    under.addImage(image);
                } else {
                    // 设置占位字段
                    form.setField(fieldName, paramsMap.get(fieldName).toString());
                }
            }

            stamper.setFormFlattening(false);
            stamper.close();

        } catch (Exception e) {
            log.error("通过模板生成PDF失败", e.getMessage());
            return null;
        } finally {
            try {
                if (null != reader) {
                    reader.close();
                }
                if (null != bos) {
                    bos.close();
                }

            } catch (IOException e) {
                log.error("close resource error", e.getMessage());
            }
        }

        return bos.toByteArray();
    }

    /**
     * 读取输入流到字节数组
     *
     * @param in
     * @return
     * @throws IOException
     */
    private static byte[] readBytes(InputStream in) throws IOException {
        //读取字节的缓冲
        byte[] buffer = new byte[1024];
        //最终的数据
        byte[] result = new byte[0];
        int size = 0;
        while ((size = in.read(buffer)) != -1) {
            int oldLen = result.length;
            byte[] tmp = new byte[oldLen + size];
            if (oldLen > 0) {//copy 旧字节
                System.arraycopy(result, 0, tmp, 0, oldLen);
            }
            //copy 新字节
            System.arraycopy(buffer, 0, tmp, oldLen, size);

            result = tmp;
        }
        return result;
    }
}

  1. 对应实体
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * @description: 签章位置信息
 * @author: wkh
 * @create: 2022-03-17 11:29
 */
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class SealPosition {
    /**
     * 签章id
     */
    private Long sealId;
    /**
     * x
     */
    private Float posX;
    /**
     * y
     */
    private Float posY;
    /**
     * 关键字
     */
    private String keyword;

    /**
     * 页码
     */
    private int pageNum;
}
  1. 使用工具类
    以下为关键代码
InputStream pdfInputStream = null;
try {
    // pdf模板
    pdfInputStream = new FileInputStream("D:\\监理日志模板.pdf");

    // 设置pdf模板参数  engineeringLog为实体类,其中的字段对应pdf表单中的字段名称
    JSONObject paramsMap = JSONObject.parseObject(JSON.toJSONString(engineeringLog));
    paramsMap.put("dairyDate", DateUtil.format(engineeringLog.getDairyDate(),"yyyy年MM月dd日"));

    // 生成pdf字节数组
    byte[] pdf = PdfGenerateUtil.generatePdf(pdfInputStream, paramsMap);
	
	// 准换成MultipartFile 
	MultipartFile multipartFile = new MockMultipartFile("file","模板.pdf","text/plain", pdf);
	
	// todo 后续处理 ,可以上传到文件服务器或其他操作
    

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}   finally {

    try {
        if (null != pdfInputStream) {
            pdfInputStream.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

}

版权声明:本文为weixin_44684303原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_44684303/article/details/124295768