找回密码
 立即注册
首页 业界区 安全 生成数据库的表结构文档

生成数据库的表结构文档

烯八 2025-7-30 15:47:41
背景说明
项目完成前后,需要提供各种各样的文档,我所在的公司,每次项目结束要整理的文档高达29个,其中有些文档很单一但是数据量很大,这个时候就必须偷懒一下了。
使用依赖
  1. <groupId>cn.smallbun.screw</groupId>
  2. screw-core</artifactId>
  3. <version>1.0.5</version>
复制代码
依赖说明
在企业级开发中、我们经常会有编写数据库表结构文档的时间付出,从业以来,待过几家企业,关于数据库表结构文档状态:要么没有、要么有、但都是手写、后期运维开发,需要手动进行维护到文档中,很是繁琐、如果忘记一次维护、就会给以后工作造成很多困扰、无形中制造了很多坑留给自己和后人,于是萌生了要自己写一个插件工具的想法,但由于自己前期在程序设计上没有很多造诣,且能力偏低,有想法并不能很好实现,随着工作阅历的增加,和知识的不断储备,终于在2020年的3月中旬开始进行编写,4月上旬完成初版,想完善差不多在开源,但由于工作太忙,业余时间不足,没有在进行完善,到了6月份由于工作原因、频繁设计和更改数据库、经常使用自己写的此插件、节省了很多时间,解决了很多问题 ,在仅有且不多的业余时间中、进行开源准备,于2020年6月22日,开源,欢迎大家使用、建议、并贡献。
  关于名字,想一个太难了,好在我这个聪明的小脑瓜灵感一现,怎么突出它的小,但重要呢?从小就学过雷锋的螺丝钉精神,摘自雷锋日记:虽然是细小的螺丝钉,是个细微的小齿轮,然而如果缺了它,那整个的机器就无法运转了,慢说是缺了它,即使是一枚小螺丝钉没拧紧,一个小齿轮略有破损,也要使机器的运转发生故障的...,感觉自己写的这个工具,很有这意味,虽然很小、但是开发中缺了它还不行,于是便起名为screw(螺丝钉)。
maven依赖配置
  1.     <dependency>
  2.             <groupId>cn.smallbun.screw</groupId>
  3.             screw-core</artifactId>
  4.             <version>1.0.5</version>
  5.             <exclusions>
  6.                 <exclusion>
  7.                     <groupId>org.freemarker</groupId>
  8.                     freemarker</artifactId>
  9.                 </exclusion>
  10.                 <exclusion>
  11.                     <groupId>com.alibaba</groupId>
  12.                     fastjson</artifactId>
  13.                 </exclusion>
  14.             </exclusions>
  15.         </dependency>
  16.         <dependency>
  17.             <groupId>org.apache.velocity</groupId>
  18.             velocity-engine-core</artifactId>
  19.             <version>2.3</version>
  20.         </dependency>
