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); }