Java Code – Generate Database Documentation

Article directory

    • core dependencies
    • core code
    • test code
    • generate effect

Core dependencies

 <!-- 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>

Core code

EnhanceImgUtil.java

@Slf4j
public class EnhanceImgUtil extends ImgUtil {<!-- -->


    /**
     * Generate solid color pictures
     *
     * @param width image width
     * @param height image height
     * @param color Color if empty, Color.BLACK
     * @return
     */
    public static BufferedImage createPureColorImage(int width, int height, Color color) {<!-- -->
        // width generates image width
        // height generates graph height
        // Create a width xheight, RGB high color map, the type can be customized
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // get graphics
        Graphics g = img. getGraphics();
        // set the color
        g.setColor(ObjectUtil.defaultIfNull(color, Color.white));
        // fill
        g. fillRect(0, 0, img. getWidth(), img. getHeight());
        // Create a file on the d drive
        return img;
    }
    
    
    /**
     * Generate text image
     *
     * @param content text
     * @param width image width
     * @param height image height
     * @return
     */
    public static BufferedImage createContentImage(String content, int width, int height) {<!-- -->
        return createContentImage(content, width, height, Color.WHITE, Color.BLACK);
    }


    /**
     * Generate a picture based on the content content
     *
     * @param content image content
     * @param width image width
     * @param height image height
     * @param bgColor image background color, white if empty
     * @param fontColor text color color, empty is black
     * @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);
    }


    /**
     * Generate a picture based on the content content
     *
     * @param content image content
     * @param width image width
     * @param height image height
     * @param bgColor image background color, white if empty
     * @param fontColor text color color, empty is black
     * @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);
    }


    /**
     * Generate a picture based on the content content
     *
     * @param content image content
     * @param width image width
     * @param height image height
     * @param backgroundTransparentFlag Whether the background is transparent
     * @return
     */
    public static Image createContentImage(String content, int width, int height, boolean backgroundTransparentFlag) {<!-- -->
        return createContentImage(content, width, height, Color.WHITE, Color.BLACK, backgroundTransparentFlag);
    }

    /**
     * Generate a picture based on the content content
     *
     * @param content image content
     * @param width image width
     * @param height image height
     * @param bgColor image background color, white if empty
     * @param fontColor text color color, empty is black
     * @param backgroundTransparentFlag Whether the background needs to be transparent true transparent and bgColor does not take effect
     * @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);
    }

    /**
     * Generate a picture based on the content content
     *
     * @param font font style of image content
     * @param content image content
     * @param width image width
     * @param height image height
     * @param bgColor image background color, white if empty
     * @param fontColor text color color, empty is black
     * @param backgroundTransparentFlag Whether the background needs to be transparent true transparent and bgColor does not take effect
     * @param fontCenterFlag Whether the text needs to be horizontally centered true horizontally centered false left-aligned
     * @return
     */
    public static BufferedImage createContentImage(Font font, String content, int width, int height, Color bgColor, Color fontColor, boolean backgroundTransparentFlag, boolean fontCenterFlag) {<!-- -->
        // Image settings: width, height, background transparent
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// Get Image object
        Graphics2D g2d = image. createGraphics();

        // Fill the white background image
        g2d.setColor(ObjectUtil.defaultIfNull(bgColor, Color.WHITE));
        g2d. fillRect(0, 0, width, height);

        // background transparent
        if (backgroundTransparentFlag) {<!-- -->
            image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        }


        // g2d.dispose();
        g2d = image.createGraphics();
        // set font color and transparency
        g2d.setColor(ObjectUtil.defaultIfNull(fontColor, Color.BLACK));
        // g2d.setStroke(new BasicStroke(1));
        // set font
        font = ObjectUtil.defaultIfNull(font, new Font("Microsoft Yahei", Font.BOLD, 25));
        g2d.setFont(font);

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


        double x = 16.0;
        // Center the text horizontally
        if (fontCenterFlag) {<!-- -->
            x = (width - bounds. getWidth()) / 2;
        }
        // display the text vertically
        double y = (height - bounds. getHeight()) / 2;
        double ascent = -bounds. getY();
        double baseY = y + ascent;
        g2d.drawString(content, Convert.toInt(x), Convert.toInt(baseY));

        // set transparency
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        // release the object
        g2d.dispose();
        return image;
    }


    /**
     * Generate images of multiline text
     *
     * @param font font style of image content
     * @param contents image content - each element represents a line of content
     * @param width image width
     * @param height image height
     * @param bgColor image background color, white if empty
     * @param fontColor text color color, empty is black
     * @param backgroundTransparentFlag Whether the background needs to be transparent true transparent and bgColor does not take effect
     * @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);
    }


    /**
     * Merge pictures vertically
     * The code is copied and pasted from {https://www.cnblogs.com/chbyiming-bky/articles/8940105.html}
     *
     * @param imgs image
     */
    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;
    }

    /**
     * Merge any number of pictures into one picture
     * The code is copied and pasted from {https://www.cnblogs.com/chbyiming-bky/articles/8940105.html}
     *
     * @param isHorizontal true means horizontal merge, fasle means vertical merge
     * @param imgs array of images to be merged
     */
    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]);

        // Generate a new image
        BufferedImage destImage = null;
        // Calculate the length and height of the new image
        int allw = 0, allh = 0, allwMax = 0, allhMax = 0;
        // Get total length, total width, longest, widest
        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();
            }
        }
        // Create a new image
        if (isHorizontal) {<!-- -->
            destImage = new BufferedImage(allw, allhMax, BufferedImage.TYPE_INT_RGB);
        } else {<!-- -->
            destImage = new BufferedImage(allwMax, allh, BufferedImage.TYPE_INT_RGB);
        }
        // Merge all subimages into a new image
        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();
            // read RGB from image
            int[] ImageArrayOne = new int[w1 * h1];
            ImageArrayOne = img.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // progressively scan the RGB of each pixel in the image into the array
            if (isHorizontal) {<!-- --> // merge horizontally
                destImage.setRGB(wx, 0, w1, h1, ImageArrayOne, 0, w1); // Set the RGB of the upper or left half
            } else {<!-- --> // Merge vertically
                destImage.setRGB(0, wy, w1, h1, ImageArrayOne, 0, w1); // Set the RGB of the upper or left half
            }
            wx + = w1;
            wy + = h1;
        }
        return destImage;
    }
}

