news 2026/9/9 3:40:03

使用screw-core一键生成数据库表结构文档

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用screw-core一键生成数据库表结构文档

1. 先从“为什么需要表结构文档”说起

我相信绝大多数后端开发都有过这样的经历:接手一个老项目,数据库里几百张表,没有文档,只能一张张点开表看字段注释。运气好点的,表注释和字段注释写得还算完整;运气差的,字段名是abc,类型是varchar(255),你只能靠猜。更别提那些分布在多个库、多个模块里的表,想梳理出一份完整的结构说明,基本等于手工考古。

那时候我用的办法很原始:用 Navicat 把每张表的建表语句导出来,再手动整理到 Word 或者 Markdown 里。表少还行,表一多,维护成本直线上升。而且只要数据库结构一改,文档就得跟着改,改漏一次,后面的人就得多踩一次坑。后来我陆续试过用mysqldump导结构、写 SQL 查询information_schema拼文档、用 Swagger 那套注解自动生成接口文档但让后端兼职维护表注释……都各有各的麻烦。

直到我遇到了 screw-core。这个工具解决的最大痛点就是:它把“数据库表结构”直接变成一份可读、可检索、可分享的文档,全程不需要手动敲一个字。它是一个开源的数据库文档生成工具,基于 Java 生态,支持 MySQL、PostgreSQL、Oracle、SQL Server、SQLite、MariaDB、达梦等主流数据库,能把表结构一键导出为 HTML、Word、Markdown 等格式。

如果你是后端开发、DBA、或者做课程设计、毕业设计的学生,经常需要交付一份数据库设计说明文档,那这个工具值得花一下午时间上手。这篇文章我直接用最简单的方式,从一个空项目开始,跑通一次完整的 screw-core 生成流程,顺便把我在实操中踩过的坑和总结的经验都写出来,希望能帮你省掉摸索的时间。

2. 核心思路与方案选型

2.1 为什么选 screw-core,而不是手工写或自研脚本

先交代一下背景。在我第一次考虑自动化生成表结构文档的时候,其实有几个候选方案,我简单对比一下,你就知道 screw-core 的定位在哪里了。

第一种方案是写 SQL 脚本,自己去查information_schema.tablesinformation_schema.columns,然后把结果导出成 CSV 或 Excel。这个方案灵活,但只适合“一次性”导出,因为你需要对付每个数据库系统的元数据表结构差异,MySQL、PostgreSQL、Oracle 的information_schema字段都不一样,脚本很难做到通用。

第二种方案是用数据库客户端自带的导出功能。Navicat 可以导出表结构,但一般导出的是 SQL 建表脚本,不是人读的说明文档,而且格式固定,无法定制。

第三种方案是像 Swagger 那样手动添加注解。这是最重的方式,相当于每个实体类、每个字段都要写注释和文档标记,工作量巨大,而且容易和数据库实际结构脱节。

screw-core 的本质思路完全不同,它直接从数据库里读元数据(表名、表注释、字段名、字段注释、字段类型、是否主键、是否允许为空、默认值、索引信息等),再通过模板引擎渲染成多种格式的文档。这意味着:

  • 零人工维护:只要数据库注释写得好,生成出来的文档质量就高。
  • 全库覆盖:不用考虑漏表、漏字段的问题,有多少张表就生成多少张。
  • 一次配置,多处使用:支持 Maven 插件、Java 代码调用、命令行等多种方式,可以接入 CI/CD,每次发布前自动生成最新文档。

所以我的结论是:如果你需要的是“数据库表结构的最终说明文档”,screw-core 几乎是当前开源生态里最省事的方案,没有之一。

2.2 核心工作流与前置要求

screw-core 的工作流程不复杂,核心就四步:配置数据源、加载数据库驱动、读取元数据、渲染输出。

但要想让生成的文档真正好用,我建议你先满足三个前置条件,否则后面生成的文档质量会打折扣:

