目录
- 序言
- Beetl
- 代码
- 总结
序言
最近公司里有一个新的需求,需要导出数据库元数据表中存储的表的 DDL 语句,而在元数据表中数据源的类型庞大,少则十几种多则达到几十种,各种数据库类型都有,比如常见就有 mysql
PostgreSQL
oracle
SQL Server
等等,而不同的数据库其数据类型和语法都存在一些差异,如果在代码中去处理工作量就太大了。所以我想到使用模版引擎来处理,现在市面上出现了一个新的模版引擎 Beetl。本篇文章就从这个模版引擎来入手介绍如何实现功能。代码已经提交到了我的 github 仓库
Beetl
Beetl
的使用方式和 Thymeleaf
、Freemarker
差不多,而且其语法简单,性能也优于这两者,目前在国内已经有一定的用户群体。话不多说,具体的使用方式非常简单,大家看一下官网就会了,下面来说功能怎么实现
代码
使用前在SpringBoot中使用的时候需要先导入依赖,我测试的 SpringBoot 的版本为 3.2.1
<dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl-spring-boot-starter-classic</artifactId> <version>3.19.1.RELEASE</version> </dependency>
创建一下库表,因为模版文件是存储在数据库中,方便后期维护
create table ddl_template ( id int auto_increment primary key, name varchar(255) not null, description varchar(255) null, created_at timestamp not null, updated_at timestamp null, created_by varchar(255) null, updated_by varchar(255) null, version float not null, db_type varchar(255) not null, template text not null ) comment 'ddl模板表' charset = utf8mb4;
表创建完成后,我事先往这个表中添加了三条数据,分别代表 MySQL、Oracle、PgSQL 的DDL 模版
MySQL:
drop table if exists `${table.tableCode}`; create table ${table.tableCode}( <% for(field in fieldList){ var code = field.code; var comment = field.comment; var type = field.type; var len = field.le编程n; var scale = field.scale; var notNull = field.notNull; var autoIncrement = field.autoIncrement; var defaultValue = field.defaultValue; var last = fieldLP.last; if (len != null) { if (len > 0) { var temp = "(" + len; if (scale != null) { if (scale > 0) { temp = temp + "," + scale; } } temp = temp + ")"; type = type + temp; } } %> `${field.code}` ${type}${autoIncrement ? " auto_increment":""}${notNull ? " not null":" null"}${defaultValue != null ? " default '" + defaultValue + "'" : "" } ${comment != null ? " comment '" + comment + "'":""}${!last ? ",":""} <% } %> <% if (primaryKey != null){ %> ,primary key (${primaryKey}) <% } %> ) comment = '${table.tableComment}';
Oracle:
create table "${table.tableCode}"( <% for(field in fiel编程dList){ var code = field.code; var comment = field.comment; var type = field.type; var len = field.len; var scale = field.scale; var primaryKey = field.primaryKey; var notNull = field.notNull; var defaultValue = field.defaultValue; var last = fieldLP.last; if (len != null && type != 'date') { if (len > 0) { var temp = "(" + len; if (scale != null) { if (scale > 0) { temp = temp + "," + scale; } } temp = temp + ")"; type = type + temp; } } if (type == 'date') { defaultValue = null; notNull = false; } %> "${field.code}" ${type}${defaultValue != null ? " default '" + defaultValue + "'" : "" }${notNull ? " not null":" null"}${!last ? ",":""} <% } %> <% if (primaryKey != null){ %> ,primary key ("${primaryKey}") <% } %> ); comment on table "${table.tableCode}" is '${table.tableComment}'; <% for(field in fieldList){ var code = field.code; var comment = field.comment; var last = fieldLP.last; %> comment on column "${table.tableCode}"."$[code]" is '${comment}'; <% } %>
PgSQL:
drop table if exists "${table.tableCode}"; create table "${table.tableCode}"( <% for(field in fieldList){ var code = field.code; var comment = field.comment; var type = field.type; var len = field.len; var scale = field.scale; var notNull = field.notNull; var autoIncrement = field.autoIncrement; var defaultValue = field.defaultValue; var last = fieldLP.last; if (len != null) { if (len > 0) { var temp = "(" + len; if (scale != null) { if (scale > 0) { temp = temp + "," + scale; } } temp = temp + ")"; type = typandroide + temp; } } %> "$[code]" ${type}${autoIncrement ? " generated always as identity" : ""}${notNull ? " not null" : ""}${defaultValue != null ? " default '" + defaultValue + "'" : "编程客栈" } ${!last ? "," : ""} <% } %> <% if (primaryKey != null){ %> ,primary key (${primaryKey}) <% } %> ); comment on table "${table.tableCode}" is '${table.tableComment}'; <% for(field in fieldList){ var code = field.code; var comment = field.comment; if (comment != null) { %> comment on column "${table.tableCode}"."$[code]" is '${comment}'; <% } } %>
准备工作完成后,接下来开发代码,具体代码如下:
@Bean public GroupTemplate groupTemplate() throws Exception { StringTemplateResourceLoader loader = new StringTemplateResourceLoader(); org.beetl.core.Configuration cfg = org.beetl.core.Configuration.defaultConfiguration(); GroupTemplate gt = new GroupTemplate(loader, cfg); return gt; }
这里使用的 StringTemplateResourceLoader
表示从字符串中来加载模板,也有其他的 ResourceLoader
,比如 FileResourceLoader
表示从文件中加载模版,具体的看官网就可以了
/** * 单张表的ddl语句创建 * * @return */ @PostMapping("/createDdl") public void createDdl(@RequestParam("version") String version,@RequestParam("dbType") String dbType) { ddlTemplateService.createDdl(version, dbType); }
@Override public void createDdl(String version, String dbType) { DbEnum dbEnum = DbEnum.fromString(dbType); Assert.notNull(dbType, "数据库类型不支持"); switch (dbEnum) { case MYSQL: generateMysqlDdl(version, dbType, buildMySQLData()); break; case ORACLE: generateOracleDdl(version, dbType, buildOracleData()); break; case POSTGRESQL: generatePostgresqlDdl(version, dbType, buildPostgresqlData()); break; } }
这里支持的数据库类型还比较少,大家可以后面扩充
/** * 这里只是模拟一下,实际情况应该是从数据库中查询的对应的表及字段 * * @return */ private Map<String, Object> buildMySQLData() { MySQLTable tableVO = MySQLTable.builder().tableCode("t_user").tableComment("用户表").build(); List<MySQLField> fieldVOList = List.of( MySQLField.builder().code("id").comment("主键").type("int").len(11).scale(0.0).autoIncrement(true).notNull(true).build(), MySQLField.builder().code("name").comment("姓名").type("varchar").len(50).scale(0.0).autoIncrement(false).defaultValue("").notNull(true).build(), MySQLField.builder().code("age").comment("年龄").type("int").len(11).scale(0.0).autoIncrement(false).notNull(true).build(), MySQLField.builder().code("email").comment("邮箱").type("varchar").len(50).scale(0.0).autoIncrement(false).defaultValue("").notNull(true).build(), MySQLField.builder().code("create_time").comment("创建时间").type("date").len(0).scale(0.0).autoIncrement(false).notNull(true).notNull(true).build() ); return Map.of("table", tableVO, "fieldList", fieldVOList, "primaryKey", "id"); } private Map<String, Object> buildOracleData() { OracleTable tableVO = OracleTable.builder().tableCode("t_user").tableComment("用户表").build(); List<OracleField> fieldVOList = List.of( OracleField.builder().code("id").comment("主键").type("NUMBER").len(11).scale(0.0).autoIncrement(true).notNull(true).build(), OracleField.builder().code("name").comment("姓名").type("varchar").len(50).scale(0.0).autoIncrement(false).defaultValue("").notNull(true).build(), OracleField.builder().code("age").comment("年龄").type("NUMBER").len(11).scale(0.0).autoIncrement(false).notNull(true).build(), OracleField.builder().code("email").comment("邮箱").type("varchar").len(50).scale(0.0).autoIncrement(false).defaultValue("").notNull(true).build(), OracleField.builder().code("create_time").comment("创建时间").type("date").len(0).scale(0.0).autoIncrement(false).notNull(true).notNull(true).build() ); return Map.of("table", tableVO, "fieldList", fieldVOList, "primaryKey", "id"); } private Map<String, Object> buildPostgresqlData() { PostgresqlTable tableVO = PostgresqlTable.builder().tableCode("t_user").tableComment("用户表").build(); List<PostgresqlField> fieldVOList = List.of( PostgresqlField.builder().code("id").comment("主键").type("integer").autoIncrement(true).notNull(true).build(), PostgresqlField.builder().code("name").comment("姓名").type("varchar").len(50).scale(0.0).autoIncrement(false).defaultValue("").notNull(true).build(), PostgresqlField.builder().code("age").comment("年龄").type("int").autoIncrement(false).notNull(true).build(), PostgresqlField.builder().code("email").comment("邮箱").type("varchar").len(50).scale(0.0).autoIncrement(false).defaultValue("").notNull(true).build(), PostgresqlField.builder().code("create_time").comment("创建时间").type("timestamp").len(0).scale(0.0).autoIncrement(false).notNull(true).notNull(true).build() ); return Map.of("table", tableVO, "fieldList", fieldVOList, "primaryKey", "id"); } private void generateMysqlDdl(String version, String dbType, Map<String, Object> data) { try { // 可以考虑将模版文件缓存 Template template = groupTemplate.getTemplate(queryByUnique(version, dbType).getTemplate()); template.binding(data); String render = template.render(); log.info("生成MysqlDDL语句成功"); FileUtil.writeUtf8String(render, "D:/ddl.sql"); } catch (Exception e) { throw new RuntimeException("生成DDL语句失败", e); } } private void generateOracleDdl(String version, String dbType, Map<String, Object> data) { try { // 可以考虑将模版文件缓存 Template template = groupTemplate.getTemplate(queryByUnique(version, dbType).getTemplate()); template.binding(data); String render = template.render(); log.info("生成OracleDDL语句成功"); FileUtil.writeUtf8String(render, "D:/ddl.sql"); } catch (Exception e) { throw new RuntimeException("生成DDL语句失败", e); } } private void generatePostgresqlDdl(String version, String dbType, Map<String, Object> data) { // 可以考虑将模版文件缓存 Template template = groupTemplate.getTemplate(queryByUnique(version, dbType).getTemplate()); template.binding(data); String render = template.render(); log.info("生成PgSQLDDL语句成功"); FileUtil.writeUtf8String(render, "D:/ddl.sql"); }
我这里运行后会分别针对不同的数据库类型来生成对应的表 DDL 语句,效果如下:
MySQL
drop table if exists `t_user`; create table t_user( `id` int(11) auto_increment not null comment '主键', `name` varchar(50) not null default '' comment '姓名', `age` int(11) not null comment '年龄', `email` varchar(50) not null default '' comment '邮箱', `create_time` date not null comment '创建时间' ,primary key (id) ) comment = '用户表';
Oracle
create table "t_user"( "id" NUMBER(11) not null, "name" varchar(50) default '' not null, "age" NUMBER(11) not null, "email" varchar(50) default '' not null, "create_time" date null ,primary key ("id") ); comment on table "t_user" is '用户表'; comment on column "t_user"."id" is '主键'; comment on column "t_user"."name" is '姓名'; comment on column "t_user"."age" iphps '年龄'; comment on column "t_user"."email" is '邮箱'; comment on column "t_user"."create_time" is '创建时间';
PgSQL
drop table if exists "t_user"; create table "t_user"( "id" integer generated always as identity not null , "name" varchar(50) not null default '' , "age" int not null , "email" varchar(50) not null default '' , "create_time" timestamp not null ,primary key (id) ); comment on table "t_user" is '用户表'; comment on column "t_user"."id" is '主键'; comment on column "t_user"."name" is '姓名'; comment on column "t_user"."age" is '年龄'; comment on column "t_user"."email" is '邮箱'; comment on column "t_user"."create_time" is '创建时间';
这三个 DDL 语句在对应的数据库里面是可以运行
总结
这里采用数据库存储模版的方式比在代码中硬编码维护性要好,不然模版有改动的话,还需要去修改代码重新打包,总体下来并不是很难。
以上就是SpringBoot+Beetl实现动态数据库DDL的示例代码的详细内容,更多关于SpringBoot Beetl动态数据库DDL的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论