子曰:工欲善其事,必先利其器
在日常的项目开发中,经常会出现以下操作来实现业务逻辑:
- 创建数据库表对应的实体类
- 创建dao类用来操作数据库
- 编写xxxMapper.xml
- 创建service类用来实现业务逻辑
- 创建controller类用来处理接口请求和返回数据
- 把dao层对象注入到service层
- 把service层对象注入到controller层
- 大量重复的crud
- …等等
这些代码的重复度非常高,称之为模板代码。对于这种模板代码,我们可以使用代码生成工具来快速生成,提高生产效率,把更多精力放在更核心的业务逻辑上。
使用Mybatis-Plus代码生成工具来生成模板代码,有以下步骤:
一、引入依赖
<!-- 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.2.0</version>
</dependency>
<!-- freemarker模板引擎 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
二、编写代码生成器配置
package com.bin.generator;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.*;
public class CodeGenerator {
public static void main(String[] args) {
// 代码生成器
AutoGenerator autoGenerator = new AutoGenerator();
// ==================== 1、数据源配置 ====================
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl("jdbc:mysql://127.0.0.1:3306/spring-boot-example?useUnicode=true&useSSL=false&characterEncoding=utf8");
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("xxx");
dataSourceConfig.setPassword("xxxxxx");
// ==================== 2、全局配置 ====================
GlobalConfig globalConfig = new GlobalConfig();
// 获取当前项目目录
String projectPath = System.getProperty("user.dir");
// 设置文件输出目录
globalConfig.setOutputDir(projectPath + "/src/main/java");
globalConfig.setAuthor("bin-brother");
// 生成完文件之后自动打开文件夹
globalConfig.setOpen(true);
// globalConfig.setMapperName("%sDao");
// ==================== 3、包配置 ====================
PackageConfig packageConfig = new PackageConfig();
packageConfig.setModuleName(scanner("模块名"));
packageConfig.setParent("com.bin");
// ==================== 4、策略配置 ====================
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
strategyConfig.setRestControllerStyle(true);
strategyConfig.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategyConfig.setControllerMappingHyphenStyle(true);
// strategyConfig.setTablePrefix(packageConfig.getModuleName() + "_");
// ==================== 5、自定义配置 ====================
InjectionConfig injectionConfig = new InjectionConfig() {
@Override
public void initMap() {
Map<String, Object> map = new HashMap();
map.put("queryById", true);
this.setMap(map);
}
};
// 自定义输出配置
List<FileOutConfig> fileOutConfigList = new ArrayList<>();
fileOutConfigList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
return projectPath + "/src/main/resources/mapper/" + packageConfig.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
injectionConfig.setFileOutConfigList(fileOutConfigList);
// ==================== 6、模板配置 ====================
TemplateConfig templateConfig = new TemplateConfig();
// 指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
templateConfig.setController("/templates/controller.java");
templateConfig.setXml(null);
autoGenerator.setGlobalConfig(globalConfig);
autoGenerator.setDataSource(dataSourceConfig);
autoGenerator.setPackageInfo(packageConfig);
autoGenerator.setCfg(injectionConfig);
autoGenerator.setTemplate(templateConfig);
autoGenerator.setStrategy(strategyConfig);
autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
autoGenerator.execute();
}
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 + "!");
}
}
数据源配置
:配置数据源信息全局配置
:设置文件输出目录、生成完是否打开、文件的命名方式等等包配置
:设置模块名、父包名、各个层的包名等等策略配置
:设置需要包含的表名、表映射到实体的命名策略、表前缀等等策略自定义配置
:可以自定义一些参数注入到自己创建的代码模板中,通过{cfg.字段名}
取值。还可以指定模板文件输出到我的自定义文件中,即把原本生成在java目录下的xml改成输出到resources目录下。模板配置
:比如自定义一个controller模板,里面有你自定义的模板代码
三、编写自定义模板
package ${package.Controller};
import org.springframework.web.bind.annotation.RequestMapping;
<#if restControllerStyle>
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
/**
* @author ${author}
* @since ${date}
*/
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
<#if kotlin>
class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
<#else>
<#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass} {
<#else>
public class ${table.controllerName} {
</#if>
@Autowired
private ${table.serviceName} ${entity?uncap_first}Service;
<#if cfg.queryById>
@RequestMapping("/queryById/{id}")
public ${entity} queryById(@PathVariable("id") Integer id) {
return ${entity?uncap_first}Service.getById(id);
}
</#if>
}
</#if>
举个栗子,在这份模板代码中,我把对应的 service 层对象注入给 controller,然后我想在controller拟生成一个 queryById
接口,这个queryById
接口由 freemarker
的 <#if cfg.queryById>
标签判断要不要生成,这取决于我在模板配置中的 map.put("queryById", true)
,设置为true则表达式为真,则生成,false则不生成queryById接口。
// ==================== 5、自定义配置 ====================
InjectionConfig injectionConfig = new InjectionConfig() {
@Override
public void initMap() {
Map<String, Object> map = new HashMap();
map.put("queryById", true);
this.setMap(map);
}
};
四、执行代码生成器
执行完成之后,生成文件目录如下:
自定义的controller生成如下:
service类生成如下:
Mapper类生成如下:
一键运行,通通搞定。实际上还可以生成前端的html模板代码,只需要自定义html的模板,然后注入对应的属性即可。
更多详情配置参考官方文档:https://mp.baomidou.com/guide/generator.html