淘先锋技术网

首页 1 2 3 4 5 6 7

核心依赖

        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generator -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        
        
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.15</version>
        </dependency>  
        
        
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-scratchpad -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>5.2.3</version>
        </dependency>              

核心代码

EnhanceImgUtil.java

@Slf4j
public class EnhanceImgUtil extends ImgUtil {


    /**
     * 生成纯色图片
     *
     * @param width  图片宽
     * @param height 图片高
     * @param color  颜色  空则Color.BLACK
     * @return
     */
    public static BufferedImage createPureColorImage(int width, int height, Color color) {
        // width 生成图宽度
        // height 生成图高度
        // 创建一个width xheight ,RGB高彩图,类型可自定
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 取得图形
        Graphics g = img.getGraphics();
        // 设置颜色
        g.setColor(ObjectUtil.defaultIfNull(color, Color.white));
        // 填充
        g.fillRect(0, 0, img.getWidth(), img.getHeight());
        // 在d盘创建个文件
        return img;
    }
    
    
    /**
     * 生成文本图片
     *
     * @param content 文本
     * @param width   图片宽
     * @param height  图片高
     * @return
     */
    public static BufferedImage createContentImage(String content, int width, int height) {
        return createContentImage(content, width, height, Color.WHITE, Color.BLACK);
    }


    /**
     * 生成基于content内容的图片
     *
     * @param content   图片内容
     * @param width     图片宽
     * @param height    图片高
     * @param bgColor   图片背景色 空则白色
     * @param fontColor 文字颜色色 空则黑色
     * @return
     */
    public static BufferedImage createContentImage(String content, int width, int height, Color bgColor, Color fontColor) {
        return createContentImage(content, width, height, ObjectUtil.defaultIfNull(bgColor, Color.WHITE), ObjectUtil.defaultIfNull(fontColor, Color.BLACK), false);
    }


    /**
     * 生成基于content内容的图片
     *
     * @param content   图片内容
     * @param width     图片宽
     * @param height    图片高
     * @param bgColor   图片背景色 空则白色
     * @param fontColor 文字颜色色 空则黑色
     * @return
     */
    public static BufferedImage createContentImage(Font font, String content, int width, int height, Color bgColor, Color fontColor) {
        return createContentImage(font, content, width, height, ObjectUtil.defaultIfNull(bgColor, Color.WHITE), ObjectUtil.defaultIfNull(fontColor, Color.BLACK), false);
    }


    /**
     * 生成基于content内容的图片
     *
     * @param content                   图片内容
     * @param width                     图片宽
     * @param height                    图片高
     * @param backgroundTransparentFlag 背景是否透明
     * @return
     */
    public static Image createContentImage(String content, int width, int height, boolean backgroundTransparentFlag) {
        return createContentImage(content, width, height, Color.WHITE, Color.BLACK, backgroundTransparentFlag);
    }

    /**
     * 生成基于content内容的图片
     *
     * @param content                   图片内容
     * @param width                     图片宽
     * @param height                    图片高
     * @param bgColor                   图片背景色 空则白色
     * @param fontColor                 文字颜色色 空则黑色
     * @param backgroundTransparentFlag 背景是否需要透明 true透明且bgColor不生效
     * @return
     */
    public static BufferedImage createContentImage(String content, int width, int height, Color bgColor, Color fontColor, boolean backgroundTransparentFlag) {
        return createContentImage(null, content, width, height, Color.WHITE, Color.BLACK, backgroundTransparentFlag);
    }

    public static BufferedImage createContentImage(Font font, String content, int width, int height, Color bgColor, Color fontColor, boolean backgroundTransparentFlag) {
        return createContentImage(font, content, width, height, bgColor, fontColor, backgroundTransparentFlag,true);
    }

