MelonBlog

实现并开源了一个有意思的命令行代码生成器

一直想有一个直接在命令行就可以生成代码的工具,之前一直在用Mybatis Generator插件,但是这个是收费的,并且我想更改模版不是很方便,并且通过gui来操作没有直接使用命令行方便。

我理想中的代码生成器,可以很方便的在项目工作目录里生成代码,并且可以适应不同的项目,在不同的项目里生成不同的样板代码。

正好最近工作中有一个报表任务,针对不同的业务做报表,这种场景写的代码非常样板式,于是我自己实现了一个,并且开源了。


github仓库地址:

https://github.com/aidonggua/code-generator

cg设计理念

.cg工作目录

我参考了git的思路,在每个项目里生成一个目录作为cg的工作目录

image


可以通过cg init 命令在你的项目中创建这个.cg目录。

cg init 命令会默认生成一些常用模版,可以根据每一个项目的具体情况来修改模版

任务链

每一张表通常会生成好几个文件,并且文件之间的信息可能会互相依赖,所以我设计了一个任务链,后执行的任务可以读取先执行任务的信息

通过config.yaml文件可以配置任务链,并且每一个任务都可以配置独有的属性

mysql:
  username: root
  password: 123456
  host: 127.0.0.1
  port: 3306
  database: test
  table: user
author: yehao
base-package: com.example
module: test
tasks:
  # 生成java实体
  - name: JavaEntity
    template: java_entity.tpl
    output: .cg/output
    file-postfix: .java
    variables:
      sub-package: dao.domain
    enable: true
  # 生成java mapper类
  - name: JavaMapper
    template: java_mapper.tpl
    output: .cg/output
    file-postfix: Mapper.java
    variables:
      sub-package: dao.mapper
      class-postfix: Mapper
    enable: true
  # 生成java mybatis 的xml文件
  - name: JavaMapperXml
    template: java_mapper_xml.tpl
    output: .cg/output
    file-postfix: Mapper.xml
    enable: true

模版引擎

调研了一些常用模版引擎,我最终发现还是go自带的模版引擎用起来最优雅,我最喜欢下面几个 特性:

通过减号-可以控制空行,这样模版文件就不会看起来非常紧凑难以阅读
命令之间还可以通过|管道符来嵌套使用,可以讲几个简单的命令组成一个复杂的命令
可以很好的控制空行和支持调用函数(可以把这个特性作为模版里的命令功能)

我还把取值方式全部改成了命令的方式{{命令 参数}},并增加了一些自定义命令,例如字符串转换操作、日期、类型转换等等。

还提供了读取配置文件和获取表信息等命令(这是最核心的),例如{{config 配置名}}{{table "comment"}}

{{refs 任务 配置名}}命令还可以读取其他任务里的配置信息


示例1:🌰

package {{config "base-package"}}.{{config "module"}}.{{var "sub-package"}};
{{""}}
{{- range imports}}
{{.}}
{{end -}}
import com.baomidou.mybatisplus.annotation.tableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
/**
* {{table "name"}}
*
* @Author {{config "author"}}
* @Date {{now}}
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("{{table "name"}}")
@ApiModel(value="{{table "comment"}}实体类", description="{{table "name"}}")
public class {{table "name" | camelCase | title}} {
{{- range columns}}
    @ApiModelProperty(value = "{{.comment}}")
    @TableField("{{.name}}")
    private {{dbToJava .type}} {{camelCase .name}}{{";"}}
{{end -}}
}

示例2:🌰

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="{{config "base-package"}}.{{config "module"}}.{{refs "JavaMapper" "sub-package"}}.{{table "name" | camelCase | title}}{{refs "JavaMapper" "class-postfix"}}">
    <resultMap id="BaseResultMap" type="{{config "base-package"}}.{{config "module"}}.{{refs "JavaEntity" "sub-package"}}.{{table "name" | camelCase | title}}">
    {{range columns -}}
        {{"    "}}<id column="{{.name}}" jdbcType="{{dbToJDBC .type}}" property="{{camelCase .name}}" />
    {{end -}}
    </resultMap>
    <sql id="Base_Column_List">
    {{"    " -}}
    {{range $i,$v := columns -}}
        {{if ne $i 0}},{{end}}{{.name -}}
    {{end}}
    </sql>
</mapper>