PDF生成

PDF生成


此版PDF生成包含: 封面, 目录,页码等功能,暂时没有实现目录跳转功能

POM依赖

<dependency>
	<groupId>com.itextpdf</groupId>
	<artifactId>layout</artifactId>
	<version>7.0.3</version>
</dependency>
<dependency>
	<groupId>com.itextpdf</groupId>
	<artifactId>font-asian</artifactId>
	<version>7.0.3</version>
</dependency>
<dependency>
	<groupId>com.itextpdf</groupId>
	<artifactId>itextpdf</artifactId>
	<version>5.4.3</version>
</dependency>
<dependency>
	<groupId>com.itextpdf</groupId>
	<artifactId>itext-asian</artifactId>
	<version>5.2.0</version>
</dependency>

字体处理

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import lombok.extern.slf4j.Slf4j;
import com.weifengqi18.investigation.constants.ReportConstant;
import com.weifengqi18.investigation.exception.BizErrorException;

/**
 * PDF字体工具类
 *
 * @author wl
 * @version 1.0
 * @date 2021-10-22
 */
@Slf4j
public class PdfFontUtil {


    /**
     * 获取字体
     *
     * @param size   字号
     * @param systel 字体
     * @param color  颜色
     * @return Font
     */
    public static Font createFont(float size, int systel, BaseColor color) {
        Font font;
        if (null != color) {
            font = new Font(createBaseFont(), size, systel, color);
        } else {
            font = new Font(createBaseFont(), size, systel);
        }
        return font;
    }

    /**
     * 获取自定义字体
     *
     * @param size   字号
     * @param systel 字体
     * @param color  颜色
     * @return Font
     */
    public static Font createCustomerFont(float size, int systel, BaseColor color, String ttfPath) {
        Font font;
        if (null != color) {
            font = new Font(createCustomerBaseFont(ttfPath), size, systel, color);
        } else {
            font = new Font(createCustomerBaseFont(ttfPath), size, systel);
        }
        return font;
    }

    /**
     * 获取基础字体信息
     *
     * @return BaseFont
     */
    public static BaseFont createBaseFont() {

        try {

            return BaseFont.createFont(ReportConstant.FONT, ReportConstant.CHARACTER,
                    BaseFont.NOT_EMBEDDED);
        } catch (Exception e) {
            log.error("云尽调_商务报告_生成商务报告PDF获取字体信息出错,错误字体为: {}, 编码为: {}, 错误信息为: {}",
                    ReportConstant.FONT,
                    ReportConstant.CHARACTER, e);
            throw new BizErrorException("云尽调获取字体失败!");
        }
    }

    /**
     * 获取自定义字体信息
     *
     * @return BaseFont
     */
    public static BaseFont createCustomerBaseFont(String fontPath) {

        try {

            return BaseFont.createFont(fontPath, BaseFont.IDENTITY_H,
                    BaseFont.EMBEDDED);
        } catch (Exception e) {
            log.error("云尽调_商务报告_生成商务报告PDF获取字体信息出错,错误字体为: {}, 编码为: {}, 错误信息为: {}",
                    ReportConstant.FONT,
                    ReportConstant.CHARACTER, e);
            throw new BizErrorException("云尽调获取字体失败!");
        }
    }

    /**
     * 段落标题字体
     *
     * @return 字体
     */
    public static Font paragraHeadFont() {

        return createCustomerFont(ReportConstant.HEAD_FONT_SIZE, Font.NORMAL,
               BaseColor.BLACK, ReportConstant.FZHTK_FNOT);
    }

    /**
     * 段落子标题字体
     *
     * @return 字体
     */
    public static Font paragraSubHeadFont() {

        return createCustomerFont(ReportConstant.SUB_HEAD_FONT_SIZE, Font.NORMAL,
                BaseColor.BLACK, ReportConstant.FZHTK_FNOT);
    }

    /**
     * 段落字体
     *
     * @return 段落字体
     */
    public static Font paragraFont() {
        return createCustomerFont(ReportConstant.PHASE_FONT_SIZE, Font.NORMAL,
                ReportConstant.BRODER_COLOR,ReportConstant.MSYH_FNOT);
    }

    /**
     * 段落字体
     *
     * @param fontSize 字体大小
     * @param sytle    字体样式
     * @param color    颜色
     * @return 段落字体
     */
    public static Font paragraFont(int fontSize, int sytle, BaseColor color) {
        return createCustomerFont(fontSize, sytle, color, ReportConstant.MSYH_FNOT);
    }


    /**
     * cell head 字体
     *
     * @return cell字体
     */
    public static Font cellHeadFont() {
        return createCustomerFont(ReportConstant.CELL_FONT_SIZE, Font.NORMAL,
                BaseColor.BLACK,ReportConstant.MSYH_FNOT);
    }