    /**
     * 生成基于content内容的图片
     *
     * @param font                      图片内容字体样式
     * @param content                   图片内容
     * @param width                     图片宽
     * @param height                    图片高
     * @param bgColor                   图片背景色 空则白色
     * @param fontColor                 文字颜色色 空则黑色
     * @param backgroundTransparentFlag 背景是否需要透明 true透明且bgColor不生效
     * @param fontCenterFlag            文字是否需要水平居中 true水平居中 false左对齐
     * @return
     */
    public static BufferedImage createContentImage(Font font, String content, int width, int height, Color bgColor, Color fontColor, boolean backgroundTransparentFlag, boolean fontCenterFlag) {
        // 图片设置:宽、高、背景透明
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 获取Image对象
        Graphics2D g2d = image.createGraphics();

        // 填充白色背景图
        g2d.setColor(ObjectUtil.defaultIfNull(bgColor, Color.WHITE));
        g2d.fillRect(0, 0, width, height);

        // 背景透明
        if (backgroundTransparentFlag) {
            image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        }


        // g2d.dispose();
        g2d = image.createGraphics();
        // 设置字体颜色和透明度
        g2d.setColor(ObjectUtil.defaultIfNull(fontColor, Color.BLACK));
        // g2d.setStroke(new BasicStroke(1));
        // 设置字体
        font = ObjectUtil.defaultIfNull(font, new Font("微软雅黑", Font.BOLD, 25));
        g2d.setFont(font);

        FontRenderContext context = g2d.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(content, context);


        double x = 16.0;
        // 文字水平居中显示
        if (fontCenterFlag) {
            x = (width - bounds.getWidth()) / 2;
        }
        // 文字垂直居中显示
        double y = (height - bounds.getHeight()) / 2;
        double ascent = -bounds.getY();
        double baseY = y + ascent;
        g2d.drawString(content, Convert.toInt(x), Convert.toInt(baseY));

        // 设置透明度
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        // 释放对象
        g2d.dispose();
        return image;
    }


    /**
     * 生成多行文字的图片
     *
     * @param font                      图片内容字体样式
     * @param contents                  图片内容-每个元素代表一行内容
     * @param width                     图片宽
     * @param height                    图片高
     * @param bgColor                   图片背景色 空则白色
     * @param fontColor                 文字颜色色 空则黑色
     * @param backgroundTransparentFlag 背景是否需要透明 true透明且bgColor不生效
     * @return
     */
    public static BufferedImage createContentsImage(Font font, List<String> contents, int width, int height, Color bgColor, Color fontColor, boolean backgroundTransparentFlag, boolean fontCenterFlag) {
        BufferedImage[] bufferedImages = CollUtil.emptyIfNull(contents)
                .stream()
                .map(content -> createContentImage(font, content, width, height, bgColor, fontColor, backgroundTransparentFlag,fontCenterFlag))
                .toArray(BufferedImage[]::new);
        return mergeImage(bufferedImages);
    }

    public static BufferedImage createContentsImage(Font font, List<String> contents, int width, int height, Color bgColor, Color fontColor, boolean fontCenterFlag) {
        return createContentsImage(font, contents, width, height, bgColor, fontColor, false,fontCenterFlag);
    }

    public static BufferedImage createContentsImage(Font font, List<String> contents, int width, int height, Color bgColor, Color fontColor) {
        return createContentsImage(font, contents, width, height, bgColor, fontColor, true);
    }

    public static BufferedImage createContentsImage(Font font, List<String> contents, int width, int height, Color bgColor, boolean fontCenterFlag) {
        return createContentsImage(font, contents, width, height, bgColor, Color.BLACK,fontCenterFlag);
    }

    public static BufferedImage createContentsImage(Font font, List<String> contents, int width, int height, Color bgColor) {
        return createContentsImage(font, contents, width, height, bgColor, Color.BLACK);
    }


    /**
     * 垂直合并图片
     * 代码复制粘贴自{https://www.cnblogs.com/chbyiming-bky/articles/8940105.html}
     *
     * @param imgs 图片
     */
    public static BufferedImage mergeImage(BufferedImage... imgs) {
        if (imgs == null) {
            return null;
        }
        imgs = ArrayUtil.removeNull(imgs);
        if (ArrayUtil.isNotEmpty(imgs)) {
            return mergeImage(false, imgs);
        }
        return null;
    }