复制代码
主代码部分
  1. package com.heit.road.web.config;
  2. import cn.hutool.core.io.FileUtil;
  3. import cn.hutool.core.util.IdUtil;
  4. import cn.smallbun.screw.core.Configuration;
  5. import cn.smallbun.screw.core.engine.EngineConfig;
  6. import cn.smallbun.screw.core.engine.EngineFileType;
  7. import cn.smallbun.screw.core.engine.EngineTemplateType;
  8. import cn.smallbun.screw.core.execute.DocumentationExecute;
  9. import cn.smallbun.screw.core.process.ProcessConfig;
  10. import com.heit.road.service.util.ServletUtils;
  11. import com.zaxxer.hikari.HikariConfig;
  12. import com.zaxxer.hikari.HikariDataSource;
  13. import io.swagger.v3.oas.annotations.Operation;
  14. import io.swagger.v3.oas.annotations.Parameter;
  15. import io.swagger.v3.oas.annotations.tags.Tag;
  16. import org.springframework.web.bind.annotation.GetMapping;
  17. import org.springframework.web.bind.annotation.RequestMapping;
  18. import org.springframework.web.bind.annotation.RequestParam;
  19. import org.springframework.web.bind.annotation.RestController;
  20. import javax.annotation.Resource;
  21. import javax.servlet.http.HttpServletResponse;
  22. import javax.sql.DataSource;
  23. import java.io.File;
  24. import java.io.IOException;
  25. import java.util.Arrays;
  26. @Tag(name = "管理后台 - 数据库文档")
  27. @RestController
  28. @RequestMapping("/infra/db-doc")
  29. public class DatabaseDocController {
  30.     @Resource
  31.     private DataSource db; //获取项目数据源
  32.     private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator
  33.             + "db-doc";
  34.     private static final String DOC_FILE_NAME = "数据库文档";
  35.     private static final String DOC_VERSION = "1.0.0";
  36.     private static final String DOC_DESCRIPTION = "文档描述";
  37.     @GetMapping("/export-html")
  38.     @Operation(summary = "导出 html 格式的数据文档")
  39.     @Parameter(name = "deleteFile", description = "是否删除在服务器本地生成的数据库文档", example = "true")
  40.     public void exportHtml(@RequestParam(defaultValue = "true") Boolean deleteFile,
  41.                            HttpServletResponse response) throws IOException {
  42.         doExportFile(EngineFileType.HTML, deleteFile, response);
  43.     }
  44.     @GetMapping("/export-word")
  45.     @Operation(summary = "导出 word 格式的数据文档")
  46.     @Parameter(name = "deleteFile", description = "是否删除在服务器本地生成的数据库文档", example = "true")
  47.     public void exportWord(@RequestParam(defaultValue = "true") Boolean deleteFile,
  48.                            HttpServletResponse response) throws IOException {
  49.         doExportFile(EngineFileType.WORD, deleteFile, response);
  50.     }
  51.     @GetMapping("/export-markdown")
  52.     @Operation(summary = "导出 markdown 格式的数据文档")
  53.     @Parameter(name = "deleteFile", description = "是否删除在服务器本地生成的数据库文档", example = "true")
  54.     public void exportMarkdown(@RequestParam(defaultValue = "true") Boolean deleteFile,
  55.                                HttpServletResponse response) throws IOException {
  56.         doExportFile(EngineFileType.MD, deleteFile, response);
  57.     }
  58.     private void doExportFile(EngineFileType fileOutputType, Boolean deleteFile,
  59.                               HttpServletResponse response) throws IOException {
  60.         String docFileName = DOC_FILE_NAME + "_" + IdUtil.fastSimpleUUID();
  61.         String filePath = doExportFile(fileOutputType, docFileName);
  62.         String downloadFileName = DOC_FILE_NAME + fileOutputType.getFileSuffix(); //下载后的文件名
  63.         try {
  64.             // 读取,返回
  65.             ServletUtils.writeAttachment(response, downloadFileName, FileUtil.readBytes(filePath));
  66.         } finally {
  67.             handleDeleteFile(deleteFile, filePath);
  68.         }
  69.     }
  70.     /**
  71.      * 输出文件,返回文件路径
  72.      *
  73.      * @param fileOutputType 文件类型
  74.      * @param fileName       文件名, 无需 ".docx" 等文件后缀
  75.      * @return 生成的文件所在路径
  76.      */
  77.     private String doExportFile(EngineFileType fileOutputType, String fileName) {
  78.         try (HikariDataSource dataSource = buildDataSource()) {
  79.             // 创建 screw 的配置
  80.             Configuration config = Configuration.builder()
  81.                     .version(DOC_VERSION)  // 版本
  82.                     .description(DOC_DESCRIPTION) // 描述
  83.                     .dataSource(dataSource) // 数据源
  84.                     .engineConfig(buildEngineConfig(fileOutputType, fileName)) // 引擎配置
  85.                     .produceConfig(buildProcessConfig()) // 处理配置
  86.                     .build();
  87.             // 执行 screw,生成数据库文档
  88.             new DocumentationExecute(config).execute();
  89.             return FILE_OUTPUT_DIR + File.separator + fileName + fileOutputType.getFileSuffix();
  90.         }
  91.     }
  92.     private void handleDeleteFile(Boolean deleteFile, String filePath) {
  93.         if (!deleteFile) {
  94.             return;
  95.         }
  96.         FileUtil.del(filePath);
  97.     }
  98.     /**
  99.      * 创建数据源
  100.      */
  101.     private HikariDataSource buildDataSource() {
  102.         HikariConfig hikariConfig = new HikariConfig();
  103.         hikariConfig.setJdbcUrl(((HikariDataSource) db).getJdbcUrl());
  104.         hikariConfig.setUsername(((HikariDataSource) db).getUsername());
  105.         hikariConfig.setPassword(((HikariDataSource) db).getPassword());
  106.         hikariConfig.addDataSourceProperty("useInformationSchema", "true"); // 设置可以获取 tables remarks 信息
  107.         // 创建数据源
  108.         return new HikariDataSource(hikariConfig);
  109.     }
  110.     /**
  111.      * 创建 screw 的引擎配置
  112.      */
  113.     private static EngineConfig buildEngineConfig(EngineFileType fileOutputType, String docFileName) {
  114.         return EngineConfig.builder()
  115.                 .fileOutputDir(FILE_OUTPUT_DIR) // 生成文件路径
  116.                 .openOutputDir(false) // 打开目录
  117.                 .fileType(fileOutputType) // 文件类型
  118.                 .produceType(EngineTemplateType.velocity) // 文件类型
  119.                 .fileName(docFileName) // 自定义文件名称
  120.                 .build();
  121.     }
  122.     /**
  123.      * 创建 screw 的处理配置,一般可忽略
  124.      * 指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置
  125.      */
  126.     private static ProcessConfig buildProcessConfig() {
  127.         return ProcessConfig.builder()
  128.                 .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_")) // 忽略表前缀
  129.                 .build();
  130.     }
  131. }
