简介

懒猴子CG是一个针对程序员的代码生成平台,旨在帮助程序员提高项目研发效率。在这里,你可以通过选择技术栈的方式来构建框架,你也可以选择一套项目模版来快速研发指定项目。 如果你需要通过自定义模版来规范项目或搭建一套自己的框架模板,建议你继续阅读此文档,我们也会不断完善和新增新的形式教程。

懒猴子CG经过一年半的发展,日趋稳定和强大,自2019年3月26日发布第一个版本以来,截止2020年7月18日已经发布了近20个大小版本,使用次数过万,已为用户生成了2000万行代码。当然,我们还有很多的不足,需要时间的沉淀和资金的支持以及更多人才的加入。2020年5月23日,懒猴子CG团队正式成立,我们有了专业的UI设计师,素材设计师,更有了更多的热情和规划。
在未来,懒猴子CG将尽可能的做到生你所想,码不停蹄。感谢新老用户的持续关注。

开始使用

  • 1 立即生成

    在模版或模版组页面,点击立即生成按钮,打开代码生成面板

  • 2 设置

    生成面板中包含设置(模版组)、模版、数据和预览四个模块

  • 3 生成代码

    点击右上角的生成代码按钮开始生成,成功后可预览生成结果

  • 4 下载代码

    代码生成后,点击右上角的下载按钮即可下载

制作模版

在制作模版前,你需要学习并掌握Freemarker中文手册
在懒猴子CG中,模版被划分为以下三类:
  • 普通模版:用于编写单个文件的生成逻辑,如Java实体类,页面等。
  • 框架模版:用于编写框架生成逻辑,结合全局属性可实现技术栈的自由组合。
  • 项目模版:用于编写项目生成逻辑,项目模版拥有更丰富的版本类型。
通过以上三种类型的模版,我们既可以实现项目的生成,也不会丢失生成实体类这样简单又普遍的需求。

属性

属性是代码生成器中的核心内容,如何划分属性决定代码模版能否灵活的获取数据。
懒猴子CG将属性划分为以下三层:
  • 内置属性:由平台提供的属性,如生成人的姓名、邮箱等。更多内容请查看内置属性
  • 全局属性:多个模版文件共享的属性,由用户自行定义。
  • 模版属性:模版文件自身的属性,模版自身可访问,也可以通过impt指令导入模版后访问。
属性的定义是有顺序的,后定义的属性可访问先定义的属性,我们可以将其视为变量来理解。 访问属性使用${propertyName}
以下三张图介绍了三种属性的使用方式:
  • 使用内置属性

  • 定义并使用全局属性

  • 定义并使用模版属性

模版依赖

在Java中,我们都会采用Controller->Service->Dao的方式来编写代码,这样Controller依赖了Service,Service依赖了Dao,我们视为代码文件的依赖,变换到模版之间就成了模版依赖。 为了解决这个问题,我们为模版设计了别名的概念,模版之间的依赖均通过别名来实现。下图展示了如何进行模版依赖,图中的Service.java模版别名为service。

元数据/表

在代码生成过程中通常我们需要根据表结构来生成,这些表结构我们称之为元数据。如果模版需要使用元数据,那么需要将生成周期设置为数据表,下图展示了如何使用元数据

生成周期

有时候我们并不希望根据数据表来生成代码文件,例如配置文件。因此我们增加了生成周期的概念。 目前系统中包含的周期有两种,分别是元数据周期组构建周期元数据周期会根据数据表的数量循环生成代码文件, 而组构建周期跟数据表无关,只会进行一次生成动作。需要注意的是,组构建周期只存在于模版组中。

数据类型

说明数据类型前,我们需要先思考一个问题。不同的语言拥有不同的数据类型定义,给你一个table,用哪门语言的数据类型来定义字段?假设你心中有了答案,那么如果换了数据库,类型匹配发生了变化又如何处理?为了灵活的进行各语言的数据类型转换,懒猴子CG内置了一套完整的数据类型,我们只需要将该套数据类型与我们的语言做类型映射即可。 那么你可能需要知道内置数据类型与各数据库的映射关系。我们整理后得到以下表格,请笑纳:

内置数据类型与各数据库的映射关系

内置数据类型 类型说明 MySQL Oracle
TEXT 文本/字符串 CHAR, VARCHAR, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT 暂无支持
NUMERIC 整数 TINYINT, SMALLINT, INT, INTEGER, BIGINT, NUMERIC, MEDIUMINT 暂无支持
DECIMAL 小数 FLOAT, DOUBLE, DECIMAL 暂无支持
DATE 日期 DATE 暂无支持
TIME 时间 TIME 暂无支持
DATETIME 日期+时间 DATETIME 暂无支持
TIMESTAMP 时间戳 TIMESTAMP 暂无支持
BYTES 字节 TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB 暂无支持
BOOLEAN 布尔 BIT 暂无支持
通过数据类型和字段长度,我们可以细致的划分出各个语言的数据类型。

