一、代码生成工具说明
1、说明
springboot+spring+SpringMVC+Mybatis+Mybatis-plus实现代码生成
2、生成器目录结构
主要生成如下文件,这些模板文件存放在 /resources下
3、创建文件结构
\resources\templates\${api_path}${base_path}api
\resources\templates\${services_path}${base_path}controller
\resources\templates\${services_path}${base_path}${biz_path}
\resources\templates\${services_path}${base_path}${biz_path}impl
\resources\templates\${test_path}${base_path}test
\resources\templates\${services_path}${base_path}mapper
\resources\templates\${resourse_path}
\resources\templates\${services_path}${base_path}converter
\resources\templates\${api_path}${base_path}vo
\resources\templates\${api_path}${base_path}dto
\resources\templates\${services_path}${base_path}entity
二、代码生成器项目构建
1、POM添加依赖
<!-- 代码生成工具 -->
<dependency>
<groupId>com.googlecode.rapid-framework</groupId>
<artifactId>rapid-generator</artifactId>
<version>4.0.6</version>
</dependency>
<!-- mysql数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<!-- 代码生成器扩展包 -->
<dependency>
<groupId>com.googlecode.rapid-framework</groupId>
<artifactId>rapid-generator-ext</artifactId>
<version>4.0.6</version>
</dependency>
<!-- 代码生成器模板,模板根目录通过 classpath:generator/template/rapid 可以引用 -->
<dependency>
<groupId>com.googlecode.rapid-framework</groupId>
<artifactId>rapid-generator-template</artifactId>
<version>4.0.6</version>
</dependency>
2、添加generator.xml配置文件
- 暂时只支持mysql数据库
- 文件放在resource文件夹下
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>
代码生成器配置文件:
1.会为所有的property生成property_dir属性,如pkg=com.company => pkg_dir=com/company
2.可以引用环境变量: ${env.JAVA_HOME} or System.properties: ${user.home},property之间也可以相互引用
</comment>
<entry key="author">liheng</entry>
<entry key="date">2021-06-18</entry>
<entry key="basepackage">cn.vipthink.icode.course</entry>
<!-- jsp namespace: web/${namespace}/${className}/list.jsp -->
<entry key="namespace">pages</entry>
<!-- 对应修改下Constants.Mybatis.NAMESPACE_PREFIX -->
<entry key="namespace_prefix">cn.vipthink.icore.course</entry>
<entry key="outRoot">E:\icode\vipthink-icode-course</entry>
<entry key="api_path">vipthink-icode-course-api\src\main\java</entry>
<entry key="services_path">vipthink-icode-course-service\src\main\java</entry>
<entry key="test_path">vipthink-icode-course-service\src\test\java</entry>
<entry key="resourse_path">vipthink-icode-course-service\src\main\resources\mapper</entry>
<entry key="biz_path">\service\</entry>
<entry key="base_path">\cn\vipthink\icode\course\</entry>
<!-- 需要移除的表名前缀,使用逗号进行分隔多个前缀,示例值: t_,v_ -->
<entry key="tableRemovePrefixes">bc_</entry>
<!-- 数据库类型映射 -->
<entry key="java_typemapping.java.sql.Timestamp">java.util.Date</entry>
<entry key="java_typemapping.java.sql.Date">java.util.Date</entry>
<entry key="java_typemapping.java.sql.Time">java.util.Date</entry>
<entry key="java_typemapping.java.lang.Byte">Integer</entry>
<entry key="java_typemapping.java.lang.Short">Integer</entry>
<entry key="java_typemapping.java.math.BigDecimal">Long</entry>
<!-- <entry key="jdbc_url">jdbc:mysql://127.0.0.1:3306/my_icode</entry>-->
<entry key="jdbc_url">jdbc:mysql://rm-wz9b4np52ucf5116d.mysql.rds.aliyuncs.com:3306/vipthink_icode</entry>
<entry key="jdbc_driver">com.mysql.jdbc.Driver</entry>
<entry key="jdbc_username">code_dev</entry>
<entry key="jdbc_password">i9JFq9CCuxueZNOLizuA</entry>
<!-- <entry key="jdbc_username">root</entry>-->
<!-- <entry key="jdbc_password">root</entry>-->
</properties>
3、添加日志配置文件log4j.properties
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
4、启动主类
@SpringBootApplication
public class CodeGeneratorApplication {
public static void main(String[] args) throws Exception {
//这里可以切换需要生成的表名
String[] tableNames = new String[]{"bc_learner_wechat"};
// 模板地址,这里可以切换模板
String templatePath = "classpath:simple_template";
GeneratorFacade g = new GeneratorFacade();
g.getGenerator().addTemplateRootDir(templatePath);
// 1、清空根路径下的文件
g.deleteOutRootDir();
// 1、通过数据库表生成文件 : 表名
for (String tableName : tableNames) {
g.generateByTable(tableName);
}
// 2、打开文件夹
Runtime.getRuntime().exec("cmd.exe /c start "+ GeneratorProperties.getRequiredProperty("outRoot"));
}
}
三、主要的模板类
第一部分:业务功能模板
${className}Api模板
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
package ${basepackage}.api;
import cn.vipthink.Result;
import cn.vipthink.common.model.PageResult;
import ${basepackage}.dto.${className}DTO;
import ${basepackage}.dto.${className}QueryDTO;
import ${basepackage}.vo.${className}VO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
/**
* ${className}管理接口
*
* @author happy-seed
*/
@Api("${className}管理相关接口")
@RequestMapping("/v1/${classNameLower}")
public interface ${className}Api {
/**
* 根据查询条件,分页查询${className}信息
*
* @param dto
* @return
*/
@ApiOperation("根据查询条件,分页查询${className}信息")
@GetMapping(value = "/list")
Result<PageResult<${className}VO>> queryPage(@ApiParam(value = "${className}查询对象") @RequestBody ${className}QueryDTO dto);
/**
* 根据 id 查询${className}信息
*
* @param id
* @return
*/
@ApiOperation("根据 id 查询${className}信息")
@GetMapping()
Result<${className}VO> get${className}ById(@ApiParam(value = "${classNameLower}Id") @PathVariable("id") Integer id);
/**
* 新增${className}
*
* @param dto
* @return
*/
@ApiOperation("新增${className}")
@PostMapping
Result<Boolean> add${className}(@RequestBody @Valid ${className}DTO ${classNameLower}DTO);
/**
* 删除${className}
*
* @param id
* @return
*/
@ApiOperation("删除${className}")
@DeleteMapping(value = "/{id}")
Result<Boolean> delete${className}ById(@ApiParam(value = "${classNameLower}Id") @PathVariable("id") Integer id);
/**
* 修改班期
*
* @param ${classNameLower}UpdateDTO 修改实体
* @return
*/
@ApiOperation(value = "修改${className}")
@PutMapping()
Result<Boolean> update(@Valid @RequestBody ${className}DTO ${classNameLower}DTO);
}
${className}Controller模板
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
package ${basepackage}.controller;
import cn.vipthink.Result;
import cn.vipthink.common.model.PageResult;
import ${basepackage}.api.${className}Api;
import ${basepackage}.dto.${className}DTO;
import ${basepackage}.dto.${className}QueryDTO;
import ${basepackage}.service.${className}Service;
import ${basepackage}.vo.${className}VO;
import cn.vipthink.icode.course.service.${className}Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List;
/**
* ${className} Controller 接口
* @author happy-seed
*/
@RestController
public class ${className}Controller implements ${className}Api {
@Autowired
private ${className}Service ${classNameLower}Service;
@Override
public Result<PageResult<${className}VO>> queryPage(${className}QueryDTO dto) {
return Result.success(${classNameLower}Service.queryPage(dto));
}
@Override
public Result<${className}VO> get${className}ById(Integer id) {
return Result.success(${classNameLower}Service.get${className}ById(id));
}
@Override
public Result<Boolean> add${className}(${className}DTO dto) {
return Result.success(${classNameLower}Service.add${className}(dto));
}
@Override
public Result<Boolean> delete${className}ById(Integer id) {
return Result.success(${classNameLower}Service.delete${className}ById(id));
}
@Override
public Result<Boolean> update(${className}DTO ${classNameLower}UpdateDTO) {
return Result.success(${classNameLower}Service.update${className}(${classNameLower}UpdateDTO));
}
}
${className}Service接口模板
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
package ${basepackage}.service;
import cn.vipthink.common.model.PageResult;
import com.baomidou.mybatisplus.extension.service.IService;
import ${basepackage}.entity.${className}DO;
import ${basepackage}.dto.${className}DTO;
import ${basepackage}.dto.${className}QueryDTO;
import ${basepackage}.vo.${className}VO;
import java.util.List;
/**
* ${classNameLower} Service 接口
*
* @author happy-seed
*/
public interface ${className}Service extends IService<${className}DO>{
/**
* 获取数据分页
* @param ${classNameLower}QueryDTO 查询参数
* @return PageResult
*/
PageResult<${className}VO> queryPage(${className}QueryDTO ${classNameLower}QueryDTO);
/**
* 新增数据
* @param ${classNameLower}DTO 新增参数
* @return Boolean
*/
Boolean add${className}(${className}DTO ${classNameLower}DTO);
/**
* 更新数据
* @param ${classNameLower}DTO 更新参数
* @return
*/
Boolean update${className}(${className}DTO ${classNameLower}DTO);
/**
* 删除数据
* @param id ID
* @return Boolean
*/
Boolean delete${className}ById(Integer id);
/**
* 根据 Id 查询数据
* @param id ID
* @return ${className}VO
*/
${className}VO get${className}ById(Integer id);
}
${className}ServiceImpl模板
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
package ${basepackage}.service.impl;
import cn.vipthink.common.model.PageResult;
import ${basepackage}.dto.${className}DTO;
import ${basepackage}.dto.${className}QueryDTO;
import ${basepackage}.entity.${className}DO;
import ${basepackage}.vo.${className}VO;
import ${basepackage}.mapper.${className}Mapper;
import ${basepackage}.service.${className}Service;
import ${basepackage}.converter.${className}Converter;
import cn.vipthink.icode.course.utils.PageUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
/**
* ${classNameLower} Service 业务实现类
*
* @author happy-seed
*/
@Slf4j
@Service
public class ${className}ServiceImpl extends ServiceImpl<${className}Mapper, ${className}DO> implements ${className}Service {
@Autowired
private ${className}Converter ${classNameLower}Converter;
@Override
public PageResult<${className}VO> queryPage(${className}QueryDTO dto) {
Page<${className}DO> ipage = new Page<>(dto.getCurrentPage(),dto.getPageSize());
${className}DO ${classNameLower}DO = ${classNameLower}Converter.convertQueryDto2Do(dto);
IPage<${className}DO> mpage = this.page(ipage, new LambdaQueryWrapper<>(${classNameLower}DO));
List<${className}DO> records = mpage.getRecords();
if(CollUtil.isEmpty(records)){
return PageResult.fail("没有找到你要查询的数据");
}
List<${className}VO> ${classNameLower}VOS = ${classNameLower}Converter.convertDo2VoList(records);
Page<${className}VO> resultPage = PageUtils.initPage(ipage, ${classNameLower}VOS);
return PageUtils.toPageResult(resultPage);
}
@Override
public ${className}VO get${className}ById(Integer id) {
return ${classNameLower}Converter.convertDo2Vo(this.getById(id));
}
@Override
public Boolean add${className}(${className}DTO ${classNameLower}Dto) {
${className}DO ${classNameLower}DO = ${classNameLower}Converter.convertDto2Do(${classNameLower}Dto);
return this.save(${classNameLower}DO);
}
@Override
public Boolean update${className}(${className}DTO ${classNameLower}Dto) {
${className}DO ${classNameLower}DO = ${classNameLower}Converter.convertDto2Do(${classNameLower}Dto);
return this.updateById(${classNameLower}DO);
}
@Override
public Boolean delete${className}ById(Integer id) {
return this.removeById(id);
}
}
${className}Mapper模板
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
package ${basepackage}.mapper;
import ${basepackage}.entity.${className}DO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* ${className}Mapper
*
* @author happy-seed
*/
@Mapper
public interface ${className}Mapper extends BaseMapper<${className}DO> {
}
${className}Mapper.xml模板
<#assign className = table.className>
<?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="${basepackage}.mapper.${className}Mapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="${basepackage}.entity.${className}DO">
<id column="${table.pkColumn.columnNameLower}" property="${table.pkColumn.columnNameLower}" />
<#list table.notPkColumns as column>
<result column="${column.sqlName}" property="${column.columnNameLower}" />
</#list>
</resultMap>
<!-- 通用查询结果 -->
<sql id="base_columns">
<#list table.columns as column> ${column.sqlName},</#list>
</sql>
</mapper>
${className}ServiceTest模板
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
package ${basepackage}.test;
import ${basepackage}.VipThinkICodeCourseApplication;
import ${basepackage}.entity.${className}DO;
import ${basepackage}.service.${className}Service;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
* ${classNameLower} ServiceTest
*
* @author happy-seed
*/
@Slf4j
@ExtendWith(SpringExtension.class)
@TestMethodOrder(MethodOrderer.Alphanumeric.class)
@SpringBootTest(classes = {VipThinkICodeCourseApplication.class})
public class ${className}ServiceTest {
@Autowired
private ${className}Service ${classNameLower}Service;
/**
* 测试新增数据
*/
@Test
public void testAdd(){
try {
${className}DO bean = new ${className}DO();
boolean save = ${classNameLower}Service.save(bean);
Assertions.assertTrue(save);
} catch (Exception e) {
log.error("单元测试出现异常!", e);
Assertions.assertTrue(true);
}
}
/**
* 测试查询数据
*/
@Test
public void testfindById(){
try {
${className}DO bean = ${classNameLower}Service.getById(1L);
Assertions.assertNotNull(bean);
} catch (Exception e) {
log.error("单元测试出现异常!", e);
Assertions.assertTrue(true);
}
}
/**
* 测试更新
*/
@Test
public void testUpdate(){
//测试直接更新
try {
${className}DO bean = new ${className}DO();
boolean b = ${classNameLower}Service.updateById(bean);
Assertions.assertTrue(b);
} catch (Exception e) {
log.error("单元测试出现异常!", e);
Assertions.assertTrue(true);
}
}
/**
* 测试逻辑删除
*/
@Test
public void testLogicDelete(){
try {
Assertions.assertTrue(${classNameLower}Service.removeById(1L));
} catch (Exception e) {
log.error("单元测试出现异常!", e);
Assertions.assertTrue(true);
}
}
}
${className}Converter
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
package ${basepackage}.converter;
import ${basepackage}.dto.${className}QueryDTO;
import ${basepackage}.entity.${className}DO;
import ${basepackage}.vo.${className}VO;
import ${basepackage}.dto.${className}DTO;
import org.mapstruct.Mapper;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* ${className}DO 转换类
*
* @author happy-seed
*/
@Component
@Mapper(componentModel = "spring")
public interface ${className}Converter {
/**
* convertAddDto2Do
* @param ${classNameLower}Dto 入参
* @return ${className}DO
*/
${className}DO convertDto2Do(${className}DTO ${classNameLower}Dto);
/**
* convertQueryDto2Do
* @param ${classNameLower}Dto 入参
* @return ${className}DO
*/
${className}DO convertQueryDto2Do(${className}QueryDTO ${classNameLower}Dto);
/**
* convertDo2Vo
* @param ${classNameLower}Do 入参
* @return ${className}VO
*/
${className}VO convertDo2Vo(${className}DO ${classNameLower}Do);
/**
* convertDo2VoList
* @param ${classNameLower}DoList 入参
* @return list
*/
List<${className}VO> convertDo2VoList(List<${className}DO> ${classNameLower}DoList);
}
第二部分:各种POJO模板
${className}DTO
<#assign className = table.className>
package ${basepackage}.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.time.LocalDateTime;
import java.io.Serializable;
/**
* <p>
*${className} 接口入参对象
* </p>
*
* @author happy-seed
*/
@Data
@ApiModel(value = "${className}DTO", description = "${className}DTO")
public class ${className}DTO implements Serializable {
private static final long serialVersionUID = 1L;
<#list table.columns as column>
<#if column.sqlName != "updated_time" && column.sqlName != "created_time"
&& column.sqlName != "updated_by" && column.sqlName != "created_by"
&& column.sqlName != "revision" && column.sqlName != "deleted">
/**
* ${column.columnAlias}
*/
@ApiModelProperty(value = "${column.columnAlias}")
<#if column.isDateTimeColumn>
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime ${column.columnNameLower};
<#else>
private ${column.simpleJavaType} ${column.columnNameLower};
</#if>
</#if>
</#list>
}
${className}QueryDTO
<#assign className = table.className>
package ${basepackage}.dto;
import ${basepackage}.page.PageRequest;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.Serializable;
/**
* <p>
* ${className} 查询 DTO 对象
* </p>
*
* @author happy-seed
*/
@Data
@ApiModel(value="${className}", description="${table.tableAlias}")
public class ${className}QueryDTO extends PageRequest implements Serializable{
private static final long serialVersionUID = 1L;
<#list table.columns as column>
<#if column.sqlName != "updated_time" && column.sqlName != "created_time"
&& column.sqlName != "updated_by" && column.sqlName != "created_by"
&& column.sqlName != "revision" && column.sqlName != "deleted">
/**
* ${column.columnAlias}
*/
@ApiModelProperty(value = "${column.columnAlias}")
<#if column.isDateTimeColumn>
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime ${column.columnNameLower};
<#else>
private ${column.simpleJavaType} ${column.columnNameLower};
</#if>
</#if>
</#list>
}
${className}VO
<#assign className = table.className>
package ${basepackage}.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
import java.io.Serializable;
/**
* <p>
* 接口返回 ${className}VO 对象
* </p>
*
* @author happy-seed
*/
@Data
public class ${className}VO implements Serializable {
private static final long serialVersionUID = 1L;
<#list table.columns as column>
<#if column.sqlName != "updated_time" && column.sqlName != "created_time"
&& column.sqlName != "updated_by" && column.sqlName != "created_by"
&& column.sqlName != "revision" && column.sqlName != "deleted">
/**
* ${column.columnAlias}
*/
@ApiModelProperty(value = "${column.columnAlias}")
<#if column.isDateTimeColumn>
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime ${column.columnNameLower};
<#else>
private ${column.simpleJavaType} ${column.columnNameLower};
</#if>
</#if>
</#list>
}
${className}DO
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
package ${basepackage}.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* ${className} 领域DO组件 ${table.tableAlias}
*
* @author happy-seed
*/
@Data
@TableName("${table.sqlName}")
public class ${className}DO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ${table.pkColumn.columnAlias}
*/
@TableId(value = "${table.pkColumn.columnNameLower}", type = IdType.AUTO)
private ${table.pkColumn.simpleJavaType} ${table.pkColumn.columnNameLower};
<#list table.notPkColumns as column>
/**
* ${column.columnAlias}
*/
<#if column.isDateTimeColumn>
<#if column.sqlName == "created_time">
@TableField(value = "created_time", fill = FieldFill.INSERT)
private LocalDateTime createdTime;
<#elseif column.sqlName == "updated_time">
@TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedTime;
<#else>
@TableField("${column.sqlName}")
private LocalDateTime ${column.columnNameLower};
</#if>
<#else>
<#if column.sqlName == "deleted">
@TableLogic
private Integer deleted;
<#elseif column.sqlName == "revision">
@Version
private Integer revision;
<#else>
@TableField("${column.sqlName}")
private ${column.simpleJavaType} ${column.columnNameLower};
</#if>
</#if>
</#list>
}
四、附录
1、读取Mysql数据库后的变量
## 数据表
${table.className} 表名对应类名-驼峰命名
${table.classNameFirstLower} 表名对应首字母小写类名
${table.sqlName} 表名
## 表字段
${table.pkColumn.simpleJavaType} 主键对应的类型
${table.pkColumn.columnName} 主键字段名
${table.pkColumn.columnNameLower} 对应字段首字母小写
${column.sqlName} 数据库中字段名
${column.columnName} 字段驼峰名
${column.columnAlias} 字段注释
${column.javaType} 字段类型
${column.simpleJavaType} 字段基础类型
${column.asType}
${column.constantName}
${column.columnNameLower} 字段驼峰命名,首字母小写
2、其他一些技巧
## generator.xml文件中定义的部分变量
${author} 内部使用的用户名
${date} 内部使用的时间,需要提前配置好
${basepackage} 基础的包名
## 需要移除的前缀
<entry key="tableRemovePrefixes">tb_</entry>
## 变量声明,将长变量设置成短变量
<#assign className = table.className>
<#assign classNameLower = className?uncap_first>
3、freemark简单语法
## 判断
<#list table.notPkColumns as column>
/*
* ${column.columnAlias}
*/
<#if column.isDateTimeColumn>
@TableField("${column.sqlName}")
private LocalDateTime ${column.columnNameLower};
<#else>
@TableField("${column.sqlName}")
private ${column.simpleJavaType} ${column.columnNameLower};
</#if>
</#list>
## 遍历
<#list table.notPkColumns as column>
// ... ....
</#list>
## 转义<#noparse>表示中间的字符不转义
<if test="null != limit">LIMIT <#noparse>#{</#noparse>limit<#noparse>} </#noparse></if>
<if test="null != start">OFFSET <#noparse>#{</#noparse>start<#noparse>} </#noparse></if>
或者:
<if test="null != limit">LIMIT #${r"{"}limit}</if>
<if test="null != start">OFFSET #${r"{"}start}</if>
五、部分源码分析
(1)Table类
//属性
String sqlName;//数据库对应表名
String remarks;//表备注
String className;//表对应驼峰命名
ColumnSet columns; //表的字段集合
List<Column> primaryKeyColumns; //表的主键集合
private String tableAlias; //表注释
//主要方法get方法
getPrimaryKeyColumns
getSqlName
getRemarks
(2)Column类
private Table _table;
private int _sqlType;
private String _sqlTypeName;
private String _sqlName;
private boolean _isPk;
private boolean _isFk;
private int _size;
private int _decimalDigits;
private boolean _isNullable;
private boolean _isIndexed;
private boolean _isUnique;
private String _defaultValue;
private String _remarks;