复制代码
 
工具类
  1. package com.heit.road.service.util;
  2. import cn.hutool.core.io.IoUtil;
  3. import cn.hutool.core.util.StrUtil;
  4. import cn.hutool.extra.servlet.ServletUtil;
  5. import org.springframework.http.MediaType;
  6. import org.springframework.web.context.request.RequestAttributes;
  7. import org.springframework.web.context.request.RequestContextHolder;
  8. import org.springframework.web.context.request.ServletRequestAttributes;
  9. import javax.servlet.ServletRequest;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;
  12. import java.io.IOException;
  13. import java.net.URLEncoder;
  14. /**
  15. * 客户端工具类
  16. *
  17. */
  18. public class ServletUtils {
  19.     /**
  20.      * 返回 JSON 字符串
  21.      *
  22.      * @param response 响应
  23.      * @param object 对象,会序列化成 JSON 字符串
  24.      */
  25.     @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码
  26.     public static void writeJSON(HttpServletResponse response, Object object) {
  27.         String content = JsonUtils.toJsonString(object);
  28.         ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
  29.     }
  30.     /**
  31.      * 返回附件
  32.      *
  33.      * @param response 响应
  34.      * @param filename 文件名
  35.      * @param content 附件内容
  36.      * @throws IOException
  37.      */
  38.     public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
  39.         // 设置 header 和 contentType
  40.         response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
  41.         response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
  42.         // 输出附件
  43.         IoUtil.write(response.getOutputStream(), false, content);
  44.     }
  45.     /**
  46.      * @param request 请求
  47.      * @return ua
  48.      */
  49.     public static String getUserAgent(HttpServletRequest request) {
  50.         String ua = request.getHeader("User-Agent");
  51.         return ua != null ? ua : "";
  52.     }
  53.     /**
  54.      * 获得请求
  55.      *
  56.      * @return HttpServletRequest
  57.      */
  58.     public static HttpServletRequest getRequest() {
  59.         RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
  60.         if (!(requestAttributes instanceof ServletRequestAttributes)) {
  61.             return null;
  62.         }
  63.         return ((ServletRequestAttributes) requestAttributes).getRequest();
  64.     }
  65.     public static String getUserAgent() {
  66.         HttpServletRequest request = getRequest();
  67.         if (request == null) {
  68.             return null;
  69.         }
  70.         return getUserAgent(request);
  71.     }
  72.     public static String getClientIP() {
  73.         HttpServletRequest request = getRequest();
  74.         if (request == null) {
  75.             return null;
  76.         }
  77.         return ServletUtil.getClientIP(request);
  78.     }
  79.     public static boolean isJsonRequest(ServletRequest request) {
  80.         return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
  81.     }
  82. }
复制代码
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册