diff --git a/pom.xml b/pom.xml
index e68c5bfe5..e1f890dc1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,6 +55,7 @@
5.5.6
2.2.7
2.2
+ 1.0.5
@@ -234,6 +235,12 @@
${velocity.version}
+
+ cn.smallbun.screw
+ screw-core
+ ${screw.version}
+
+
diff --git a/src/main/java/cn/iocoder/dashboard/modules/infra/controller/dbdoc/InfDbDocController.java b/src/main/java/cn/iocoder/dashboard/modules/infra/controller/dbdoc/InfDbDocController.java
new file mode 100644
index 000000000..114efa266
--- /dev/null
+++ b/src/main/java/cn/iocoder/dashboard/modules/infra/controller/dbdoc/InfDbDocController.java
@@ -0,0 +1,103 @@
+package cn.iocoder.dashboard.modules.infra.controller.dbdoc;
+
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.smallbun.screw.core.Configuration;
+import cn.smallbun.screw.core.engine.EngineConfig;
+import cn.smallbun.screw.core.engine.EngineFileType;
+import cn.smallbun.screw.core.engine.EngineTemplateType;
+import cn.smallbun.screw.core.execute.DocumentationExecute;
+import cn.smallbun.screw.core.process.ProcessConfig;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import io.swagger.annotations.Api;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Collections;
+
+@Api(tags = "数据库文档")
+@RestController
+@RequestMapping("/infra/db-doc")
+public class InfDbDocController {
+
+ @Resource
+ private DataSourceProperties dataSourceProperties;
+
+ private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator
+ + "db-doc";
+ private static final EngineFileType FILE_OUTPUT_TYPE = EngineFileType.HTML; // 可以设置 Word 或者 Markdown 格式
+ private static final String DOC_FILE_NAME = "数据库文档";
+ private static final String DOC_VERSION = "1.0.0";
+ private static final String DOC_DESCRIPTION = "文档描述";
+
+ @Resource
+ private DataSource dataSource;
+
+ @GetMapping("/export-html")
+ public synchronized void exportHtml(HttpServletResponse response) throws FileNotFoundException {
+ // 创建 screw 的配置
+ Configuration config = Configuration.builder()
+ .version(DOC_VERSION) // 版本
+ .description(DOC_DESCRIPTION) // 描述
+ .dataSource(buildDataSource()) // 数据源
+ .engineConfig(buildEngineConfig()) // 引擎配置
+ .produceConfig(buildProcessConfig()) // 处理配置
+ .build();
+
+ // 执行 screw,生成数据库文档
+ new DocumentationExecute(config).execute();
+
+ // 读取,返回
+ ServletUtil.write(response,
+ new FileInputStream(FILE_OUTPUT_DIR + File.separator + DOC_FILE_NAME + FILE_OUTPUT_TYPE.getFileSuffix()),
+ MediaType.TEXT_HTML_VALUE);
+ }
+
+ /**
+ * 创建数据源
+ */
+ private DataSource buildDataSource() {
+ // 创建 HikariConfig 配置类
+ HikariConfig hikariConfig = new HikariConfig();
+// hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
+ hikariConfig.setJdbcUrl(dataSourceProperties.getUrl());
+ hikariConfig.setUsername(dataSourceProperties.getUsername());
+ hikariConfig.setPassword(dataSourceProperties.getPassword());
+ hikariConfig.addDataSourceProperty("useInformationSchema", "true"); // 设置可以获取 tables remarks 信息
+ // 创建数据源
+ return new HikariDataSource(hikariConfig);
+ }
+
+ /**
+ * 创建 screw 的引擎配置
+ */
+ private static EngineConfig buildEngineConfig() {
+ return EngineConfig.builder()
+ .fileOutputDir(FILE_OUTPUT_DIR) // 生成文件路径
+ .openOutputDir(false) // 打开目录
+ .fileType(FILE_OUTPUT_TYPE) // 文件类型
+ .produceType(EngineTemplateType.freemarker) // 文件类型
+ .fileName(DOC_FILE_NAME) // 自定义文件名称
+ .build();
+ }
+
+ /**
+ * 创建 screw 的处理配置,一般可忽略
+ * 指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置
+ */
+ private static ProcessConfig buildProcessConfig() {
+ return ProcessConfig.builder()
+ .ignoreTablePrefix(Collections.singletonList("QRTZ_")) // 忽略表前缀
+ .build();
+ }
+
+}
diff --git a/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java b/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java
index 6ed88ad8d..927c9775a 100644
--- a/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java
+++ b/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java
@@ -4,7 +4,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
-import cn.hutool.extra.template.TemplateUtil;
+import cn.hutool.extra.template.engine.velocity.VelocityEngine;
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.common.pojo.PageParam;
@@ -28,7 +28,10 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
-import java.util.*;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
import static cn.hutool.core.map.MapUtil.getStr;
import static cn.hutool.core.text.CharSequenceUtil.*;
@@ -107,7 +110,7 @@ public class ToolCodegenEngine {
// 初始化 TemplateEngine 属性
TemplateConfig config = new TemplateConfig();
config.setResourceMode(TemplateConfig.ResourceMode.CLASSPATH);
- this.templateEngine = TemplateUtil.createEngine(config);
+ this.templateEngine = new VelocityEngine(config);
}
@PostConstruct