    /**
     * 合并任数量的图片成一张图片
     * 代码复制粘贴自{https://www.cnblogs.com/chbyiming-bky/articles/8940105.html}
     *
     * @param isHorizontal true代表水平合并,fasle代表垂直合并
     * @param imgs         待合并的图片数组
     */
    public static BufferedImage mergeImage(boolean isHorizontal, BufferedImage... imgs) {

        List<BufferedImage> bufferedImageList = Arrays.asList(imgs).stream()
                .filter(ObjectUtil::isNotNull)
                .collect(Collectors.toList());
        imgs = Convert.convert(BufferedImage[].class, bufferedImageList, new BufferedImage[0]);

        // 生成新图片
        BufferedImage destImage = null;
        // 计算新图片的长和高
        int allw = 0, allh = 0, allwMax = 0, allhMax = 0;
        // 获取总长、总宽、最长、最宽
        for (int i = 0; i < imgs.length; i++) {
            BufferedImage img = imgs[i];
            if (img == null) {
                continue;
            }
            allw += img.getWidth();
            allh += img.getHeight();
            if (img.getWidth() > allwMax) {
                allwMax = img.getWidth();
            }
            if (img.getHeight() > allhMax) {
                allhMax = img.getHeight();
            }
        }
        // 创建新图片
        if (isHorizontal) {
            destImage = new BufferedImage(allw, allhMax, BufferedImage.TYPE_INT_RGB);
        } else {
            destImage = new BufferedImage(allwMax, allh, BufferedImage.TYPE_INT_RGB);
        }
        // 合并所有子图片到新图片
        int wx = 0, wy = 0;
        for (int i = 0; i < imgs.length; i++) {
            BufferedImage img = imgs[i];
            int w1 = img.getWidth();
            int h1 = img.getHeight();
            // 从图片中读取RGB
            int[] ImageArrayOne = new int[w1 * h1];
            ImageArrayOne = img.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行扫描图像中各个像素的RGB到数组中
            if (isHorizontal) { // 水平方向合并
                destImage.setRGB(wx, 0, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
            } else { // 垂直方向合并
                destImage.setRGB(0, wy, w1, h1, ImageArrayOne, 0, w1); // 设置上半部分或左半部分的RGB
            }
            wx += w1;
            wy += h1;
        }
        return destImage;
    }
}    


DbQO.java

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "数据库查询类")
public class DbQO {

    private final String urlTemplate = "jdbc:{dbType}://{ip}:{port}/{databaseName}";

    @ApiModelProperty(value = "数据库类型(dbType)")
    String dbType;

    @ApiModelProperty(value = "数据库IP地址(ip)")
    String ip;

    @ApiModelProperty(value = "数据库端口号(port)")
    String port;

    @ApiModelProperty(value = "数据库库名(databaseName)")
    String databaseName;

    @ApiModelProperty(value = "其他参数(otherParams) == 比如时区、编码等配置")
    Map<String, String> otherParams;

    @ApiModelProperty(value = "数据库url(url) == 参考jdbc:{dbType}://{ip}:{port}/{databaseName}")
    String url;

    @ApiModelProperty(value = "数据库账号(userName)",required = true)
    @NotBlank(message = "数据库账号缺失")
    String userName;

    @ApiModelProperty(value = "数据库密码(password)",required = true)
    @NotBlank(message = "数据库密码缺失")
    String password;

    @ApiModelProperty(value = "需匹配的表名,多个则逗号分隔(includeTableName) = 某些接口支持正则匹配")
    String includeTableName;

    @ApiModelProperty(value = "被排除的表名,多个则逗号分隔(excludeTableName) = 某些接口支持正则匹配")
    String excludeTableName;

    @ApiModelProperty(value = "待执行的SQL语句(sql)")
    String sql;

    @ApiModelProperty(value = "解析-SQL执行计划(explainSqlFlag)")
    Boolean explainSqlFlag;


    @ApiModelProperty(value = "自动在查询语句上添加分页参数(autoAddPageSQLParams)")
    boolean autoAddPageSQLParamsFlag = true;