数据类型映射

在阅读此篇内容前,请确保阅读并理解了数据类型。
以下列出了常用的数据类型映射模版代码,你可以通过copy指令来引入类型映射模版,然后调用模版提供的函数实现类型转换。我们以Java类型映射为例:

Java类型映射模版代码

<#function getJavaType row>
  <#assign originType=row.originType!'' />
  <#if row.type == 'CHAR'><#return "Character" /></#if>
  <#if row.type == 'TEXT'><#return "String" /></#if>
            <#if originType == 'TINYINT' && row.length == 1><#return "Boolean" /></#if>
          <#if originType == 'TINYINT'><#return "Byte" /></#if>
        <#if originType == 'INT' || originType == 'INTEGER'><#return "Integer" /></#if>
      <#if originType == 'BIGINT'><#return "Long" /></#if>
    <#if originType == 'NUMERIC'><#return "BigDecimal" /></#if>
  <#if row.type == 'NUMERIC'><#return "Integer" /></#if>
<#if row.type == 'DECIMAL'><#return "BigDecimal" /></#if>
<#if row.type == 'DATE'><#return "Date" /></#if>
<#if row.type == 'TIME'><#return "Time" /></#if>
<#if row.type == 'DATETIME'><#return "Date" /></#if>
<#if row.type == 'TIMESTAMP'><#return "Long" /></#if>
<#if row.type == 'BYTES'><#return "byte[]" /></#if>
<#if row.type == 'BOOLEAN'><#return "Boolean" /></#if>
<#return "String"/>
</#function>

Java类型对象导入模版代码

<#copy "java.getJavaType" />
<#function getImports datas>
  <#assign imports=""/>
  <#list datas as data>
      <#if getJavaType(data)== "Date" && imports?index_of("java.util.Date") == -1><#assign imports+="import java.util.Date;\n"/>
      <#elseif getJavaType(data) == "BigDecimal" && imports?index_of("java.math.BigDecimal") == -1><#assign imports+="import java.math.BigDecimal;\n"/>
      <#elseif getJavaType(data) == "Time" && imports?index_of("java.sql.Time") == -1><#assign imports+="import java.sql.Time;\n"/></#if>
  </#list>
<#return imports/>
</#function>
将以上代码加入到别名分别为java.getJavaTypejava.getImports的模版中,那么Getter/Setter实体类模版代码可以像下面这样编写
<#copy "java.getImports" />
<#copy "java.getJavaType" />
package ${package};

${getImports(_table.rows)}
/**
 * @author ${_author}
 * @date ${_yyyy}-${_MM}-${_dd} ${_HH}:${_mm}:${_ss}
 * @email ${_email}
 */
public class ${_fileName} {

  <#list _table.rows as row>
  <#if row.remark == "">
  private ${getJavaType(row)} ${row.name};
  <#else>
  // ${row.remark}
  private ${getJavaType(row)} ${row.name};
  </#if>

  </#list>
<#list _table.rows as row>
public ${getJavaType(row)} get${row.name?cap_first}() {
return ${row.name};
}

public void set${row.name?cap_first}(${getJavaType(row)} ${row.name}){
this.${row.name} = ${row.name};
}

</#list>
}

以下是MySQL JDBC类型映射模版代码

<#function getJdbcType row>
  <#if row.originType == 'INT' || row.originType == 'INTEGER' || row.originType == 'MEDIUMINT'>
    <#return 'INTEGER'/>
  </#if>
  <#if row.originType == 'FLOAT'>
    <#return 'REAL'/>
  </#if>
  <#if row.originType == 'DATETIME'>
  <#return 'TIMESTAMP'/>
</#if>
<#if row.originType == 'TEXT' || row.originType == 'MEDIUMTEXT' || row.originType == 'LONGTEXT'>
<#return 'LONGVARCHAR'/>
</#if>
<#if row.originType == 'BLOB' || row.originType == 'MEDIUMBLOB' || row.originType == 'LONGBLOB'>
<#return 'LONGVARBINARY'/>
</#if>
<#if row.originType == 'TINYBLOB'>
<#return 'BINARY'/>
</#if>
<#return row.originType />
</#function>

impt指令

在Java中,使用import实现一个类依赖另一个类。在freemarker也有对应的import指令来完成同样的事情,但这远远不够。我们希望直接通过别名来导入模版对象。 为了避免和原生freemarker的import指令冲突,我们采用了import的简写作为指令名称。在这里,一个模版依赖另一个模版你可以使用<#impt "模版别名" as model />。 除此之外,别名还能使用变量,如<#impt "${modelAlias}" as model />

copy & fork指令

