OFDRW 核心功能开发文档

ofdrw 库是一个用于操作 OFD(Open Fixed-layout Document)格式文件的强大工具。本指南将详细介绍如何使用 ofdrw 库进行常见操作,如生成 OFD 文件、转换格式、设置文本和图片等。

环境准备

Maven 依赖

<dependency>
  <groupId>org.ofdrwgroupId>
  <artifactId>ofdrw-fullartifactId>
  <version>2.3.5version>
dependency>

创建基础 OFD 文档

protected void generateOfd(String filePath) {
    if (StringUtils.isBlank(filePath)) {
        return;
    }
    try (OFDDoc ofdDoc = new OFDDoc(Paths.get(filePath))) {

        PageLayout pageLayout = ofdDoc.getPageLayout();
        pageLayout.setHeight(OFD_BODY_HEIGHT);
        pageLayout.setWidth(OFD_BODY_WIDTH);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

生成 OFD 输出流

protected ByteArrayOutputStream generateOfdBos() {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (OFDDoc ofdDoc = new OFDDoc(bos)) {
            PageLayout pageLayout = ofdDoc.getPageLayout();
            pageLayout.setHeight(OFD_BODY_HEIGHT);
            pageLayout.setWidth(OFD_BODY_WIDTH);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return bos;
    }

OFD 转换功能

OFD 转图片

ofd 库并未提供直接转换图片的功能,需要将生成的图片暂存到本地,转成输出流后再删除文件,这里需要注意的是,转换图片所需要的参数不是文件名,而是一个文件夹路径,生成的图片会使用默认的命名方式保存在这个文件夹(0.png,1.png)。

public ByteArrayOutputStream covertOfdBosToPng(ByteArrayOutputStream bos) {
        ByteArrayInputStream ofdInput = new ByteArrayInputStream(bos.toByteArray());
        try {
            String pngFolderPath = String.format("%s/%s/", TEMPORARY_IMAGE_FOLDER, UUID.randomUUID());
            ImageExporter exporter = new ImageExporter(ofdInput, Paths.get(pngFolderPath));
            exporter.export();
            List<Path> pathList = exporter.getImgFilePaths();
            if (CollectionUtils.isNotEmpty(pathList)) {
                ByteArrayOutputStream pngBos = convertFileToByteArray(exporter.getImgFilePaths().get(0).toString());
                deleteFolder(pngFolderPath);
                return pngBos;
            }
            log.warn("图片转换失败");
            return null;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

private void deleteFolder(String folderPath) {
        deleteFolder(new File(folderPath));
    }

    private void deleteFolder(File folder) {
        if (folder.isDirectory()) {
            File[] files = folder.listFiles();
            if (files != null) {
                for (File file : files) {
                    deleteFolder(file); // 递归删除子文件/子文件夹
                }
            }
        }
        folder.delete(); // 删除当前文件或空文件夹
    }

OFD 转 PDF

@Override
    public String covertBosToBase64Str(ByteArrayOutputStream bos) {
        return Base64.encode(bos.toByteArray());
    }

文本元素操作

设置段落(Paragraph)和行内样式(span)

这里需要注意,段落不直接支持设置垂直方向上的对齐方式,需要自己通过内外边距的方式设置垂直对齐。

public static Paragraph generateParagraph(OFDPositionEnum positionEnu, String text) {
        Font font1 = new Font(positionEnu.getFont().getCode(), Paths.get(positionEnu.getFont().getPath()));
        if (OFDPositionEnum.INDEX_VALUE.equals(positionEnu)) {
            font1.setPrintableAsciiWidthMap(FontWidthConstants.NOTO_PRINTABLE_ASCII_WIDTH_MAP);
        }
        Paragraph paragraph = new Paragraph()
                .setPosition(Position.Absolute)
//                .setBorder(0.5d)
                .setXY(positionEnu.getX(), positionEnu.getY())
                .setWidth(positionEnu.getWidth())
                .setHeight(positionEnu.getHeight());
        Span span = new Span(font1, positionEnu.getFontSize(), text);
        if (OFDPositionEnum.INDEX_VALUE.equals(positionEnu)) {
            span.setLetterSpacing(0.1d);
        }

        paragraph.add(span);
        switch (positionEnu.getAlignModeHor()) {
            case HORIZONTAL_LEFT -> paragraph.setTextAlign(TextAlign.left);
            case HORIZONTAL_CENTER -> paragraph.setTextAlign(TextAlign.center);
            case HORIZONTAL_RIGHT -> paragraph.setTextAlign(TextAlign.right);
        }
        switch (positionEnu.getAlignModeVer()) {
            case VERTICAL_TOP -> paragraph.setPaddingTop(0d);
            case VERTICAL_CENTER -> paragraph.setPaddingTop(paragraph.getHeight() / 2 - span.getFontSize() / 2);
            case VERTICAL_BOTTOM -> paragraph.setPaddingTop(paragraph.getHeight() - span.getFontSize());
        }

        return paragraph;
    }

画布与图形操作

创建画布(Canvas)

public static Canvas generateCanvas(OFDAlignModeEnum alignModeHor, OFDAlignModeEnum alignModeVer, double width, double height, double x, double y, int fontThick, double fontSize, FontEnum font, String text) {
        Canvas canvas = new Canvas(width, height)
                .setPosition(Position.Absolute)
//                .setBorder(0.5d)
                .setXY(x, y);
        canvas.setDrawer(ctx -> {
            String fontName = font.getCode();
//            FontManager.getInstance().addFont(Font.loadFont("fonts/SimHei.ttf"));

            ctx.addFont(fontName, Paths.get(font.getPath()));
            ctx.font = String.format("bold %d %fmm %s", fontThick, fontSize, FontName.SimHei);
            ctx.fillStyle = OFDLayoutConstants.FONT_COLOR;
            double textWidth = ctx.measureText(text).width;
            double textX = getTextXY(alignModeHor, width, height, textWidth, fontSize);
            double textY = getTextXY(alignModeVer, width, height, textWidth, fontSize);
            StringBuilder currentLine = new StringBuilder();
            for (int i = 0; i < text.length(); i++) {
                currentLine.append(text.charAt(i));
                double currentLineWidth = ctx.measureText(currentLine.toString()).width;
                if (currentLineWidth >= width - fontSize) {
                    ctx.fillText(currentLine.toString(), textX, textY);
                    currentLine = new StringBuilder();
                    textY += fontSize * 3 / 2;
                }
            }
            if (!currentLine.isEmpty()) {
                ctx.fillText(currentLine.toString(), textX, textY);
            }
        });
        return canvas;
    }

插入图片到画布

private static Img generatorImg(String filePath, double width, double height, double x, double y) {
        try {
            Path imgPath = Paths.get(filePath);
            return new Img(width, height, imgPath)
                    .setPosition(Position.Absolute)
//                    .setBorder(0d)
//                    .setPadding(0d)
                    .setX(x).setY(y);
        } catch (IOException e) {
            System.out.println("生成图片失败");
            throw new RuntimeException(e);
        }

    }

public static ByteArrayOutputStream generateOfdBos(OfdAuthCertDataSource dataSource) {
        if (Objects.isNull(dataSource) || CollectionUtils.isEmpty(dataSource.getOfdGeneralLayout())) {
            return new ByteArrayOutputStream();
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (OFDDoc ofdDoc = new OFDDoc(bos)) {
            PageLayout pageLayout = ofdDoc.getPageLayout();
            pageLayout.setHeight(OFDLayoutConstants.OFD_BODY_HEIGHT);
            pageLayout.setWidth(OFDLayoutConstants.OFD_BODY_WIDTH);
            VirtualPage virtualPage = new VirtualPage(pageLayout);
            virtualPage.add(generatorImg(...));
            ofdDoc.addVPage(virtualPage);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return bos;
    }

背景图片设置

页面添加背景图

private static Img generatorImg(String filePath, double width, double height, double x, double y) {
        try {
            Path imgPath = Paths.get(filePath);
            return new Img(width, height, imgPath)
                    .setPosition(Position.Absolute)
//                    .setBorder(0d)
//                    .setPadding(0d)
                    .setX(x).setY(y);
        } catch (IOException e) {
            System.out.println("生成图片失败");
            throw new RuntimeException(e);
        }

    }

public static ByteArrayOutputStream generateOfdBos(OfdAuthCertDataSource dataSource) {
        if (Objects.isNull(dataSource) || CollectionUtils.isEmpty(dataSource.getOfdGeneralLayout())) {
            return new ByteArrayOutputStream();
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (OFDDoc ofdDoc = new OFDDoc(bos)) {
            PageLayout pageLayout = ofdDoc.getPageLayout();
            pageLayout.setHeight(OFDLayoutConstants.OFD_BODY_HEIGHT);
            pageLayout.setWidth(OFDLayoutConstants.OFD_BODY_WIDTH);
            VirtualPage virtualPage = new VirtualPage(pageLayout);
            virtualPage.add(generatorImg(...));
            ofdDoc.addVPage(virtualPage);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return bos;
    }

完整示例结构

实体类

三方字体库枚举
@Getter
@AllArgsConstructor
public enum FontEnum {
    SIM_HEI("simHei", "黑体", "D:/data/font/simhei.ttf"),
//    SIM_SUN("simSun", "宋体", "D:/data/font/simsun.ttf"),
//    MS_YH("msyh", "微软雅黑", "D:/data/font/msyh.ttc"),
//    MS_YH_BD("msyhbd", "微软雅黑-粗体", "D:/data/font/msyhbd.ttc"),
//    MS_YH_L("msyhl", "微软雅黑-细", "D:/data/font/msyhl.ttc"),
//    CALI_BRI("calibri", "Calibri", "D:/data/font/calibri.ttf"),
    ;
    private final String code;
    private final String desc;
    private final String path;
}
对齐方式枚举
@Getter
@AllArgsConstructor
public enum OFDAlignModeEnum {
    HORIZONTAL_LEFT("0", "水平居左"),
    HORIZONTAL_CENTER("1", "水平居中"),
    HORIZONTAL_RIGHT("2", "水平居右"),
    VERTICAL_TOP("3", "垂直居上"),
    VERTICAL_CENTER("4", "垂直居中"),
    VERTICAL_BOTTOM("5", "垂直居下"),
    ;

    private final String code;
    private final String desc;
}
自定义字间距常量
public class FontWidthConstants {

    /**
     * 可打印的ASCII表字母宽度所占用百分比
     * 

* ASCII区间: [32,126] *

* 其中空格特殊处理,默认为半个字符宽度也就是 0.5 */ public static final double[] NOTO_PRINTABLE_ASCII_WIDTH_MAP = { // 空格 (ASCII 32) 0.5, // 标点符号及特殊字符 (ASCII 33-47) 0.3125, // '!' (ASCII 33) 0.435546875, // '"' (ASCII 34) 0.63818359375, // '#' (ASCII 35) 0.58642578125, // '$' (ASCII 36) 0.8896484375, // '%' (ASCII 37) 0.8701171875, // '&' (ASCII 38) 0.25634765625, // ''' (ASCII 39) 0.333984375, // '(' (ASCII 40) 0.333984375, // ')' (ASCII 41) 0.455078125, // '*' (ASCII 42) 0.74169921875, // '+' (ASCII 43) 0.24072265625, // ',' (ASCII 44) 0.4326171875, // '-' (ASCII 45) 0.24072265625, // '.' (ASCII 46) 0.42724609375, // '/' (ASCII 47) // 数字 (ASCII 48-57) // 数字 '0' (ASCII 48) 的宽度从 0.58642578125 调整为 0.5 0.5, // '0' (ASCII 48) 0.58642578125, // '1' (ASCII 49) 0.58642578125, // '2' (ASCII 50) 0.58642578125, // '3' (ASCII 51) 0.58642578125, // '4' (ASCII 52) 0.58642578125, // '5' (ASCII 53) 0.58642578125, // '6' (ASCII 54) 0.58642578125, // '7' (ASCII 55) 0.58642578125, // '8' (ASCII 56) 0.58642578125, // '9' (ASCII 57) // 标点符号及特殊字符 (ASCII 58-64) 0.24072265625, // ':' (ASCII 58) 0.24072265625, // ';' (ASCII 59) 0.74169921875, // '<' (ASCII 60) 0.74169921875, // '=' (ASCII 61) 0.74169921875, // '>' (ASCII 62) 0.48291015625, // '?' (ASCII 63) 1.03125, // '@' (ASCII 64) // 大写字母 (ASCII 65-90) 0.51318359375, // 'A' (ASCII 65) 0.51318359375, // 'B' (ASCII 66) 0.51318359375, // 'C' (ASCII 67) 0.51318359375, // 'D' (ASCII 68) 0.5498046875, // 'E' (ASCII 69) 0.53125, // 'F' (ASCII 70) 0.51318359375, // 'G' (ASCII 71) 0.51318359375, // 'H' (ASCII 72) 0.51318359375, // 'I' (ASCII 73) 0.51318359375, // 'J' (ASCII 74) 0.51318359375, // 'K' (ASCII 75) 0.51318359375, // 'L' (ASCII 76) 0.51318359375, // 'M' (ASCII 77) 0.51318359375, // 'N' (ASCII 78) // 大写字母 'O' (ASCII 79) 的宽度从 0.74365234375 调整为 0.6 0.51318359375, // 'O' (ASCII 79) 0.51318359375, // 'P' (ASCII 80) 0.61181640625, // 'Q' (ASCII 81) 0.51318359375, // 'R' (ASCII 82) 0.65283203125, // 'S' (ASCII 83) 0.5771484375, // 'T' (ASCII 84) 0.5732421875, // 'U' (ASCII 85) 0.51318359375, // 'V' (ASCII 86) 0.67626953125, // 'W' (ASCII 87) 0.65283203125, // 'X' (ASCII 88) // 标点符号及特殊字符 (ASCII 91-96) 0.64501953125, // '[' (ASCII 91) 0.603515625, // '\' (ASCII 92) 0.6201171875, // ']' (ASCII 93) 0.333984375, // '^' (ASCII 94) 0.416015625, // '_' (ASCII 95) 0.333984375, // '`' (ASCII 96) // 小写字母 (ASCII 97-122) 0.74169921875, // 'a' (ASCII 97) 0.7734375, // 'b' (ASCII 98) 0.2939453125, // 'c' (ASCII 99) 0.39599609375, // 'd' (ASCII 100) 0.634765625, // 'e' (ASCII 101) 0.51318359375, // 'f' (ASCII 102) 0.97705078125, // 'g' (ASCII 103) 0.81298828125, // 'h' (ASCII 104) 0.81494140625, // 'i' (ASCII 105) 0.61181640625, // 'j' (ASCII 106) 0.81494140625, // 'k' (ASCII 107) 0.65283203125, // 'l' (ASCII 108) // 小写字母 'm' (ASCII 109) 的宽度从 0.6396484375 调整为 0.55 0.55, // 'm' (ASCII 109) 0.6396484375, // 'n' (ASCII 110) 0.5673828125, // 'o' (ASCII 111) 0.3466796875, // 'p' (ASCII 112) 0.6396484375, // 'q' (ASCII 113) 0.61572265625, // 'r' (ASCII 114) 0.26611328125, // 's' (ASCII 115) 0.26708984375, // 't' (ASCII 116) 0.54443359375, // 'u' (ASCII 117) 0.26611328125, // 'v' (ASCII 118) 0.93701171875, // 'w' (ASCII 119) 0.6162109375, // 'x' (ASCII 120) 0.6357421875, // 'y' (ASCII 121) 0.638671875, // 'z' (ASCII 122) // 标点符号及特殊字符 (ASCII 123-126) 0.6396484375, // '{' (ASCII 123) 0.3818359375, // '|' (ASCII 124) 0.462890625, // '}' (ASCII 125) 0.37255859375, // '~' (ASCII 126) }; }

每个组件位置枚举
@Getter
@AllArgsConstructor
public enum OFDPositionEnum {
    TITLE("标题", OFDLayoutConstants.OFD_BODY_WIDTH, 18.5d, 0d, 41d, 600, OFDLayoutConstants.FONT_SIZE_32MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_TOP),
    INDEX_NAME("编号标题:", 60d, 23.5d, 0d, 59.5d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    INDEX_VALUE("编号填充", 133d, 5d, 61d, 59d, 500, OFDLayoutConstants.FONT_SIZE_14MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),

    DATA_SOURCE_NAME("资源数据名称标题", 65.5d, 15d, 0d, 83d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    DATA_SOURCE_VALUE("数据资源名称填充", 123d, 12d, 70d, 80d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_CENTER),
    DATA_SOURCE_VALUE_2("数据资源名称填充", 123d, 12d, 70d, 80d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),

    REGISTER_SUBJECT_NAME("登记主体标题", 65.5d, 14d, 0d, 98d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    REGISTER_SUBJECT_VALUE("登记主体填充", 123d, 18d, 70d, 92d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_CENTER),

    INDUSTRY_TYPE_NAME("行业分类标题", 65.5d, 15d, 0d, 112d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    INDUSTRY_TYPE_VALUE("行业分类填充", 123d, 12d, 70d, 112d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),

    DATA_CONTENT_INTRODUCTION_NAME("数据内容标题", 65.5d, 24d, 0d, 127d, 500, OFDLayoutConstants.FONT_SIZE_15MM,FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    DATA_CONTENT_INTRODUCTION_VALUE("数据内容简介填充", 123d, 20d, 70d, 127d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),

    VALID_DATE_NAME("有效期标题", 65.5d, 15d, 0d, 151d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    VALID_DATE_VALUE("有效期填充", 123d, 6d, 70d, 151d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),

    REGISTER_INST_NAME("登记机构标题", 65.5d, 61d, 0d, 166d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    REGISTER_INST_VALUE("登记机构填充", 123d, 12d, 70d, 166d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),

    QR_CODE("二维码", 28d, 28d, 40d, 227d, 0, 0d, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),
    QR_CODE_Name("二维码标题", 28d, 5d, 40d, 257.5d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),

    STAMP_UNIT("盖章单位", OFDLayoutConstants.STAMP_CENTER_X, 8d, 0d, 236d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    STAMP_TIME("盖章时间", OFDLayoutConstants.STAMP_CENTER_X, 11.5, 0d, 244d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    ELECTRONIC_SIGNAL("电子签章", 40d, 40d, 147d - 20d, 245d - 20d, 0, 0d, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),
    BACK_PNG("背景图片", OFDLayoutConstants.OFD_BODY_WIDTH, OFDLayoutConstants.OFD_BODY_HEIGHT, 0d, 0d, 0, 0d, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),


    DATA_SOURCE_NAME_PRO("数据产品和服务名称标题", 76.5d, 23d, 0d, 83d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    DATA_SOURCE_VALUE_PRO("数据产品和服务名称填充", 112d, 12d, 80d, 80d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_CENTER),
    DATA_SOURCE_VALUE_PRO_2("数据产品和服务名称填充", 112d, 12d, 80d, 80d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),
    REGISTER_SUBJECT_NAME_PRO("登记主体标题", 76.5d, 15d, 0d, 106d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    REGISTER_SUBJECT_VALUE_PRO("登记主体填充", 112d, 18d, 80d, 100d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_CENTER),
    INDUSTRY_TYPE_NAME_PRO("行业分类标题", 76.5d, 15d, 0d, 121d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    INDUSTRY_TYPE_VALUE_PRO("行业分类填充", 112d, 12d, 80d, 121d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),
    DATA_CONTENT_INTRODUCTION_NAME_PRO("产品和服务简介标题", 76.5d, 23d, 0d, 136d, 500, OFDLayoutConstants.FONT_SIZE_15MM,FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    DATA_CONTENT_INTRODUCTION_VALUE_PRO("产品和服务简介填充", 112d, 20d, 80d, 136d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),
    VALID_DATE_NAME_PRO("有效期标题", 76.5d, 14d, 0d, 159d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    VALID_DATE_VALUE_PRO("有效期填充", 112d, 6d, 80d, 159d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),
    REGISTER_INST_NAME_PRO("登记机构标题", 76.5d, 61d, 0d, 173d, 500, OFDLayoutConstants.FONT_SIZE_15MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    REGISTER_INST_VALUE_PRO("登记机构填充", 112d, 12d, 80d, 173d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_LEFT, OFDAlignModeEnum.VERTICAL_TOP),

    QR_CODE_PRO("二维码", 28d, 28d, 40d, 234d, 0, 0d, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),
    QR_CODE_Name_PRO("二维码标题", 28d, 5d, 40d, 264.5d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),

    STAMP_UNIT_PRO("盖章单位", OFDLayoutConstants.STAMP_CENTER_X, 8d, 0d, 243d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),
    STAMP_TIME_PRO("盖章时间", OFDLayoutConstants.STAMP_CENTER_X, 11.5, 0d, 251d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.SIM_HEI, OFDAlignModeEnum.HORIZONTAL_RIGHT, OFDAlignModeEnum.VERTICAL_TOP),


//    QR_CODE("二维码", 28d, 28d, 40d, 227d, 0, 0d, FontEnum.MS_YH, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),
//    QR_CODE_Name("二维码标题", 28d, OFDLayoutConstants.FONT_HEIGHT_12MM, 40d, 257d, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.MS_YH, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),
//
//    STAMP_UNIT("盖章单位", 210d, OFDLayoutConstants.FONT_HEIGHT_12MM, OFDLayoutConstants.STAMP_CENTER_X, OFDLayoutConstants.STAMP_UNIT_Y, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.MS_YH_BD, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),
//    STAMP_TIME("盖章时间", 210d, OFDLayoutConstants.FONT_HEIGHT_12MM, OFDLayoutConstants.STAMP_CENTER_X, OFDLayoutConstants.STAMP_TIME_Y, 500, OFDLayoutConstants.FONT_SIZE_12MM, FontEnum.MS_YH_BD, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),
//    ELECTRONIC_SIGNAL("电子签章", 40d, 40d, 147d - 20d, 245d - 20d, 0, 0d, FontEnum.MS_YH, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),
//    BACK_PNG("背景图片", OFDLayoutConstants.OFD_BODY_WIDTH, OFDLayoutConstants.OFD_BODY_HEIGHT, 0d, 0d, 0, 0d, FontEnum.MS_YH, OFDAlignModeEnum.HORIZONTAL_CENTER, OFDAlignModeEnum.VERTICAL_CENTER),

    ;
    private final String desc;
    private final Double width;
    private final Double height;
    private final Double x;
    private final Double y;
    private final int fontThick;
    private final Double fontSize;
    private final FontEnum font;
    private final OFDAlignModeEnum alignModeHor;
    private final OFDAlignModeEnum alignModeVer;
}
填充数据实体类
@Data
public class OfdData {
    /**
     * 数据类型
     */
    private AuthType authType;

    /**
     * 登记资源|产品 标题
     */
    private String title;

    /**
     * 登记资源|产品 编号
     */
    private String code;

    /**
     * 登记资源|产品 名称
     */
    private String name;

    /**
     * 登记主体
     */
    private String registerSubject;

    /**
     * 行业分类
     */
    private String industryType;

    /**
     * 数据内容简介
     */
    private String contentIntroduction;

    /**
     * 证书有效期
     */
    private String dateValid;

    /**
     * 登记机构
     */
    private String registerInst;

    /**
     * 盖章单位
     */
    private String stampUnit;

    /**
     * 盖章时间
     */
    private String stampTime;

    /**
     * 背景图片地址
     */
    private String backUrl;

    /**
     * 二维码图片地址
     */
    private String qrCodeUrl;

    /**
     * 二维码图片地址名称
     */
    private String qrCodeUrlName;

    /**
     * 保存地址
     */
    private String savePath;

    /**
     * 600 最多有1个登记主体,5个共有主体,每个登记主体名称长度为100汉字,多个之前用“、”分隔
     *
     * @param subjectList
     */
    public void setRegisterSubject(List<String> subjectList) {
        if (CollectionUtils.isNotEmpty(subjectList)) {
            String registerSubject = subjectList.stream()
                    .limit(6)
                    .filter(StringUtils::isNotBlank)
                    .map(str -> str.length() > 100 ? str.substring(0, 100) : str)
                    .collect(Collectors.joining(","));
            this.registerSubject = registerSubject.length() > 600 ? registerSubject.substring(0, 600) : registerSubject;
        }
    }

    public void setRegisterSubject(String registerSubject) {
        this.registerSubject = registerSubject;
    }
}
元素组件实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Item {
    private String text;

    private OFDPositionEnum position;
}

业务类

工厂接口
public interface AuthCertGenerator {
    String generateOfdBase64(OfdData data);

    byte[] generateOfdByteArray(OfdData data);

    ByteArrayOutputStream generateOfd(OfdData data);

    void generateOfd(String filePath, OfdData data);

    ByteArrayOutputStream covertBase64StrToBos(String str);

    String covertBosToBase64Str(ByteArrayOutputStream bos);

    ByteArrayOutputStream covertOfdBosToPng(ByteArrayOutputStream bos);

    ByteArrayOutputStream covertOfdToPng(OfdData data);

    ByteArrayOutputStream covertOfdBosToPdf(ByteArrayOutputStream bos);

    ByteArrayOutputStream covertOfdToPdf(OfdData data);

    void saveFile(String filePath, ByteArrayOutputStream bos);
}
抽象方法,实现工厂接口,实现公共方法
@Slf4j
public abstract class AbstractAuthCertGenerator implements AuthCertGenerator{
    // 页面整体宽度
    public static final Double OFD_BODY_WIDTH = 210d;

    // 页面整体高度
    protected static final Double OFD_BODY_HEIGHT = 297d;

    // 字体颜色
    public static final String FONT_COLOR = "#000000";

    public static final String SIGN_FILE_PATH = "/data/template/zmb.png";

    public static final String TEMPORARY_IMAGE_FOLDER = "D:/data/OFD/PNG";

    @Override
    public ByteArrayOutputStream covertBase64StrToBos(String str) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        // 检查 Base64 字符串是否有效
        if (StringUtils.isBlank(str)) {
            log.warn("Base64 String is null or empty");
            return null;
        }

        // 解码 Base64 字符串
        byte[] pdfBytes = Base64.decode(str);
        try {
            bos.write(pdfBytes);
        } catch (IOException e) {
            throw new UncheckedIOException("编码失败", e);
        }
        return bos;
    }

    @Override
    public String covertBosToBase64Str(ByteArrayOutputStream bos) {
        return Base64.encode(bos.toByteArray());
    }

    @Override
    public ByteArrayOutputStream covertOfdBosToPdf(ByteArrayOutputStream bos) {
        // 关键步骤:将OFD输出流转为输入流
        ByteArrayInputStream ofdInput = new ByteArrayInputStream(bos.toByteArray());
        ByteArrayOutputStream pdfOutput = new ByteArrayOutputStream();
        ConvertHelper.toPdf(ofdInput, pdfOutput); // 核心转换
        return pdfOutput;
    }

    @Override
    public ByteArrayOutputStream covertOfdBosToPng(ByteArrayOutputStream bos) {
        ByteArrayInputStream ofdInput = new ByteArrayInputStream(bos.toByteArray());
        try {
            String pngFolderPath = String.format("%s/%s/", TEMPORARY_IMAGE_FOLDER, UUID.randomUUID());
            ImageExporter exporter = new ImageExporter(ofdInput, Paths.get(pngFolderPath));
            exporter.export();
            List<Path> pathList = exporter.getImgFilePaths();
            if (CollectionUtils.isNotEmpty(pathList)) {
                ByteArrayOutputStream pngBos = convertFileToByteArray(exporter.getImgFilePaths().get(0).toString());
                deleteFolder(pngFolderPath);
                return pngBos;
            }
            log.warn("图片转换失败");
            return null;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void saveFile(String filePath, ByteArrayOutputStream bos) {
        Path path = Paths.get(filePath);
        try {
            Files.write(path, bos.toByteArray());
            System.out.println("OFD 文件已生成并保存至: " + path.toAbsolutePath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    protected ByteArrayOutputStream generateOfdBos(List<Item> itemList) {
        if (CollectionUtils.isEmpty(itemList)) {
            return null;
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (OFDDoc ofdDoc = new OFDDoc(bos)) {
            PageLayout pageLayout = ofdDoc.getPageLayout();
            pageLayout.setHeight(OFD_BODY_HEIGHT);
            pageLayout.setWidth(OFD_BODY_WIDTH);
            VirtualPage virtualPage = generateVirtualPage(itemList, pageLayout);
            ofdDoc.addVPage(virtualPage);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return bos;
    }

    protected void generateOfd(String filePath, List<Item> itemList) {
        if (StringUtils.isBlank(filePath) || CollectionUtils.isEmpty(itemList)) {
            return;
        }
        try (OFDDoc ofdDoc = new OFDDoc(Paths.get(filePath))) {

            PageLayout pageLayout = ofdDoc.getPageLayout();
            pageLayout.setHeight(OFD_BODY_HEIGHT);
            pageLayout.setWidth(OFD_BODY_WIDTH);
            VirtualPage virtualPage = generateVirtualPage(itemList, pageLayout);
            ofdDoc.addVPage(virtualPage);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static VirtualPage generateVirtualPage(List<Item> items, PageLayout pageLayout) {
        VirtualPage virtualPage = new VirtualPage(pageLayout);
        for (Item item : items) {
            if (Objects.nonNull(item)) {
                OFDPositionEnum positionEnu = item.getPosition();
                Div div = switch (positionEnu) {
                    case BACK_PNG ->
                            generatorBackgroundImage(item.getText(), positionEnu.getWidth(), positionEnu.getHeight()); // 背景图层要最后添加
                    case ELECTRONIC_SIGNAL ->
                            generatorImg(SIGN_FILE_PATH, positionEnu.getWidth(), positionEnu.getHeight(), positionEnu.getX(), positionEnu.getY());// 电子签章,用于mock数据,实际签章调用平台接口
                    case QR_CODE, QR_CODE_PRO ->
                            generatorImg(item.getText(), positionEnu.getWidth(), positionEnu.getHeight(), positionEnu.getX(), positionEnu.getY());// 二维码图片
                    case STAMP_UNIT, STAMP_UNIT_PRO ->
                            generateParagraphStampInfo(positionEnu, item.getText());// TODO 盖章单位,待确认
                    case STAMP_TIME, STAMP_TIME_PRO ->
                            generateParagraphStampInfo(positionEnu, item.getText());// 盖章时间,签章当天时间
                    default ->
                            generateParagraph(positionEnu, item.getText());
                };
                virtualPage.add(div);
            }
        }
        return virtualPage;
    }

    public static Paragraph generateParagraph(OFDPositionEnum positionEnu, String text) {
        Font font1 = new Font(positionEnu.getFont().getCode(), Paths.get(positionEnu.getFont().getPath()));
        if (OFDPositionEnum.INDEX_VALUE.equals(positionEnu)) {
            font1.setPrintableAsciiWidthMap(FontWidthConstants.NOTO_PRINTABLE_ASCII_WIDTH_MAP);
        }
        Paragraph paragraph = new Paragraph()
                .setPosition(Position.Absolute)
//                .setBorder(0.5d)
                .setXY(positionEnu.getX(), positionEnu.getY())
                .setWidth(positionEnu.getWidth())
                .setHeight(positionEnu.getHeight());
        Span span = new Span(font1, positionEnu.getFontSize(), text);
        if (OFDPositionEnum.INDEX_VALUE.equals(positionEnu)) {
            span.setLetterSpacing(0.1d);
        }

        paragraph.add(span);
        switch (positionEnu.getAlignModeHor()) {
            case HORIZONTAL_LEFT -> paragraph.setTextAlign(TextAlign.left);
            case HORIZONTAL_CENTER -> paragraph.setTextAlign(TextAlign.center);
            case HORIZONTAL_RIGHT -> paragraph.setTextAlign(TextAlign.right);
        }
        switch (positionEnu.getAlignModeVer()) {
            case VERTICAL_TOP -> paragraph.setPaddingTop(0d);
            case VERTICAL_CENTER -> paragraph.setPaddingTop(paragraph.getHeight() / 2 - span.getFontSize() / 2);
            case VERTICAL_BOTTOM -> paragraph.setPaddingTop(paragraph.getHeight() - span.getFontSize());
        }

        return paragraph;
    }

    private static Paragraph generateParagraphStampInfo(OFDPositionEnum positionEnu, String text) {
        Font font1 = new Font(positionEnu.getFont().getCode(), Paths.get(positionEnu.getFont().getPath()));
        font1.setPrintableAsciiWidthMap(FontName.TIMES_NEW_ROMAN_PRINTABLE_ASCII_MAP);
        Paragraph paragraph = new Paragraph()
                .setPosition(Position.Absolute)
//                .setBorder(0.5d)
                .setXY(OFD_BODY_WIDTH - 64d - positionEnu.getWidth() / 2, positionEnu.getY())
                .setWidth(positionEnu.getWidth())
                .setHeight(positionEnu.getHeight())
                .setTextAlign(TextAlign.center)
                .setPaddingTop(0d);
        Span span = new Span(font1, positionEnu.getFontSize(), text);
        paragraph.add(span);
        return paragraph;
    }

    private static Img generatorImg(String filePath, double width, double height, double x, double y) {
        try {
            Path imgPath = Paths.get(filePath);
            return new Img(width, height, imgPath)
                    .setPosition(Position.Absolute)
//                    .setBorder(0d)
//                    .setPadding(0d)
                    .setX(x).setY(y);
        } catch (IOException e) {
            System.out.println("生成图片失败");
            throw new RuntimeException(e);
        }

    }

    /**
     * 生成背景图片
     *
     * @param filePath
     * @param width
     * @param height
     * @return
     * @throws IOException
     */
    private static Img generatorBackgroundImage(String filePath, double width, double height) {
        try {
            Path imgPath = Paths.get(filePath);
            Img img = new Img(width, height, imgPath)
                    .setPosition(Position.Absolute)
//                    .setBorder(0.1d)
                    .setX(0d).setY(0d) // 坐标原点
                    .setLayer(Type.Background);
            return img;
        } catch (IOException e) {
            System.out.println("生成图片失败");
            throw new RuntimeException(e);
        }
    }

    private ByteArrayOutputStream convertFileToByteArray(String filePath)  {
        File file = new File(filePath);
        try (FileInputStream fis = new FileInputStream(file);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            return bos;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void deleteFolder(String folderPath) {
        deleteFolder(new File(folderPath));
    }

    private void deleteFolder(File folder) {
        if (folder.isDirectory()) {
            File[] files = folder.listFiles();
            if (files != null) {
                for (File file : files) {
                    deleteFolder(file); // 递归删除子文件/子文件夹
                }
            }
        }
        folder.delete(); // 删除当前文件或空文件夹
    }
}
实现类
public class AuthCertOPFGenerator extends AbstractAuthCertGenerator{

    @Override
    public String generateOfdBase64(OfdData data) {
        byte[] bytes = generateOfdByteArray(data);
        if (Objects.isNull(bytes) || bytes.length == 0) {
            return null;
        }
        return Base64.encode(bytes);
    }

    @Override
    public byte[] generateOfdByteArray(OfdData data) {
        ByteArrayOutputStream bos = generateOfd(data);
        if (Objects.isNull(bos)) {
            return null;
        }
        return bos.toByteArray();
    }

    @Override
    public ByteArrayOutputStream generateOfd(OfdData data) {
        List<Item> itemList = dataInit(data);
        if (CollectionUtils.isEmpty(itemList)) {
            return null;
        }
        return generateOfdBos(itemList);
    }

    @Override
    public void generateOfd(String filePath, OfdData data) {
        List<Item> itemList = dataInit(data);
        if (CollectionUtils.isEmpty(itemList)) {
            return;
        }
        generateOfd(filePath, itemList);

    }

    @Override
    public ByteArrayOutputStream covertOfdToPng(OfdData data) {
        ByteArrayOutputStream bos = generateOfd(data);
        if (Objects.isNull(bos)) {
            return null;
        }
        return covertOfdBosToPng(bos);
    }

    @Override
    public ByteArrayOutputStream covertOfdToPdf(OfdData data) {
        ByteArrayOutputStream bos = generateOfd(data);
        if (Objects.isNull(bos)) {
            return null;
        }
        return covertOfdBosToPdf(bos);
    }

    private List<Item> dataInit(OfdData data) {
        if (Objects.nonNull(data.getAuthType())) {
            return switch (data.getAuthType()) {
                case TENURE -> tenureInit(data);
                case PROCESS -> processInit(data);
            };
        }
        return null;
    }

    private List<Item> tenureInit(OfdData data) {
        List<Item> ofdGeneralLayout = new ArrayList<>();
        ofdGeneralLayout.add(new Item(data.getTitle(), OFDPositionEnum.TITLE));
        ofdGeneralLayout.add(new Item("编号 :", OFDPositionEnum.INDEX_NAME));
        ofdGeneralLayout.add(new Item(data.getCode(), OFDPositionEnum.INDEX_VALUE));
        ofdGeneralLayout.add(new Item("数据资源名称 :", OFDPositionEnum.DATA_SOURCE_NAME));
        if (data.getName().length() >= 27) {
            ofdGeneralLayout.add(new Item(data.getName(), OFDPositionEnum.DATA_SOURCE_VALUE_2));
        } else {
            ofdGeneralLayout.add(new Item(data.getName(), OFDPositionEnum.DATA_SOURCE_VALUE));
        }
        ofdGeneralLayout.add(new Item("登记主体 :", OFDPositionEnum.REGISTER_SUBJECT_NAME));
        ofdGeneralLayout.add(new Item(data.getRegisterSubject(), OFDPositionEnum.REGISTER_SUBJECT_VALUE));
        ofdGeneralLayout.add(new Item("行业分类 :", OFDPositionEnum.INDUSTRY_TYPE_NAME));
        ofdGeneralLayout.add(new Item(data.getIndustryType(), OFDPositionEnum.INDUSTRY_TYPE_VALUE));
        ofdGeneralLayout.add(new Item("数据内容简介 :", OFDPositionEnum.DATA_CONTENT_INTRODUCTION_NAME));
        String contentIntroduction = data.getContentIntroduction().length() >= 76 ? data.getContentIntroduction().substring(0, 76) + "..." : data.getContentIntroduction();
        ofdGeneralLayout.add(new Item(contentIntroduction, OFDPositionEnum.DATA_CONTENT_INTRODUCTION_VALUE));
        ofdGeneralLayout.add(new Item("有效期 :", OFDPositionEnum.VALID_DATE_NAME));
        ofdGeneralLayout.add(new Item(data.getDateValid(), OFDPositionEnum.VALID_DATE_VALUE));
        ofdGeneralLayout.add(new Item("登记机构 :", OFDPositionEnum.REGISTER_INST_NAME));
        ofdGeneralLayout.add(new Item(data.getRegisterInst(), OFDPositionEnum.REGISTER_INST_VALUE));
        ofdGeneralLayout.add(new Item(data.getQrCodeUrl(), OFDPositionEnum.QR_CODE));
        ofdGeneralLayout.add(new Item("查验", OFDPositionEnum.QR_CODE_Name));
        ofdGeneralLayout.add(new Item(data.getStampUnit(), OFDPositionEnum.STAMP_UNIT));
        ofdGeneralLayout.add(new Item(data.getStampTime(), OFDPositionEnum.STAMP_TIME));
        ofdGeneralLayout.add(new Item(data.getBackUrl(), OFDPositionEnum.BACK_PNG));
        return ofdGeneralLayout;
    }

    private List<Item> processInit(OfdData data) {
        List<Item> ofdGeneralLayout = new ArrayList<>();
        ofdGeneralLayout.add(new Item(data.getTitle(), OFDPositionEnum.TITLE));
        ofdGeneralLayout.add(new Item("编号 :", OFDPositionEnum.INDEX_NAME));
        ofdGeneralLayout.add(new Item(data.getCode(), OFDPositionEnum.INDEX_VALUE));
        ofdGeneralLayout.add(new Item("数据产品和服务名称 :", OFDPositionEnum.DATA_SOURCE_NAME_PRO));
        if (data.getName().length() >= 27) {
            ofdGeneralLayout.add(new Item(data.getName(), OFDPositionEnum.DATA_SOURCE_VALUE_PRO_2));
        } else {
            ofdGeneralLayout.add(new Item(data.getName(), OFDPositionEnum.DATA_SOURCE_VALUE_PRO));
        }
        ofdGeneralLayout.add(new Item("登记主体 :", OFDPositionEnum.REGISTER_SUBJECT_NAME_PRO));
        ofdGeneralLayout.add(new Item(data.getRegisterSubject(), OFDPositionEnum.REGISTER_SUBJECT_VALUE_PRO));
        ofdGeneralLayout.add(new Item("行业分类 :", OFDPositionEnum.INDUSTRY_TYPE_NAME_PRO));
        ofdGeneralLayout.add(new Item(data.getIndustryType(), OFDPositionEnum.INDUSTRY_TYPE_VALUE_PRO));
        ofdGeneralLayout.add(new Item("产品和服务简介 :", OFDPositionEnum.DATA_CONTENT_INTRODUCTION_NAME_PRO));
        String contentIntroduction = data.getContentIntroduction().length() >= 76 ? data.getContentIntroduction().substring(0, 76) + "..." : data.getContentIntroduction();
        ofdGeneralLayout.add(new Item(contentIntroduction, OFDPositionEnum.DATA_CONTENT_INTRODUCTION_VALUE_PRO));
        ofdGeneralLayout.add(new Item("有效期 :", OFDPositionEnum.VALID_DATE_NAME_PRO));
        ofdGeneralLayout.add(new Item(data.getDateValid(), OFDPositionEnum.VALID_DATE_VALUE_PRO));
        ofdGeneralLayout.add(new Item("登记机构 :", OFDPositionEnum.REGISTER_INST_NAME_PRO));
        ofdGeneralLayout.add(new Item(data.getRegisterInst(), OFDPositionEnum.REGISTER_INST_VALUE_PRO));
        ofdGeneralLayout.add(new Item(data.getQrCodeUrl(), OFDPositionEnum.QR_CODE_PRO));
        ofdGeneralLayout.add(new Item("查验", OFDPositionEnum.QR_CODE_Name_PRO));
        ofdGeneralLayout.add(new Item(data.getStampUnit(), OFDPositionEnum.STAMP_UNIT_PRO));
        ofdGeneralLayout.add(new Item(data.getStampTime(), OFDPositionEnum.STAMP_TIME_PRO));
        ofdGeneralLayout.add(new Item(data.getBackUrl(), OFDPositionEnum.BACK_PNG));
        return ofdGeneralLayout;

    }
}

你可能感兴趣的:(java,开发语言,设计模式,抽象工厂模式)