    /**
     * cell head 字体
     *
     * @return cell字体
     */
    public static Font cellFont() {
        return createCustomerFont(ReportConstant.CELL_FONT_SIZE, Font.NORMAL,
                ReportConstant.BRODER_COLOR,ReportConstant.MSYH_FNOT);
    }

    /**
     * cell head 字体
     *
     * @param fontSize 字体大小
     * @param sytle    字体样式
     * @param color    颜色
     * @return cell字体
     */
    public static Font cellFont(float fontSize, int sytle, BaseColor color) {
        return PdfFontUtil.createFont(fontSize, sytle, color);
    }

}

PDF内容处理

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.draw.DottedLineSeparator;
import io.swagger.annotations.ApiModel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;

import com.weifengqi18.investigation.constants.ReportConstant;
import com.weifengqi18.investigation.event.TOCEvent;
import com.weifengqi18.investigation.vo.report.business.ChangesInfo;
import com.weifengqi18.investigation.vo.report.business.LawStatusVo;

/**
 * PDF 上下文工具类
 *
 * @author wl
 * @version 1.0
 * @date 2021-10-25
 */
@Slf4j
public class PdfContextUtil {

    private PdfContextUtil() {
    }

    /** 合并列下表数组 */
    private static final int CELL_ARRAY_SIZE = 2;

    /**
     * 解析股东情况
     *
     * @param table table
     * @param tList list
     */
    @SneakyThrows
    public static void parseListInfo(PdfPTable table, List<?> tList, Class<?> clazz,
            boolean needSerial,
            boolean hasTotal, Font cellHeadFont, Font cellFont, String cloumName) {
        // 设置表头
        Field[] declaredFields = clazz.getDeclaredFields();

        if (needSerial) {
            table.addCell(PdfContextUtil.createPdfpCell(cloumName, cellHeadFont));
        }
        for (Field declaredField : declaredFields) {
            String value = DateConvertUtil.changeNumToYear(declaredField);
            table.addCell(PdfContextUtil.createPdfpCell(value, cellHeadFont));
        }

        // 设置cell值
        List<Object> objects = new ArrayList<>();
        if (CollectionUtils.isEmpty(tList)) {
            Object o = clazz.newInstance();
            objects.add(o);
        }

        int size;
        boolean isEmpty = CollectionUtils.isEmpty(tList);
        if (isEmpty) {
            size = objects.size();
        } else {
            size = tList.size();
        }
        log.info("云尽调_PDF报告解析属性,属性集合为: {}", JSONObject.toJSONString(tList));
        for (int i = 0; i < size; i++) {
            Object o;
            if (isEmpty) {
                o = objects.get(i);
            } else {
                o = tList.get(i);
            }
            if (!ObjectUtils.isEmpty(o)) {

                if (needSerial) {

                    PdfContextUtil.assignSerialNumberCell(table, i + 1, size, hasTotal, cellFont);
                }
                for (Field declaredField : declaredFields) {
                    declaredField.setAccessible(true);
                    PdfContextUtil.assignCellByField(table, o, declaredField, null, cellFont);
                }
            }
        }
    }

    /**
     * 创建段
     *
     * @param value       值
     * @param paragraFont 字体
     * @return Paragraph
     */
    public static Paragraph createParagraph(String value, Font paragraFont) {
        return new Paragraph(value, paragraFont);
    }

    /**
     * 创建空白段
     *
     * @param spcae
     * @return
     */
    public static Paragraph createSpace(float spcae) {
        Paragraph paragraph = new Paragraph();
        paragraph.setSpacingAfter(spcae);
        return paragraph;
    }

    /**
     * 创建PdfpHeadCell
     *
     * @param value        cellvalue
     * @param cellHeadFont 字体
     * @return PdfPCell
     */
    public static PdfPCell createPdfpCell(String value, Font cellHeadFont) {
        PdfPCell cell = new PdfPCell();
        Paragraph paragraph = new Paragraph(value, cellHeadFont);
        paragraph.setAlignment(Paragraph.ALIGN_CENTER);
        cell.addElement(paragraph);
        setCellStyle(cell);
        return cell;
    }

    /**
     * 设置cell 样式
     *
     * @param cell cell
     */
    private static void setCellStyle(PdfPCell cell) {
        cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
        cell.setBorderColor(ReportConstant.BRODER_COLOR);
        cell.setPaddingTop(0f);
        cell.setPaddingBottom(10f);
    }

    /**
     * 创建table
     *
     * @param floats 列数组
     * @return Table
     */
    public static PdfPTable createTable(float[] floats) {
        PdfPTable table = new PdfPTable(floats);
        table.setWidthPercentage(100);
        table.setSpacingBefore(1);
        table.setHorizontalAlignment(Element.ALIGN_CENTER);
        return table;
    }