第一,表和字段的注释必须写清楚。screw-core 生成文档时,表名旁边会显示表注释,字段名旁边会显示字段注释。如果注释缺失,整份文档的可读性会大幅下降。很多老项目的表没有注释,这种情况我建议先补一轮注释再生成文档,因为工具只是把数据库里的信息“搬运”到文档里,源头信息不全,文档自然好看不了。

第二,确认驱动版本和数据库版本匹配。这是新手最常遇到的坑。MySQL 5.x 和 MySQL 8.x 的驱动类名、连接 URL 都有差异,比如 MySQL 8 以上的驱动类名是com.mysql.cj.jdbc.Driver,URL 里还要带上useSSL=falseserverTimezone=Asia/Shanghai这类参数,否则很容易报时区错误或者 SSL 连接异常。后面我会单独列一个避坑清单。

第三,确定文档输出格式和存放目录。screw-core 支持HTMLWordMarkdown三种主流格式,你可以一次生成全部格式,也可以只生成其中一种。建议第一次先输出到一个临时目录,确认内容没问题后再调整目录和覆盖范围。

2.3 直接看效果:一份文档大概长什么样

在开始写代码之前,你先有个心理预期:screw-core 生成的 HTML 文档包含一个目录页,左侧是表名列表,右侧是表的详细字段信息,每张表包含表名、表注释、字段名、字段注释、字段类型、是否主键、是否为空、默认值、索引等完整信息。Word 文档和 Markdown 文档的结构类似。

这其实就是我们在课程设计、项目验收、团队交接时最喜欢的那类文档——结构完整、信息准确、不用自己排版。我记得我第一次用这工具给我负责的一个老模块生成文档,那个模块有 30 多张表,手工整理至少要半天,用工具生成只花了几分钟,那一刻真的有一种“为什么没早点用”的感慨。

3. 从零到一:快速跑通 screw-core

3.1 环境准备

这部分假设你手头有一个可以正常连接、里面有数据的数据库。我用的是 MySQL 8.0,Java 版本是 JDK 8+,构建工具用 Maven。screw-core 官方支持 JDK 8,所以如果你的项目还在用老 JDK 也没有问题。

你需要准备的环境清单:

组件版本建议说明
JDK8+screw-core 最低要求 JDK 8
Maven3.6+用于引入依赖和执行插件
MySQL5.7 / 8.0其他数据库也可,驱动需额外引入
screw-core最新版(如 1.0.5)Maven 中央仓库可直接拉取
MySQL JDBC 驱动8.0.x与 MySQL 数据库版本匹配

我这边建议先用 Maven 创建一个最简单的 Java 项目,不需要 Spring Boot 全家桶,直接一个带main方法的普通 Maven 项目就够了。screw-core 本身不依赖 Spring,用纯 Java 代码就能跑起来,这样更容易理解它每一步在干什么。

3.2 Maven 依赖引入

pom.xml里加入以下依赖:

<dependencies> <!-- screw-core 核心依赖 --> <dependency> <groupId>cn.smallbun.screw</groupId> <artifactId>screw-core</artifactId> <version>1.0.5</version> </dependency> <!-- MySQL 驱动,按你实际数据库选择 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> </dependencies>

注意:screw-core 1.0.5 是截至我写这篇文章时比较稳定的版本,你可以在 Maven 中央仓库确认最新版本。如果你的项目已经用了 Spring Boot,需要注意依赖冲突,尤其是 commons-lang3 这类常用库的版本。

3.3 最简单的现场生成代码