copy和fork指令的作用是一样的,他们只做一件事情,那就是把另一个模版的内容拷贝(copy)至当前模版中,如果你喜欢用github,那么这就像github一样把内容叉(fork)到你本地。这样我们可以实现模版代码的复用, 便可以通过这种方式定义各个语言的数据类型转换模版,大大增加模版的利用率和维护便捷性。
<#copy "${modelAlias}" />

check指令

一套代码生成的逻辑难免会存在校验,比如验证表是否有主键,验证表是否缺少必要的字段,验证文件名称、路径等是否准确,然后给出相应的提示。这些校验,我们就可以通过check指令来实现。基本语法如下
<#check message="验证失败消息">false</#check>
当指令标签内容不为true时,则表示验证未通过,此时系统会弹出"验证失败消息"。

作者

变量名
_author
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
优先使用“代码作者”,如果没有则使用“昵称”

作者邮箱

变量名
_email
类型
String
默认值
""
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
登录后为操作用户的注册邮箱

作者手机号码

变量名
_mobile
类型
String
默认值
""
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
登录后为操作用户注册手机号

项目英文名称

变量名
_projectName
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
丢弃版本
true
生成模版组时为用户录入的项目名称,生成模版时始终为"codes"

项目英文名称

变量名
_project.enName
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.14.0

项目中文名称

变量名
_project.zhName
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.14.0

项目描述

变量名
_project.description
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.14.0

文件生成路径

变量名
_filePath
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
代码文件最终路径,不包含文件名

文件生成名称

变量名
_fileName
类型
String
默认值
"unknown"
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
代码文件名称,不包含文件后缀

文件生成全名称

变量名
_fullFileName
类型
String
默认值
"unknown"
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.10.0
代码文件名称,包含文件后缀

数据表名称

变量名
_table.name
类型
String
默认值
"unknown"
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当前正在生成的数据表名称(驼峰命名)

数据表原名称

变量名
_table.originName
类型
String
默认值
""
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当前正在生成的数据表原名称

数据表备注

变量名
_table.remark
类型
String
默认值
""
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当前正在生成的数据表备注

数据表字段数组

变量名
_table.rows
类型
Array
默认值
[]
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当前正在生成的数据表行数组

表字段名称

变量名
_table.rows[<index>].name
类型
String
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
将字段名称转换成驼峰命名后的表字段名称

表原字段名称

变量名
_table.rows[<index>].originName
类型
String
默认值
""
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为空

表字段类型

变量名
_table.rows[<index>].type
类型
String
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
表原字段类型对应的系统字段数据类型

表原字段类型

变量名
_table.rows[<index>].originType
类型
String
默认值
""
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为空

表字段长度

变量名
_table.rows[<index>].length
类型
Integer
默认值
0
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为0

表字段小数长度

变量名
_table.rows[<index>].decimal
类型
Integer
默认值
0
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为0

表字段是否为主键

变量名
_table.rows[<index>].isPrimaryKey
类型
Boolean
默认值
false
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为false

表字段是否自动增长

变量名
_table.rows[<index>].isAutoIncrement
类型
Boolean
默认值
false
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为false

表字段是否必填

变量名
_table.rows[<index>].required
类型
Boolean
默认值
false
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为false

表字段是否唯一

变量名
_table.rows[<index>].isUnique
类型
Boolean
默认值
false
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为false

表字段默认值

变量名
_table.rows[<index>].defaultValue
类型
String
默认值
NULL
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2
当采用非SQL语句导入的数据表时,该字段始终为"NULL"

表字段备注

变量名
_table.rows[<index>].remark
类型
String
默认值
""
周期
元数据周期
作用域
模版代码
加入版本
v1.4.2

表主键数组

变量名
_table.pks
类型
Array
默认值
[]
周期
元数据周期
作用域
模版代码
加入版本
v1.4.3
当前表的主键数组,数组中的对象与行对象数据格式一致

所有数据表

变量名
_tables
类型
Array
默认值
[]
周期
元数据周期、组构建周期
作用域
模版代码
加入版本
v1.4.2

年份(4位)

变量名
_yyyy
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间在哪一年(4位,如2020)

年份(2位)

变量名
_yy
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间在哪一年(2位,如20表示2020年)

月份

变量名
_MM
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间本年哪一月,从1开始计数

变量名
_dd
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间本月哪一天

周(在当前月中的第几周)

变量名
_weekOfMonth
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间在当月中的第几周

周(在当前年中的第几周)

变量名
_weekOfYear
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间在当前年中的第几周

时(24H)

变量名
_HH
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间在当天几时(24小时制)

时(12H)

变量名
_hh
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间在当天几时(12小时制)

变量名
_mm
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间(分)

变量名
_ss
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间(秒)

毫秒

变量名
_sss
类型
String
周期
元数据周期、组构建周期
作用域
模版代码、模版属性
加入版本
v1.0.0
生成时间(毫秒)