    /**
     * 创建标题块
     *
     * @param serialNumber    序号
     * @param clazz           clazz
     * @param baseColor       字体颜色
     * @param paragraHeadFont 字体
     * @param isSubTitle      是否是子标题
     * @return Chunk 块
     */
    public static Chunk createTitleChunk(String serialNumber, Class<?> clazz, BaseColor baseColor,
            Font paragraHeadFont, boolean isSubTitle) {
        String value;
        if (clazz.equals(ChangesInfo.class)) {
            value = serialNumber;
        } else {
            value = serialNumber + clazz.getAnnotation(ApiModel.class).value();
        }
        Chunk chunk;
        if (isSubTitle) {
            chunk = new Chunk(value, paragraHeadFont);
        } else {
            chunk = new Chunk(value + "\n", paragraHeadFont);
        }
        if (null != baseColor) {

            chunk.setBackground(baseColor);
        }
        // 这里就是统一添加目录的地方 
        chunk.setGenericTag(value);
        return chunk;
    }

    /**
     * 给属性赋值
     *
     * @param table         pdf table
     * @param obj           解析对象
     * @param declaredField 声明字段
     * @param rowSpanArray  合并列
     * @param cellFont      字体
     */
    public static void assignCellByField(PdfPTable table, Object obj,
            Field declaredField, int[] rowSpanArray, Font cellFont) {

        Object o = null;
        log.info("云尽调_PDF报告解析属性,解析的属性为: {}", JSONObject.toJSONString(obj));
        try {
            o = declaredField.get(obj);
        } catch (IllegalAccessException e) {
            log.error("云尽调_商务报告_生成商务报告PDF解析字段出错,字段为: {}, 错误信息为: {}", declaredField.getName(), e);
        }
        List<Phrase> paragraphList = new ArrayList<>();
        if (null != o) {
            String s = o.toString();
            if (o instanceof List) {
                dealListField((List) o, paragraphList, s, cellFont);
            } else {
                setParagraphValue(paragraphList, s, cellFont);
            }
        }
        PdfPCell cell = new PdfPCell();
        int size = paragraphList.size();
        for (int i = 1; i <= size; i++) {
            Phrase phrase = paragraphList.get(i - 1);
            cell.addElement(phrase);
        }
        if (null != rowSpanArray && rowSpanArray.length == CELL_ARRAY_SIZE) {
            cell.setColspan(3);
        }
        setCellStyle(cell);
        table.addCell(cell);
    }

    /**
     * 处理数组属性
     *
     * @param list          原对象
     * @param paragraphList list
     * @param s             value
     * @param cellFont      字体
     */
    public static void dealListField(List<?> list, List<Phrase> paragraphList, String s,
            Font cellFont) {
        Object o1 = list.get(0);
        if (o1 instanceof LawStatusVo) {
            for (Object o2 : list) {
                LawStatusVo lawStatusVo = (LawStatusVo) o2;
                String value = "(" + lawStatusVo.getDate() + " , " + lawStatusVo.getStatus() + ")";
                setParagraphValue(paragraphList, value, cellFont);
            }

        } else {
            setParagraphValue(paragraphList, s, cellFont);
        }
    }

    /**
     * 设置代码段信息
     *
     * @param paragraphList 断码段List
     * @param s             value
     * @param paragraFont   字体
     */
    public static void setParagraphValue(List<Phrase> paragraphList, String s, Font paragraFont) {
        Paragraph paragraph = new Paragraph(s, paragraFont);
        paragraph.setAlignment(Element.ALIGN_CENTER);
        paragraphList.add(paragraph);
    }

    /**
     * 设置表格序号
     *
     * @param table        表
     * @param serialNumber 序号
     * @param size         位置
     * @param hasTotal     是否有合计
     * @param cellFont     字体
     */
    public static void assignSerialNumberCell(PdfPTable table, int serialNumber, int size,
            boolean hasTotal, Font cellFont) {

        PdfPCell cell;
        if (size == serialNumber && hasTotal) {
            cell = PdfContextUtil.createPdfpCell("合计", cellFont);
        } else {
            cell = PdfContextUtil.createPdfpCell(String.valueOf(serialNumber), cellFont);
        }
        table.addCell(cell);
    }

    /**
     * 生成目录
     *
     * @param document  文档
     * @param event     事件
     * @param totalFont 大标题字体
     * @param title     标题
     * @param subFont   子标题字体
     * @throws DocumentException 异常
     */
    public static void createCatalog(Document document, TOCEvent event, Font totalFont,
            String title, Font subFont)
            throws DocumentException {
        document.newPage();
        document.add(new Paragraph(title, totalFont));
        Chunk dottedLine = new Chunk(new DottedLineSeparator());
        List<SimpleEntry<String, Integer>> entries = event.getTOC();
        Paragraph p;
        for (SimpleEntry<String, Integer> entry : entries) {
            p = new Paragraph(entry.getKey(), subFont);
            p.add(dottedLine);
            p.add(String.valueOf(entry.getValue()));
            document.add(p);
        }
    }

