MyBatis-Plus代码生成器所需jar包:
<!--逆向生成代码-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1</version>
</dependency>
<!--逆向生成代码模版-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
本地配置好的MyBatis-Plus代码生成器
/**
* 代码生成器
*/
public class CodeGeneratorV2 {
//数据库连接url
private static String url = "jdbc:mysql://192.168.118.130:3306/book_store?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8";
//mysql驱动
private static String driverName = "com.mysql.jdbc.Driver";
//mysql账号
private static String userName = "root";
//mysql密码
private static String password = "root";
//项目路径
private static String projectPackage = "com.gdky.book";
public static void main(String[] args) {
// 代码生成器
AutoGenerator autoGenerator = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor(System.getProperty("user.name"));
gc.setOpen(false);
//是否开启Swagger2注解
// gc.setSwagger2(true); 实体属性 Swagger2 注解
autoGenerator.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl(url);
// dsc.setSchemaName("public");
dsc.setDriverName(driverName);
dsc.setUsername(userName);
dsc.setPassword(password);
autoGenerator.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent(projectPackage);
autoGenerator.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
// cfg.setFileCreate(new IFileCreate() {
// @Override
// public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// // 判断自定义文件夹是否需要创建
// checkDir("调用默认方法创建的目录");
// return false;
// }
// });
cfg.setFileOutConfigList(focList);
autoGenerator.setCfg(cfg);
// 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改,
// 放置自己项目的 src/main/resources/templates 目录下, 默认名称一下可以不配置,也可以自定义模板名称
// 配置模板
TemplateConfig tc = new TemplateConfig();
//配置自定义的模板
tc.setController("/codetemplates/controller.java");
tc.setService("/codetemplates/service.java");
tc.setServiceImpl("/codetemplates/serviceImpl.java");
tc.setEntity("/codetemplates/entity.java");
tc.setXml(null);
autoGenerator.setTemplate(tc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
// strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
// 写于父类中的公共字段
// strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
// strategy.setTablePrefix(pc.getModuleName() + "_");
autoGenerator.setStrategy(strategy);
//指定使用Freemarker模板引擎
autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
// mpg.setTemplateEngine(new BeetlTemplateEngine());
autoGenerator.execute();
}
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
}
在配置文件中:创建对应的模板
controller模板:
package ${package.Controller};
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gdky.book.common.entity.Result;
/**
* ${entity} 前端控制器
*
* @author ${author}
* @since ${date}
*/
@RestController
@RequestMapping("/${table.entityPath}")
public class ${entity}Controller {
@Autowired
private ${table.serviceName} ${table.entityPath}Service;
/***
* 无分页查询${entity}数据列表
* @param ${table.entityPath}
* @return
*/
@PostMapping(value = "/getList" )
public Result<List<${entity}>> getList(@RequestBody ${entity} ${table.entityPath}){
LambdaQueryWrapper<${entity}> queryWrapper = ${table.entityPath}Service.buildLambdaQueryWrapper(${table.entityPath});
List<${entity}> list = ${table.entityPath}Service.list(queryWrapper);
return new Result(list);
}
/**
* 分页查询${entity}数据
* @param ${table.entityPath}
* @Param pageNum 页数
* @Param pageSize 每页大小
* @return
*/
@PostMapping("/getPage")
public Result<Page<${entity}>> getPage(Integer pageNum,Integer pageSize,@RequestBody ${entity} ${table.entityPath}){
LambdaQueryWrapper<${entity}> queryWrapper = ${table.entityPath}Service.buildLambdaQueryWrapper(${table.entityPath});
Page<${entity}> page = ${table.entityPath}Service.page(new Page(pageNum,pageSize),queryWrapper);
return new Result(page);
}
/***
* 新增/修改${entity}数据(id为空:新增,不为空:修改)
* @param ${table.entityPath}
* @return
*/
@PostMapping(value="/addOrUpdate")
public Result addOrUpdate(@RequestBody ${entity} ${table.entityPath}){
if(${table.entityPath}.getId() == null){
${table.entityPath}Service.save(${table.entityPath});
}else{
${table.entityPath}Service.updateById(${table.entityPath});
}
return Result.ok();
}
/***
* 根据编号获取${table.entityPath}详情数据
* @param code
* @return
*/
@PostMapping(value="/getInfo")
public Result getInfo(String code){
${entity} ${table.entityPath} = ${table.entityPath}Service.getByCode(code);
return new Result(${table.entityPath});
}
}
service模板:
package ${package.Service};
import ${package.Entity}.${entity};
import ${superServiceClassPackage};
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
/**
* <p>
* ${table.comment!} 服务类
* </p>
*
* @author ${author}
* @since ${date}
*/
public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
/**
* 根据code获取${entity}
*/
${entity} getByCode(String code);
/**
* 使用lambda表达式构建查询条件
*/
LambdaQueryWrapper<${entity}> buildLambdaQueryWrapper(${entity} ${table.entityPath});
}
serviceImpl模板:
package ${package.ServiceImpl};
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
import ${superServiceImplClassPackage};
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
/**
* ${table.serviceImplName} 服务实现类
*
* @author ${author}
* @since ${date}
*/
@Service
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
@Autowired
private ${table.mapperName} ${table.entityPath}Mapper;
/**
* 根据code获取${entity}
*/
public ${entity} getByCode(String code){
return this.getOne(new QueryWrapper<${entity}>().eq("", code));
}
/**
* ${entity}使用lambda构建查询对象
* @param ${table.entityPath}
* @return
*/
public LambdaQueryWrapper<${entity}> buildLambdaQueryWrapper(${entity} ${table.entityPath}){
LambdaQueryWrapper<${entity}> lambdaQueryWrapper = new LambdaQueryWrapper<>();
<#list table.fields as md>
// ${md.propertyName} : ${md.comment}
if(!StringUtils.isEmpty(${table.entityPath}.get${md.propertyName ? cap_first}())){
<#if (md.propertyName?contains("title") || md.propertyName?contains("name"))>
lambdaQueryWrapper.like(${table.entityName}::get${md.propertyName ? cap_first},${table.entityPath}.get${md.propertyName ? cap_first}());
<#else>
lambdaQueryWrapper.eq(${table.entityName}::get${md.propertyName ? cap_first},${table.entityPath}.get${md.propertyName ? cap_first}());
</#if>
}
</#list>
return lambdaQueryWrapper;
}
}
entity模板:
这里只是在原有模板的基础上加上了以下判断:
<#if (field.propertyType == 'LocalDateTime')>
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date ${field.propertyName};
<#else>
private ${field.propertyType} ${field.propertyName};
</#if>
以上便是自定义模板的所有内容。
总结:
1.从数据库中获取的字段和对应字段的数据。
以sys_user表为例:
${entity} :SysUser;
${package.Entity} :SysUser所在的包;
${table.entityPath} : sysUser;
${table.serviceName} :ISysUserService;
${package.Service} :ISysUserService所在的包;
在AbstractTemplateEngine的getObjectMap方法可以看到对应的属性:
public Map<String, Object> getObjectMap(TableInfo tableInfo) {
Map<String, Object> objectMap = new HashMap<>(30);
ConfigBuilder config = getConfigBuilder();
if (config.getStrategyConfig().isControllerMappingHyphenStyle()) {
objectMap.put("controllerMappingHyphenStyle", config.getStrategyConfig().isControllerMappingHyphenStyle());
objectMap.put("controllerMappingHyphen", StringUtils.camelToHyphen(tableInfo.getEntityPath()));
}
objectMap.put("restControllerStyle", config.getStrategyConfig().isRestControllerStyle());
objectMap.put("config", config);
objectMap.put("package", config.getPackageInfo());
GlobalConfig globalConfig = config.getGlobalConfig();
objectMap.put("author", globalConfig.getAuthor());
objectMap.put("idType", globalConfig.getIdType() == null ? null : globalConfig.getIdType().toString());
objectMap.put("logicDeleteFieldName", config.getStrategyConfig().getLogicDeleteFieldName());
objectMap.put("versionFieldName", config.getStrategyConfig().getVersionFieldName());
objectMap.put("activeRecord", globalConfig.isActiveRecord());
objectMap.put("kotlin", globalConfig.isKotlin());
objectMap.put("swagger2", globalConfig.isSwagger2());
objectMap.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
objectMap.put("table", tableInfo);
objectMap.put("enableCache", globalConfig.isEnableCache());
objectMap.put("baseResultMap", globalConfig.isBaseResultMap());
objectMap.put("baseColumnList", globalConfig.isBaseColumnList());
objectMap.put("entity", tableInfo.getEntityName());
objectMap.put("entitySerialVersionUID", config.getStrategyConfig().isEntitySerialVersionUID());
objectMap.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
objectMap.put("entityBuilderModel", config.getStrategyConfig().isEntityBuilderModel());
objectMap.put("entityLombokModel", config.getStrategyConfig().isEntityLombokModel());
objectMap.put("entityBooleanColumnRemoveIsPrefix", config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix());
objectMap.put("superEntityClass", getSuperClassName(config.getSuperEntityClass()));
objectMap.put("superMapperClassPackage", config.getSuperMapperClass());
objectMap.put("superMapperClass", getSuperClassName(config.getSuperMapperClass()));
objectMap.put("superServiceClassPackage", config.getSuperServiceClass());
objectMap.put("superServiceClass", getSuperClassName(config.getSuperServiceClass()));
objectMap.put("superServiceImplClassPackage", config.getSuperServiceImplClass());
objectMap.put("superServiceImplClass", getSuperClassName(config.getSuperServiceImplClass()));
objectMap.put("superControllerClassPackage", verifyClassPacket(config.getSuperControllerClass()));
objectMap.put("superControllerClass", getSuperClassName(config.getSuperControllerClass()));
return Objects.isNull(config.getInjectionConfig()) ? objectMap : config.getInjectionConfig().prepareObjectMap(objectMap);
}
可在以上的方法中找到对应属性,比如 e n t i t y 在 {entity} 在 entity在{table}中:
public class TableInfo {
private final Set<String> importPackages = new HashSet<>();
private boolean convert;
//对应表名:如:sys_user
private String name;
//对应表的说明:
private String comment;
//对应表名对应的javabean:如:SysUser
private String entityName;
//对应表名对应的mapper:如:SysUserMapper
private String mapperName;
//对应表名对应的mapper对应xml名称:如:SysUserMapper
private String xmlName;
//对应表名对应的service:如:ISysUserService
private String serviceName;
//对应表名对应的serviceImpl:如:SysUserServiceImpl
private String serviceImplName;
//对应表名对应的controller:如:SysUserController
private String controllerName;
//该表中对应的具体字段
private List<TableField> fields;
/**
* 公共字段
*/
private List<TableField> commonFields;
//对应表中所有字段的名称:如:
//id, user_code, account, password, salt, username, head_image, mail, phone, role_code, create_time
private String fieldNames;
//省略了部分代码
...
}
TableField:(对应一张表中的字段),propertyType 为拓展字段,对应java中字段的类型
public class TableField {
private boolean convert;
private boolean keyFlag;
/**
* 主键是否为自增类型
*/
private boolean keyIdentityFlag;
//对应表中的字段:如:user_code
private String name;
//对应表中的字段的类型和长度:如:varchar(20)
private String type;
//对应转换后的符合驼峰规则的字段:如:userCode
private String propertyName;
//对应java中的数据类型:如:STRING
private IColumnType columnType;
//对应数据库中字段的说明:如:用户编号
private String comment;
private String fill;
/**
* 自定义查询字段列表
*/
private Map<String, Object> customMap;
}
2.FreeMarker简单的语法:
2.1 表达式取值:${entity} ;
2.2 逻辑判断:if…else
<#if (md.propertyName?contains("title") || md.propertyName?contains("name"))>
//为true,do something
<#else>
//为false,do otherthing
</#if>
2.3 循环:
空值判断:<#if UserList?size = 0></#if>
<#list table.fields as md>
// do something
</#list>