?
DbQO.java

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "Database query class")
public class DbQO {<!-- -->

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

    @ApiModelProperty(value = "Database Type (dbType)")
    String dbType;

    @ApiModelProperty(value = "Database IP address (ip)")
    String ip;

    @ApiModelProperty(value = "Database port number (port)")
    String port;

    @ApiModelProperty(value = "Database Name (databaseName)")
    String databaseName;

    @ApiModelProperty(value = "Other parameters (otherParams) == such as time zone, encoding and other configurations")
    Map<String, String> otherParams;

    @ApiModelProperty(value = "database url(url) == reference jdbc:{dbType}://{ip}:{port}/{databaseName}")
    String url;

    @ApiModelProperty(value = "database account (userName)", required = true)
    @NotBlank(message = "The database account is missing")
    String userName;

    @ApiModelProperty(value = "Database password (password)", required = true)
    @NotBlank(message = "Database password missing")
    String password;

    @ApiModelProperty(value = "Table names to be matched, separated by commas if multiple (includeTableName) = some interfaces support regular matching")
    String includeTableName;

    @ApiModelProperty(value = "Excluded table names, separated by commas if multiple (excludeTableName) = some interfaces support regular matching")
    String excludeTableName;

    @ApiModelProperty(value = "SQL statement to be executed (sql)")
    String sql;

    @ApiModelProperty(value = "Analysis-SQL execution plan (explainSqlFlag)")
    Boolean explainSqlFlag;


    @ApiModelProperty(value = "Automatically add pagination parameters to the query statement (autoAddPageSQLParams)")
    boolean autoAddPageSQLParamsFlag = true;

    @ApiModelProperty(value = "page number (pageNo) = start from 1")
    Integer pageNo;

    @ApiModelProperty(value = "Number of page records (pageSize)")
    Integer pageSize;

    /**
     * Get database link
     * If {@link DbQO#url} has a value, take this, otherwise build through {@link DbQO#dbType, DbQO#ip}, etc.
     *
     * @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());
    }

    /**
     * Get the meta information of a table in the database
     *
     * @param dbQO database information
     * @return
     */
    public static List<TableInfo> getTablesMeta(DbQO dbQO) {<!-- -->

        // 1. Database connection
        DataSourceConfig dataSourceConfig = new DataSourceConfig. Builder(getDataSource(dbQO))
                .build();

        // 2. Find strategy
        String includeTableName = 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, "article", 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);

        // top, middle and bottom borders
        BufferedImage result = EnhanceImgUtil.mergeImage(rowBorderbufferedImage, tableNameImage, rowBorderbufferedImage, tableFieldsImage, rowBorderbufferedImage);


        // left and right borders
        BufferedImage columnBorderbufferedImage = EnhanceImgUtil.createPureColorImage(borderHeight, result.getHeight(), new Color(0x0080C0));
        result = EnhanceImgUtil. mergeImage(true, columnBorderbufferedImage, result, columnBorderbufferedImage);

        return result;
    }

Test Code

 @Test
    @SneakyThrows
    public void test58() {<!-- -->

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

        FileOutputStream outputStream = new FileOutputStream("C:\Users\Administrator\Desktop\Database Documentation.docx");

        Word07Writer writer = new Word07Writer();

        // title
        Font docTitleFont = new Font(Font. SANS_SERIF, Font. BOLD, 25);
        writer.addText(ParagraphAlignment.CENTER, docTitleFont, "Database Design Document");
        writer.addText(ParagraphAlignment.CENTER, docTitleFont, StrUtil.EMPTY);
        writer.addText(ParagraphAlignment.CENTER, docTitleFont, StrUtil.EMPTY);

        // table index
        AtomicInteger tableIndexAtomicInteger = new AtomicInteger();
        tablesMetas.forEach(tableInfo -> {<!-- -->

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


            // 1. Title
            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 table structure picture
            Integer docWidth = 450;
            BufferedImage pwTableStructureImageimage = createTableStructureImage(tableInfo);

            // Scale the proportion of the image in 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. Table structure table
            List<TableField> tableFields = tableInfo. getFields();
            // field index of the table
            AtomicInteger tableFieldInexAtomicInteger = new AtomicInteger(0);
            List<Map<String, Object>> workTableFields = tableFields. stream()
                    .map(tableField -> {<!-- -->
                        Map<String, Object> wrokTableRow = new LinkedHashtable();
                        wrokTableRow.put("Number", tableFieldInexAtomicInteger.incrementAndGet());
                        wrokTableRow.put("field name", tableField.getName());
                        wrokTableRow.put("data type", tableField.getMetaInfo().getJdbcType());
                        wrokTableRow.put("data length", tableField.getMetaInfo().getLength());
                        wrokTableRow.put("Primary key", tableField.isKeyFlag() ? "Yes" : "No");
                        wrokTableRow.put("Not Null", tableField.getMetaInfo().isNullable() ? "Yes" : "No");
                        wrokTableRow.put("default value", tableField.getMetaInfo().getDefaultValue());
                        wrokTableRow.put("description", 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);


    }

Generating effects