    @ApiModelProperty(value = "页码(pageNo) = 从1开始")
    Integer pageNo;

    @ApiModelProperty(value = "页记录数(pageSize)")
    Integer pageSize;

    /**
     * 获取数据库链接
     * 如果{@link DbQO#url}有值则取这个,否则通过{@link DbQO#dbType, DbQO#ip}等进行构建
     *
     * @return
     */
    public String blankToBuildUrl() {
        String result = url;
        if (StrUtil.isBlank(result)) {
            result = StrUtil.format(urlTemplate, BeanUtil.beanToMap(this), true);
            if (CollUtil.isNotEmpty(otherParams)) {
                String otherParamsStr = URLUtil.buildQuery(otherParams, CharsetUtil.CHARSET_UTF_8);
                result = StrUtil.format("{}?{}", result, otherParamsStr);
            }
        }
        return result;
    }

}

    private static DataSource getDataSource(DbQO dbQO) {
        return new DriverManagerDataSource(dbQO.blankToBuildUrl(), dbQO.getUserName(), dbQO.getPassword());
    }

    /**
     * 获取数据库的某表的元信息
     *
     * @param dbQO 数据库信息
     * @return
     */
    public static List<TableInfo> getTablesMeta(DbQO dbQO) {

        // 1. 数据库连接
        DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(getDataSource(dbQO))
                .build();

        // 2. 查找策略
        String inclueTableName = dbQO.getIncludeTableName();
        String excludeTableName = dbQO.getExcludeTableName();
        StrategyConfig.Builder strategyConfigBuilder = new StrategyConfig.Builder();
        if (StrUtil.isNotBlank(inclueTableName)) {
            strategyConfigBuilder.addInclude(StrUtil.split(inclueTableName, StrUtil.COMMA));
        }
        if (StrUtil.isNotBlank(excludeTableName)) {
            strategyConfigBuilder.addExclude(StrUtil.split(excludeTableName, StrUtil.COMMA));
        }


        ConfigBuilder configBuilder = new ConfigBuilder(null, dataSourceConfig, strategyConfigBuilder.build(), null, null, null);
        DefaultQuery defaultQuery = new DefaultQuery(configBuilder);

        return defaultQuery.queryTables();
    }



    private static BufferedImage createTableStructureImage(TableInfo tableInfo) {


        String tableComment = tableInfo.getComment();
        String tableName = tableInfo.getName();
        String tableDesc = StrUtil.isNotBlank(tableComment) ? StrUtil.format("{}({})", tableName, tableComment) : tableName;


        List<TableField> tableFields = tableInfo.getFields();
        Integer maxLengthTableFieldNameDesc = tableFields.stream()
                .map(tableField -> {
                    String tableFieldName = tableField.getName();
                    String tableFieldComment = tableField.getComment();
                    String tableFieldNameDesc = StrUtil.isNotBlank(tableFieldComment) ? StrUtil.format("{}({})", tableFieldName, tableFieldComment) : tableFieldName;
                    return tableFieldNameDesc;
                })
                .map(StrUtil::length)
                .map(length -> length + 4)
                .max(Integer::compareTo)
                .orElse(0);

        Integer maxLengthTableFieldTypeDesc = tableFields.stream()
                .map(tableField -> {
                    String jdbcType = Convert.toStr(tableField.getMetaInfo().getJdbcType());
                    int typeLength = tableField.getMetaInfo().getLength();
                    String tableFieldTypeDesc = typeLength > 0 ? StrUtil.format("{}({})", jdbcType, typeLength) : jdbcType;
                    return tableFieldTypeDesc;
                })
                .map(StrUtil::length)
                .max(Integer::compareTo)
                .orElse(0);


        List<String> tableFieldDescList = tableFields.stream()
                .map(tableField -> {
                    String tableFieldName = tableField.getName();
                    String tableFieldComment = tableField.getComment();
                    String tableFieldNameDesc = StrUtil.isNotBlank(tableFieldComment) ? StrUtil.format("{}({})", tableFieldName, tableFieldComment) : tableFieldName;
                    tableFieldNameDesc = StrUtil.padAfter(tableFieldNameDesc, maxLengthTableFieldNameDesc, StrUtil.SPACE);
                    // EnhanceImgUtil.createContentImage(font, "文章", imageWidth, rowHeight, new Color(0xD9EAFD), Color.BLACK);

                    String jdbcType = Convert.toStr(tableField.getMetaInfo().getJdbcType());
                    int typeLength = tableField.getMetaInfo().getLength();
                    String tableFieldTypeDesc = typeLength > 0 ? StrUtil.format("{}({})", jdbcType, typeLength) : jdbcType;

                    return StrUtil.format("{}    {}", tableFieldNameDesc, tableFieldTypeDesc);
                })
                .collect(Collectors.toList());

        Integer fontSize = 16;
        Integer maxRowContentLength = ArrayUtil.max(maxLengthTableFieldNameDesc + maxLengthTableFieldTypeDesc, StrUtil.length(tableDesc));
        Integer maxRowContentWidth = maxRowContentLength * fontSize;


        Integer rowHeight = fontSize + 4;
        Integer tableFieldNameDescWidth = maxLengthTableFieldNameDesc * fontSize;
        Integer tableFieldTypeDescWidth = maxRowContentWidth - tableFieldNameDescWidth;


        Font font = new Font(Font.MONOSPACED, Font.BOLD, fontSize);
        BufferedImage[] tableFieldsImages = tableFields.stream()
                .map(tableField -> {
                    String tableFieldName = tableField.getName();
                    String tableFieldComment = tableField.getComment();
                    String tableFieldNameDesc = StrUtil.isNotBlank(tableFieldComment) ? StrUtil.format("{}({})", tableFieldName, tableFieldComment) : tableFieldName;
                    tableFieldNameDesc = StrUtil.padAfter(tableFieldNameDesc, maxLengthTableFieldNameDesc, StrUtil.SPACE);

                    BufferedImage tableFieldNameDescImage = EnhanceImgUtil.createContentImage(font, tableFieldNameDesc, tableFieldNameDescWidth, rowHeight, new Color(0xD9EAFD), Color.BLACK, false, false);

                    String jdbcType = Convert.toStr(tableField.getMetaInfo().getJdbcType());
                    int typeLength = tableField.getMetaInfo().getLength();
                    String tableFieldTypeDesc = typeLength > 0 ? StrUtil.format("{}({})", jdbcType, typeLength) : jdbcType;
                    BufferedImage tableFieldTypeDescImage = EnhanceImgUtil.createContentImage(font, tableFieldTypeDesc, tableFieldTypeDescWidth, rowHeight, new Color(0xD9EAFD), Color.BLACK, false, false);

                    return EnhanceImgUtil.mergeImage(true, tableFieldNameDescImage, tableFieldTypeDescImage);
                })
                .toArray(BufferedImage[]::new);


        Integer borderHeight = 2;


        BufferedImage tableNameImage = EnhanceImgUtil.createContentImage(font, tableDesc, maxRowContentWidth, rowHeight, new Color(0xD9EAFD), Color.BLACK);
        BufferedImage rowBorderbufferedImage = EnhanceImgUtil.createPureColorImage(maxRowContentLength * fontSize, borderHeight, new Color(0x0080C0));
        BufferedImage tableFieldsImage = EnhanceImgUtil.mergeImage(tableFieldsImages);

        // 上中下边框
        BufferedImage result = EnhanceImgUtil.mergeImage(rowBorderbufferedImage, tableNameImage, rowBorderbufferedImage, tableFieldsImage, rowBorderbufferedImage);


        // 左右边框框
        BufferedImage columnBorderbufferedImage = EnhanceImgUtil.createPureColorImage(borderHeight, result.getHeight(), new Color(0x0080C0));
        result = EnhanceImgUtil.mergeImage(true, columnBorderbufferedImage, result, columnBorderbufferedImage);

        return result;
    }