下面是核心代码。我把每个配置项的作用都写在注释里,方便你对着看。

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 javax.sql.DataSource; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ScrewDemo { public static void main(String[] args) { // 1. 配置数据源 DataSource dataSource = buildDataSource(); // 2. 生成配置 EngineConfig engineConfig = EngineConfig.builder() // 生成文件的存放路径 .fileOutputDir("D:/temp/screw") // 是否打开输出目录 .openOutputDir(false) // 生成的文件类型,支持 HTML、WORD、MD .fileType(EngineFileType.HTML) // 生成模板,这里使用 freemarker .produceType(EngineTemplateType.freemarker) // 自定义生成的文件名 .fileName("数据库表结构文档") .build(); // 3. 指定需要忽略的表,按需配置 List<String> ignoreTableName = Arrays.asList("flyway_schema_history"); List<String> ignorePrefix = new ArrayList<>(); List<String> ignoreSuffix = new ArrayList<>(); ProcessConfig processConfig = ProcessConfig.builder() // 忽略指定的表名 .ignoreTableName(ignoreTableName) // 忽略表前缀,比如忽略所有以 t_ 开头的表 .ignoreTablePrefix(ignorePrefix) // 忽略表后缀 .ignoreTableSuffix(ignoreSuffix) .build(); // 4. 组装配置 Configuration config = Configuration.builder() // 版本号,会显示在生成的文档标题里 .version("1.0.0") // 描述信息 .description("订单系统数据库设计文档") // 数据源 .dataSource(dataSource) // 引擎配置 .engineConfig(engineConfig) // 处理配置,可忽略表 .produceConfig(processConfig) .build(); // 5. 执行生成 new DocumentationExecute(config).execute(); System.out.println("数据库表结构文档生成完成!"); } /** * 构建数据源,这里直接使用 HikariCP,screw-core 内部已经集成了 HikariCP */ private static DataSource buildDataSource() { // screw-core 提供了一个简单的数据源构建工具类,也可以直接使用 HikariConfig cn.smallbun.screw.core.util.HikariConfig hikariConfig = new cn.smallbun.screw.core.util.HikariConfig(); hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver"); hikariConfig.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/your_database?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai"); hikariConfig.setUsername("root"); hikariConfig.setPassword("your_password"); hikariConfig.setMaximumPoolSize(10); return new cn.smallbun.screw.core.util.HikariDataSource(hikariConfig); } }

这里有一个小知识点:screw-core 内部其实已经集成了 HikariCP 连接池,所以我们可以直接用它的HikariDataSource来构造数据源,不需要再引入额外的依赖。如果你想用自己的数据源,比如 Druid,也可以,只要实现javax.sql.DataSource接口就行。

3.4 执行与输出结果

直接运行main方法,控制台会输出类似下面的日志:

[main] INFO cn.smallbun.screw.core.execute.DocumentationExecute - 开始生成数据库设计文档 [main] INFO cn.smallbun.screw.core.process.DataTableProcess - 获取表信息已完成,共 12 张表 [main] INFO cn.smallbun.screw.core.process.DataTableProcess - 获取列信息已完成 [main] INFO cn.smallbun.screw.core.process.DataTableProcess - 获取索引信息已完成 [main] INFO cn.smallbun.screw.core.engine.AbstractEngine - 文档生成成功,文件位置:D:/temp/screw/数据库表结构文档.html

打开生成出来的 HTML 文件,你会看到一个带侧边栏的页面,左侧列出所有表名,点击表名右侧展示该表的字段列表。每个字段都包含字段名、数据类型、是否主键、是否为空、默认值、注释等信息。如果你选择了 Markdown 格式,生成的是.md文件,内容就是一张张 Markdown 表格,可以直接贴到 Git 仓库的 docs 目录下。

我第一次跑通的时候,最直观的感受是:省时间、省心、还不容易出错。相比之前手动核对字段,这个工具等于把“读库”这件事自动化了。

4. 进阶玩法与实用配置

4.1 一次生成多种格式文档

上文的配置里fileType一次只能指定一种格式。如果你既需要 HTML 给团队成员在浏览器里看,又要 Markdown 放到 Git 仓库,可以稍微改造一下:把生成逻辑封装成一个方法,循环执行多种格式。

public static void generateByType(DataSource dataSource, EngineFileType fileType, String fileName) { EngineConfig engineConfig = EngineConfig.builder() .fileOutputDir("D:/temp/screw") .openOutputDir(false) .fileType(fileType) .produceType(EngineTemplateType.freemarker) .fileName(fileName) .build(); Configuration config = Configuration.builder() .version("1.0.0") .description("订单系统数据库设计文档") .dataSource(dataSource) .engineConfig(engineConfig) .build(); new DocumentationExecute(config).execute(); } public static void main(String[] args) { DataSource dataSource = buildDataSource(); generateByType(dataSource, EngineFileType.HTML, "数据库表结构文档"); generateByType(dataSource, EngineFileType.WORD, "数据库表结构文档"); generateByType(dataSource, EngineFileType.MD, "数据库表结构文档"); }

这里有个细节:三种格式共用同一个文件名时会生成三份不同后缀的文件,不会互相覆盖。我实际用下来,推荐在项目日常维护中优先生成 Markdown 格式,因为可以直接 diff,结构变更一目了然;对外交付或评审时用 Word 格式;给别人快速浏览时用 HTML 格式。

4.2 指定生成范围:只看你想看的表

有时候一个库里表非常多,但这次只想给某个模块生成文档,这时可以用ProcessConfig来控制范围。上面例子中用的ignoreTableName是“排除法”,如果你希望更精细化,还有includeTableName可以只生成指定的表。

ProcessConfig processConfig = ProcessConfig.builder() // 只生成这两张表,其他表忽略 .includeTableName(Arrays.asList("user", "order")) .build();

注意一点:includeTableNameignoreTableName是互斥的逻辑。如果同时设置了,screw-core 的处理规则是:先用includeTableName过滤出表集合,再用ignoreTableName排除掉不需要的表。实际使用中,我建议除非确实需要,否则不要同时配置这两个参数,否则很容易出现“我明明设置了几张表怎么生成的却少了几张”的困惑。

4.3 在 Spring Boot 项目中集成

如果你的项目本身就是 Spring Boot,那么在已有DataSource的前提下,集成更简单。可以在测试类或启动类里直接注入数据源:

@SpringBootTest class ScrewGeneratorTest { @Autowired private DataSource dataSource; @Test void generateDatabaseDoc() { EngineConfig engineConfig = EngineConfig.builder() .fileOutputDir("./docs") .openOutputDir(false) .fileType(EngineFileType.MD) .produceType(EngineTemplateType.freemarker) .fileName("database-doc") .build(); ProcessConfig processConfig = ProcessConfig.builder() .ignoreTableName(Arrays.asList("sys_user", "sys_role")) .build(); Configuration config = Configuration.builder() .version("1.0.0") .description("Spring Boot 项目数据库文档") .dataSource(dataSource) .engineConfig(engineConfig) .produceConfig(processConfig) .build(); new DocumentationExecute(config).execute(); } }

这样你在本地跑一下测试方法,文档就生成到./docs目录下了。如果要接入 CI/CD,可以把这一步放到流水线里,每次发布时自动生成并归档到制品库,这样团队拿到的永远是最新结构说明。

4.4 让文档更好看:表注释与字段注释的规范

生成文档质量的上限,取决于你的注释质量。这里分享几个我踩过坑之后总结的注释规范建议:

  • 表注释:一句话说明这张表的核心用途,比如“用户基本信息表”,而不是只写“用户表”。如果表是从某个业务模块拆出来的,注释里建议加上模块名。
  • 字段注释:尽可能说明字段的业务含义和取值范围。比如status字段,注释可以写成“状态:0-禁用,1-启用”。这样生成的文档里,别人不用翻代码就能理解字段含义。
  • 不要过度依赖工具补注释:screw-core 不提供反向把注释写回数据库的能力,所以源头注释还是要靠开发者在建表/改表时维护好。

如果你负责的老项目注释缺失严重,可以临时写一个 SQL,把information_schema.columns里的字段信息导出来,人工批量补一轮注释再更新表。虽然这项工作比较枯燥,但从长期维护的角度看,投入产出比很高。

5. 常见问题与排查心得

5.1 时区或 SSL 连接报错

这是 MySQL 8 环境下最容易遇到的问题,错误信息通常长这样:

java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized...

解决方案就是在 JDBC URL 里加上时区参数:

String url = "jdbc:mysql://127.0.0.1:3306/your_database?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";

useSSL=false是为了避免本地开发环境下 SSL 握手带来的额外麻烦,生产环境如果需要加密连接,可以单独配置 SSL 证书,但生成文档这种内部工具场景没必要开。

5.2 驱动类找不到

如果你用的是 MySQL 5.x 的驱动,但配置里写的是com.mysql.cj.jdbc.Driver,也会报错。反过来,MySQL 8 用老的com.mysql.jdbc.Driver同样可能有问题。

一个简单的判断方法:看你的pom.xmlmysql-connector-java的版本。5.1.x 版本用com.mysql.jdbc.Driver,8.0.x 版本用com.mysql.cj.jdbc.Driver。如果你的项目里既有旧又有新,建议统一成 8.0.x,新版驱动向下兼容 MySQL 5.7 数据库。

5.3 生成出来的文档内容是空的

生成成功但文档里只有标题没有表格内容,最常见的原因是ProcessConfig里设置的忽略规则把所有表都过滤掉了。比如你设置了ignoreTableName包含所有表名,或者ignoreTablePrefix设置成空字符串导致匹配异常。

排查思路很简单:先把ProcessConfig里的规则清空,生成一次确认表数量,然后再把忽略规则一项一项加回去。screw-core 在日志里会打印获取到的表数量,比如获取表信息已完成,共 12 张表,如果这个数字是 0,那基本可以确定是表被过滤规则误伤了。

5.4 生成过程卡住不动

这种情况多半是数据库连接问题。我遇到过一种典型的场景:数据库服务器和本地网络有防火墙限制,本地用 Navicat 连接没问题,但 screw-core 生成时连接超时,因为 HikariCP 默认的连接超时时间比较长,看起来就像卡住了。

建议在配置 Hikari 数据源时显式设置连接测试相关参数,比如:

hikariConfig.setConnectionTimeout(30000); hikariConfig.setValidationTimeout(5000); hikariConfig.setMaximumPoolSize(5);

此外,确认你用的数据库账号有权限读取元数据。比如 MySQL 下需要账号对information_schema有查询权限,否则 screw-core 会拿到空的表列表。

5.5 其他数据库的使用注意

screw-core 不只是支持 MySQL。如果你用的是 PostgreSQL、Oracle、SQL Server、SQLite、MariaDB、达梦等,基本上只需要替换驱动和 URL 就能跑通。

有几个小地方提醒一下:

  • PostgreSQL 的驱动类名是org.postgresql.Driver,URL 格式是jdbc:postgresql://127.0.0.1:5432/your_database
  • 达梦数据库的驱动类名是dm.jdbc.driver.DmDriver,URL 格式是jdbc:dm://127.0.0.1:5236
  • SQLite 是文件型数据库,URL 一般长这样:jdbc:sqlite:/path/to/your.db,使用起来最简单,不需要账号密码。

我在实际项目里用 PostgreSQL 和达梦生成过文档,除了驱动和 URL,其他配置基本不用改,兼容性做得还是不错的。

6. 生成文档之后的维护心得

工具能帮你把“从库到文档”这一半自动化,但另一半“让文档保持最新”还需要流程保障。这里分享一个我后来一直在用的做法:把文档生成接入到每次数据库变更的收尾阶段

具体来说,我会在涉及表结构变更的需求里加一个“文档同步”的任务。数据库变更脚本执行完之后,本地跑一下 screw-core,生成新的 Markdown 文档,提交到 Git 仓库。这样,每个版本的表结构变更都能在代码仓库里追溯到。

有朋友问我说:直接让 CI 每次构建时重新生成一次文档,然后自动提交,不是更省事吗?我试过,但不太推荐全自动,因为表结构变更往往需要配合人工确认变更说明,全自动提交容易出现“文档变了但没人知道变了什么”的尴尬。反而是在 code review 阶段,人工触发一次生成,顺便在 PR 描述里列出本次文档变更涉及的表,这样整个变更链路是清晰可追溯的。

再补充一个小技巧:如果团队使用 Git,每次提交完数据库结构文档后,可以在 commit message 里标注清楚涉及的表名,比如docs: 更新订单表和支付表结构说明。这样日后想查找某个时间点的表结构,直接翻 Git 提交历史就能定位,比在数据库里翻 binlog 或者回忆要可靠得多。

7. 写在最后的大白话建议

说实话,screw-core 这个工具本身不复杂,我见过不少同事半小时就能跑通。但工具越简单,越能暴露出团队在数据库注释规范和文档维护流程上的短板。如果你打算把它引到团队里,我的建议是先花点时间把存量表的注释补齐,再统一生成一次文档作为基线,然后约定后续表结构变更时必须更新注释、同步文档。

我自己用下来的体会是:这类“一键生成”的工具最大的价值不在于省下那几分钟,而在于它让“数据库结构”这件事从某个人的脑子里、某个人的本地文件里,变成了团队共享的、版本可控的、始终和真实环境保持一致的一份资产。对课程设计、毕业设计、项目验收来说,它更是能直接帮你产出一份结构规范、内容详实的数据库设计文档。

最后分享一个可以减少返工的小经验:在第一次生成文档前,先拿一个小库试跑,确认输出格式和内容样式符合预期,再去处理核心业务库。这样就算配置有问题,影响面也小,排查起来更省事。希望这篇文章能帮你顺利跑通 screw-core,少踩几个我踩过的坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 3:39:31

等精度测频原理与Verilog实现:电赛数字频率计设计全解析

简介&#xff1a;一套基于Verilog的等精度测频完整工程方案&#xff0c;源自2015年电赛F题&#xff0c;适合FPGA初学者、电子竞赛参赛者及数字系统设计相关课程实践。工程采用50MHz采样时钟&#xff0c;通过计数器测量输入信号边沿&#xff0c;并借助UART串口将频率结果发送至上…

作者头像 李华
网站建设 2026/9/9 3:39:23

服务器内存ECC错误日志判读与排障实战:从uncorr. ECC到MBIST诊断

1. 从一条“2”开始&#xff1a;ECC错误日志到底在说什么 前几天处理一台机房告警&#xff0c;登录iDRAC一看&#xff0c;事件日志里躺着一条&#xff1a; Uncorrectable ECC at DIMM_A2, error count: 2 。如果你没见过这条日志&#xff0c;可能觉得“2”只是个小数字&#…

作者头像 李华
网站建设 2026/9/9 3:37:12

Java基础核心梳理:从环境配置到集合框架与并发锁的实践要点

1. 环境搭建别只配个PATH就完事很多初学者接触JAVA的第一课就是装JDK、配环境变量&#xff0c;然后敲一个HelloWorld跑通就觉得自己会了。但等到真正在命令行里编译、运行带依赖的项目&#xff0c;或者部署到服务器上时&#xff0c;各种莫名其妙的环境问题就冒出来了。热搜词里…

作者头像 李华
网站建设 2026/9/9 3:36:37

工控单板存储配置与OverlayFS恢复出厂机制详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 3:36:30

DSpark:融合半自回归与置信度调度的推理加速方案

最近和几个做推理优化的朋友聊&#xff0c;大家最关心的其实还是那几件事&#xff1a;单卡能不能多撑点并发、长上下文会不会把显存打爆、以及有没有办法让大模型别再一个一个 token 往外蹦。说实话&#xff0c;自回归生成的天花板摆在那里&#xff0c;纯靠算子优化已经卷到一定…

作者头像 李华
网站建设 2026/9/9 3:33:35

PIVlab工具箱安装与使用指南:从zip解压到流场计算全流程

简介&#xff1a;PIVlab.zip是一款面向流体力学研究与工程应用的时间分辨粒子图像测速&#xff08;PIV&#xff09;软件包&#xff0c;适合需要分析流场速度分布、涡量及流动模式的研究人员、研究生及相关工程师。软件提供用户友好的图形用户界面&#xff0c;并支持命令行调用&…

作者头像 李华