项目源码地址: github
背景
利用plantuml
绘制架构评审图时,发现数据库ER图手写字段信息成本太大,需要一个把DB表结构转换为plantuml
格式的工具。
搜索了一番,没有发现支持工具,所以准备手撸一个,并记录下设计及编码实现的过程。
需求
一句话需求: 读取数据库表结构,转换为plantuml格式的ER图。
设计
根据需求抽象出下列概念
基础元素(一个输入一个输出)
ER
-> plantuml
格式er
图
db_schema
-> 数据库结构,ddl语句是其中一种实现形式
扩展概念
table
-> 表结构信息
template
-> 模板,定义er
图输出格式
操作行为
reader
-> 读取数据库结构,识别 table
parser
-> 根据 table
和 template
转换为ER
图
writer
-> 输出ER
图文件
整体交互
选型
都是基本的文件及String操作,通过 druid 进行sql解析
编码实现
Reader
读取ddl.sql文件,解析成 table
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| interface Reader {
fun read(dbType: String? = DEFAULT_DB_TYPE): Iterable<Table>
fun extract(dbType: String, sql: String): Table { ... } }
class FileReader(private val path: String) : Reader {
override fun read(dbType: String?): Iterable<Table> { return Files.readAllLines(Paths.get(path)) .filter { !it.startsWith("#") } .joinToString("") .split(";") .filter { it.isNotBlank() } .map { extract(dbType?: DEFAULT_DB_TYPE, it) } .toList() }
}
|
Writer
template
通过resource文件管理,接收table
输出plantuml格式ER
图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| interface Writer {
fun write(tables: Iterable<Table>)
fun parse(tables: Iterable<Table>): String { val template = Thread.currentThread().contextClassLoader.getResource("dot.template")!!.readText()
val content = tables.joinToString("") { table -> val columns = table.columnList.joinToString("\n") { "${it.notNullNameWrapper()} ${it.type} ${it.defaultValue} ${it.comment}" } "Table(${table.name}, \"${table.name}\\n(${table.comment})\"){ \n $columns + \n } \n" }
return template.replace("__content__", content) }
private fun Column.notNullNameWrapper(): String { return if (this.notNull) { "not_null(${this.name})" } else { this.name } } }
class FileWriter(private val path: String) : Writer {
override fun write(tables: Iterable<Table>) { Files.write(Paths.get(path), parse(tables).toByteArray()) }
}
|
Main
1 2 3 4 5 6 7 8 9 10
| fun main(args: Array<String>) {
val inPath = args[0] val outPath = args[1] val dbType = args.getOrNull(2)
FileReader(inPath).read(dbType) .apply { FileWriter(outPath).write(this) }
}
|
效果
1
| java -jar ddl2plantuml.jar ddl.sql er.puml
|
程序会读取当前目录下的ddl.sql文件,并转换生成er.puml文件。