测试代码

    @Test
    @SneakyThrows
    public void test58() {

        DbQO dbQO = new DbQO();
        dbQO.setUrl("jdbc:mysql://localhost:3306/lrc-utils-web?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai\n");
        dbQO.setUserName("root");
        dbQO.setPassword("root");
        List<TableInfo> tablesMetas = getTablesMeta(dbQO);

        FileOutputStream outputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\数据库文档.docx");

        Word07Writer writer = new Word07Writer();

        // 标题
        Font docTitleFont = new Font(Font.SANS_SERIF, Font.BOLD, 25);
        writer.addText(ParagraphAlignment.CENTER, docTitleFont, "数据库设计文档");
        writer.addText(ParagraphAlignment.CENTER, docTitleFont, StrUtil.EMPTY);
        writer.addText(ParagraphAlignment.CENTER, docTitleFont, StrUtil.EMPTY);

        // 表索引
        AtomicInteger tableIndexAtomicInteger = new AtomicInteger();
        tablesMetas.forEach(tableInfo -> {

            String comment = tableInfo.getComment();
            comment = StrUtil.isBlank(comment) ? StrUtil.EMPTY : StrUtil.format("({})", comment);


            // 1. 标题
            Font tableNameTitleFont = new Font(Font.SANS_SERIF, Font.BOLD, 20);
            writer.addText(tableNameTitleFont, StrUtil.format("{}、{}{}", tableIndexAtomicInteger.incrementAndGet(), tableInfo.getName(), comment));
            writer.addText(FontUtil.createFont(), StrUtil.EMPTY);

            // 2. pw表结构图片
            Integer docWidth = 450;
            BufferedImage pwTableStructureImageimage = createTableStructureImage(tableInfo);

            // 缩放图片在Doc中的比例
            int docPwTableStructureImageimageWidth = NumberUtil.min(pwTableStructureImageimage.getWidth(), docWidth);
            double docLengthProportion = NumberUtil.div(docPwTableStructureImageimageWidth, pwTableStructureImageimage.getWidth());
            int docPwTableStructureImageimageHeight = Convert.toInt(NumberUtil.mul(pwTableStructureImageimage.getHeight(), docLengthProportion));

            ByteArrayOutputStream imageOutputStream = new ByteArrayOutputStream();
            ImgUtil.write(pwTableStructureImageimage, "png", imageOutputStream);
            ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(imageOutputStream);
            writer.addPicture(byteArrayInputStream, PicType.JPEG, tableInfo.getName(), docPwTableStructureImageimageWidth, docPwTableStructureImageimageHeight);
            writer.addText(FontUtil.createFont(), StrUtil.EMPTY);

            // 3. 表结构表格
            List<TableField> tableFields = tableInfo.getFields();
            // 表的字段索引
            AtomicInteger tableFieldInexAtomicInteger = new AtomicInteger(0);
            List<Map<String, Object>> workTableFields = tableFields.stream()
                    .map(tableField -> {
                        Map<String, Object> wrokTableRow = new LinkedHashtable();
                        wrokTableRow.put("序号", tableFieldInexAtomicInteger.incrementAndGet());
                        wrokTableRow.put("字段名", tableField.getName());
                        wrokTableRow.put("数据类型", tableField.getMetaInfo().getJdbcType());
                        wrokTableRow.put("数据长度", tableField.getMetaInfo().getLength());
                        wrokTableRow.put("主键", tableField.isKeyFlag() ? "是" : "否");
                        wrokTableRow.put("非空", tableField.getMetaInfo().isNullable() ? "是" : "否");
                        wrokTableRow.put("默认值", tableField.getMetaInfo().getDefaultValue());
                        wrokTableRow.put("描述", tableField.getComment());
                        return wrokTableRow;
                    })
                    .collect(Collectors.toList());
            ;

            writer.addTable(workTableFields);


            writer.addText(FontUtil.createFont(), StrUtil.EMPTY);
            writer.addText(FontUtil.createFont(), StrUtil.EMPTY);
        });
        writer.flush(outputStream, false);


    }

生成效果

在这里插入图片描述