代码生成器
本章将介绍 Kronos 代码生成器的使用方法,可根据数据库表结构自动生成实体类。
代码生成器
Kronos 代码生成器会读取数据库元数据,并写出 Kotlin KPojo 实体类。数据库结构是项目实体来源时,可以用它让实体类与已有表结构保持一致。
代码生成器使用 TOML 配置文件和 Kotlin Script 模板。配置文件选择表、数据源、命名策略和输出目录,模板控制生成的 Kotlin 文件内容。
Database First 工作流请参考 Database First。 安装与运行时排查见
📚故障排查。
依赖 添加脚本依赖
在 .main.kts 脚本中加入 kronos-codegen、kronos-core 和 kronos-jdbc-wrapper。JDBC Driver 和连接池使用与数据库、JDK 匹配的最新稳定版。
example.main.kts
#!/usr/bin/env kotlin
@file:Repository("https://repo1.maven.org/maven2")
@file:DependsOn("com.kotlinorm:kronos-codegen:0.4.0")
@file:DependsOn("com.kotlinorm:kronos-core:0.4.0")
@file:DependsOn("com.kotlinorm:kronos-jdbc-wrapper:0.4.0")
@file:DependsOn("org.apache.commons:commons-dbcp2:<latest-stable>")
@file:DependsOn("com.mysql:mysql-connector-j:<latest-stable>")将 <latest-stable> 替换为连接池或 JDBC Driver 项目发布的当前稳定版。
配置 选择数据表
创建 config.toml。每个 [[table]] 会生成一个 Kotlin 文件。
config.toml
[[table]]
name = "tb_user"
className = "User"
[[table]]
name = "tb_order"
className = "Order"配合下面的输出配置,生成器会为每张表写出一个文件。
generated files
src/main/kotlin/com/example/entity/User.kt
src/main/kotlin/com/example/entity/Order.kt需要明确控制 Kotlin 类名时,设置 className。
class name
[[table]]
name = "sys_account"
className = "Account"配置输出目录
targetDir 指定生成文件目录,packageName 指定模板写入的包名。
config.toml
[output]
targetDir = "src/main/kotlin/com/example/entity"
packageName = "com.example.entity"
tableCommentLineWords = 80模板中可以直接读取这些值。
template
template {
+"package $packageName"
+""
+formatedComment
}生成文件会以配置的包名和格式化后的表注释开头。
User.kt
package com.example.entity
// User account table配置数据源
dataSource 用于创建读取表注释、字段和索引的 JDBC 连接。下面示例使用 Apache DBCP2 和内置 KronosJdbcWrapper。
config.toml
[dataSource]
wrapperClassName = "com.kotlinorm.wrappers.KronosJdbcWrapper"
dataSourceClassName = "org.apache.commons.dbcp2.BasicDataSource"
url = "jdbc:mysql://localhost:3306/kronos_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false"
username = "root"
password = "your_password"
driverClassName = "com.mysql.cj.jdbc.Driver"
initialSize = 5
maxTotal = 10切换连接池时,使用该 DataSource 类支持的属性名。
Druid
[dataSource]
wrapperClassName = "com.kotlinorm.wrappers.KronosJdbcWrapper"
dataSourceClassName = "com.alibaba.druid.pool.DruidDataSource"
url = "jdbc:mysql://localhost:3306/kronos_demo"
username = "root"
password = "your_password"
driverClassName = "com.mysql.cj.jdbc.Driver"
initialSize = 5
maxActive = 10切换连接池实现时,在脚本中加入对应依赖。
Druid dependency
@file:DependsOn("com.alibaba:druid:<latest-stable>")配置命名策略
lineHumpNamingStrategy 会将下划线名称映射为驼峰 Kotlin 属性名。
config.toml
[strategy]
tableNamingStrategy = "lineHumpNamingStrategy"
fieldNamingStrategy = "lineHumpNamingStrategy"使用该策略时,数据库字段 create_time 会生成 createTime。
User.kt
var createTime: java.time.LocalDateTime? = null希望生成名保持数据库元数据名称时,使用 noneNamingStrategy。
keep names
[strategy]
tableNamingStrategy = "noneNamingStrategy"
fieldNamingStrategy = "noneNamingStrategy"User.kt
var create_time: java.time.LocalDateTime? = null生成特殊字段注解
在策略中配置主键、创建时间、更新时间、逻辑删除和乐观锁字段。
config.toml
[strategy]
primaryKeyStrategy = "id"
createTimeStrategy = "create_time"
updateTimeStrategy = "update_time"
logicDeleteStrategy = "deleted"
optimisticLockStrategy = "version"数据库表包含对应字段时,field.annotations() 会写出 Kronos 注解。逻辑删除列需要定义DEFAULT 0(PostgreSQL 使用DEFAULT false),Codegen 才会生成下例中的@Default注解。
User.kt
import com.kotlinorm.annotations.CreateTime
import com.kotlinorm.annotations.Default
import com.kotlinorm.annotations.LogicDelete
import com.kotlinorm.annotations.PrimaryKey
import com.kotlinorm.annotations.UpdateTime
import com.kotlinorm.annotations.Version
data class User(
@PrimaryKey(identity = true)
var id: Int? = null,
@CreateTime
var createTime: java.time.LocalDateTime? = null,
@UpdateTime
var updateTime: java.time.LocalDateTime? = null,
@LogicDelete
@Default("0") // @Default("false") for Postgres
var deleted: Boolean? = null,
@Version
var version: Int? = null
) : KPojo注解在 ORM 操作中的行为请参考 📚注解配置。
生成字段元数据注解
模板可以把数据库元数据转换成字段注解。非空数据库字段会生成 @NonNull。
template
fields.forEach { field ->
field.annotations().forEach { annotation ->
+"""${indent(4)}$annotation"""
}
+"""${indent(4)}var ${field.name}: ${field.kotlinType}? = null,"""
}必填的 name 字段会生成带 @NonNull 的属性。
User.kt
@NonNull
var name: String? = null带精度信息的 decimal 字段会生成 @ColumnType。
User.kt
@ColumnType(type = KColumnType.DECIMAL, length = 10, scale = 2)
var balance: java.math.BigDecimal? = null生成表索引
使用 indexes.toAnnotations() 写出从数据库元数据读取到的索引注解。
template
+indexes.toAnnotations()
+"""@Table("$tableName")"""生成的实体类会在类声明前带上 @TableIndex。
User.kt
@TableIndex(name = "idx_user_email", columns = ["email"], type = "UNIQUE")
@Table("tb_user")
data class User(
var email: String? = null
) : KPojo创建模板
先调用 init("config.toml"),再调用 template { ... }。模板块会为每张配置的数据表执行一次。
example.main.kts
import com.kotlinorm.codegen.KronosConfig.Companion.write
import com.kotlinorm.codegen.TemplateConfig.Companion.template
import com.kotlinorm.codegen.init
import com.kotlinorm.codegen.kotlinType
init("config.toml")
template {
+"package $packageName"
+""
+imports.joinToString("
") { "import $it" }
+""
+formatedComment
+indexes.toAnnotations()
+"""@Table("$tableName")"""
+"""data class $className("""
+fields.mapIndexed { index, field ->
val annotations = field.annotations().joinToString("
") { "${indent(4)}$it" }
val annotationBlock = if (annotations.isEmpty()) "" else "$annotations
"
val comma = if (index == fields.lastIndex) "" else ","
"""$annotationBlock${indent(4)}var ${field.name}: ${field.kotlinType}? = null$comma"""
}.joinToString("
")
+") : KPojo"
}.write()生成文件会按照模板拼出的结构写入。
User.kt
package com.example.entity
import com.kotlinorm.annotations.Table
import com.kotlinorm.interfaces.KPojo
@Table("tb_user")
data class User(
var id: Int? = null,
var name: String? = null
) : KPojo使用配置继承
把共享输出目录和数据源配置放入基础 TOML 文件。
base.toml
[output]
targetDir = "src/main/kotlin/com/example/entity"
packageName = "com.example.entity"
[dataSource]
wrapperClassName = "com.kotlinorm.wrappers.KronosJdbcWrapper"
dataSourceClassName = "org.apache.commons.dbcp2.BasicDataSource"
url = "jdbc:mysql://localhost:3306/kronos_demo"
username = "root"
password = "your_password"
driverClassName = "com.mysql.cj.jdbc.Driver"项目配置可以继承基础文件,并补充自己的表列表。
config.toml
extend = "base.toml"
[[table]]
name = "tb_user"
className = "User"脚本运行时读取项目配置。
example.main.kts
init("config.toml")运行生成器
Kotlin 脚本文件名使用 xxx.main.kts 格式。
shell
kotlinc -script example.main.kts运行成功后,生成器会输出每个写入的文件。
output
File generated successfully: src/main/kotlin/com/example/entity/User.kt配置缺少必要区域时,脚本会输出明确错误信息。
missing table
IllegalArgumentException: Table configuration is required in config: config.toml