    /**
     * 操作PDF (添加页码和封面)
     *
     * @param src  源文件路径
     * @param dest 目标文件
     * @throws IOException
     * @throws DocumentException
     */
    @SneakyThrows
    public static void manipulatePdf(String src, String dest, Font cellFont, String titlePath) {
        PdfReader reader = new PdfReader(src);
        int n = reader.getNumberOfPages();
        // 把目录移动到最前面(把d%页放到第一页,然后排序1~(d-1))
        reader.selectPages(String.format("%d, 1-%d", n, n-1));
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        PdfContentByte pagecontent;
        for (int i = 1; i < n; ) {
            pagecontent = stamper.getOverContent(++i);
            ColumnText.showTextAligned(pagecontent, Element.ALIGN_RIGHT,
                    new Phrase(String.format("第 %s 页", i-1), cellFont), 300, 15, 0);
        }

        PdfReader cover = new PdfReader(titlePath);
        stamper.insertPage(1, cover.getPageSizeWithRotation(1));
        PdfContentByte page1 = stamper.getOverContent(1);
        PdfImportedPage page = stamper.getImportedPage(cover, 1);
        page1.addTemplate(page, 0, 0);
        stamper.close();
        cover.close();
        reader.close();
        File file = new File(src);
        System.out.println(file.delete());
    }


}

生成目录事件

import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;

import com.itextpdf.text.Document;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * @author wl
 * @version 1.0
 * @date 2021-10-27
 */
public class TOCEvent extends PdfPageEventHelper {

    protected List<SimpleEntry<String, Integer>> toc = new ArrayList<>();

    @Override
    public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) {
        toc.add(new SimpleEntry(text, writer.getPageNumber()));
    }

    public List getTOC() {
        return toc;
    }
}

**目录生成事件使用: **

  • writer中写入事件
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(tempFile));
TOCEvent event = new TOCEvent();
writer.setPageEvent(event);
document.open();
  • 写入目录值
String title = "整体概述";
Chunk c = new Chunk("整体概述", paragraHeadFont);
c.setGenericTag(title);
document.add(new Paragraph(c));
  • 生成目录
    /**
     * 生成目录
     *
     * @param document  文档
     * @param event     事件
     * @param totalFont 大标题字体
     * @param title     标题
     * @param subFont   子标题字体
     * @throws DocumentException 异常
     */
    public static void createCatalog(Document document, TOCEvent event, Font totalFont,
            String title, Font subFont)
            throws DocumentException {
        document.newPage();
        document.add(new Paragraph(title, totalFont));
        Chunk dottedLine = new Chunk(new DottedLineSeparator());
        List<SimpleEntry<String, Integer>> entries = event.getTOC();
        Paragraph p;
        for (SimpleEntry<String, Integer> entry : entries) {
            p = new Paragraph(entry.getKey(), subFont);
            p.add(dottedLine);
            p.add(String.valueOf(entry.getValue()));
            document.add(p);
        }
    }
  • 生成页码并把目录移动到首页并添加封面
  /**
     * 操作PDF (添加页码和封面)
     *
     * @param src  源文件路径
     * @param dest 目标文件
     * @throws IOException
     * @throws DocumentException
     */
    @SneakyThrows
    public static void manipulatePdf(String src, String dest, Font cellFont, String titlePath) {
        PdfReader reader = new PdfReader(src);
        int n = reader.getNumberOfPages();
        // 把目录移动到最前面(把d%页放到第一页,然后排序1~(d-1))
        reader.selectPages(String.format("%d, 1-%d", n, n-1));
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        PdfContentByte pagecontent;
        // 添加页码 
        for (int i = 1; i < n; ) {
            pagecontent = stamper.getOverContent(++i);
            ColumnText.showTextAligned(pagecontent, Element.ALIGN_RIGHT,
                    new Phrase(String.format("第 %s 页", i-1), cellFont), 300, 15, 0);
        }

        // 添加封面 
        PdfReader cover = new PdfReader(titlePath);
        stamper.insertPage(1, cover.getPageSizeWithRotation(1));
        PdfContentByte page1 = stamper.getOverContent(1);
        PdfImportedPage page = stamper.getImportedPage(cover, 1);
        page1.addTemplate(page, 0, 0);
        stamper.close();
        cover.close();
        reader.close();
        File file = new File(src);
        System.out.println(file.delete());
    }

样例展示

在这里插入图片描述

参考文章

itext_官方实例

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值