目录
简介
mybatis-plus是mybatis的升级版,在 mybatis 的基础上只做增强不做改变,主要目的是简化开发、提高开发效率。它内置通用的 Mapper与 Service,仅仅通过少量配置即可实现单表大部分 简单的CRUD 操作,还有强大的条件构造器,满足各类使用需求。即使涉及到咱们最头疼的表结构调整,只要没调整业务逻辑,也可以不用手动改变代码,只需从新使用generator生成一次即可。且其可以直接丢掉xml编写sql,直接在java代码中通过wrapper编写(个人不太支持非简单CRUD的sql写到代码,因为阅读维护成本高,dao层与service层耦合度高)。它支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库。使用generator可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,可自定义各层代码生成的模版。废话不多说了,开始撸代码。
一、maven依赖
<!-- MyBatis相关依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- mybatis-plus-generator模版依赖 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
二、编写generator代码生成器
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
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 com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MyBatisPlusGenerator {
//作者名
private static final String AUTHOR = "kevin";
//表table的前缀,不加到生成的类名中
private static final String PREFIX = "t_";
//功能模块名称,生成的文件会存放到模块下
private static final String MODULE_NAME = "test";
//要生成的表名
private static final String[] TABLES= {"想生成代码的表名"};
private static final String JDBC_URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8" +
"&useSSL=false&zeroDateTimeBehavior=convertToNull&";
private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
private static final String JDBC_USERNAME = "数据库用户名";
private static final String JDBC_PASSWORD = "数据库密码";
private static final String BASE_PACKAGE = "com.liu.test.mybatis.demo";
public static void main(String[] args) {
//当前项目路径
String projectPath = System.getProperty("user.dir");
// 代码生成器
AutoGenerator generator = new AutoGenerator();
//数据库配置
configDataSource(generator);
//全局配置
configGlobal(generator, projectPath);
//包相关配置
configPackage(generator);
//策略配置
configStrategy(generator);
//自定义配置
cofnigCustom(generator, projectPath);
//模版引擎配置
configTemplate(generator);
generator.execute();
}
/**
* 进行数据库相关配置
* @author kevin
* @param generator :
* @date 2021/2/8 13:27
*/
private static void configDataSource(AutoGenerator generator){
//数据源配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl(JDBC_URL);
dataSourceConfig.setDbType(DbType.MYSQL);
// dataSourceConfig.setSchemaName("public");
dataSourceConfig.setDriverName(JDBC_DRIVER);
dataSourceConfig.setUsername(JDBC_USERNAME);
dataSourceConfig.setPassword(JDBC_PASSWORD);
generator.setDataSource(dataSourceConfig);
}
/**
* 进行全局配置
* @author kevin
* @param generator :
* @param projectPath :
* @date 2021/2/8 13:28
*/
private static void configGlobal(AutoGenerator generator, String projectPath) {
// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
//生成文件输出存放路径 = 当前项目路径 + 想存放到项目中的路径
String fileOutputPatch = projectPath.concat("/src/main/java");
globalConfig.setOutputDir(fileOutputPatch);
//设置作者
globalConfig.setAuthor(AUTHOR);
//生成完后是否打开输出目录
globalConfig.setOpen(false);
//是否覆盖生成过的已有文件
globalConfig.setFileOverride(true);
//是否开启activeRecord模式
globalConfig.setActiveRecord(true);
// 是否在xml中添加二级缓存配置,默认false
globalConfig.setEnableCache(false);
// XML文件返回对象定义ResultMap
globalConfig.setBaseResultMap(true);
// XML返回对象字段列表columList
globalConfig.setBaseColumnList(true);
//设置主键字段类型
globalConfig.setIdType(IdType.INPUT);
//生成的文件名字定义,%s 会自动填充表实体属性
globalConfig.setMapperName("%sMapper");
globalConfig.setXmlName("%sMapper");
globalConfig.setEntityName("%s");
globalConfig.setServiceName("%sService");
globalConfig.setServiceImplName("%sServiceImpl");
globalConfig.setControllerName("%sController");
//开启 swagger2 模式,实体属性 Swagger2 注解,默认false
globalConfig.setSwagger2(true);
generator.setGlobalConfig(globalConfig);
}
/**
* 各个包配置
* @author kevin
* @param generator :
* @date 2021/2/8 13:34
*/
private static void configPackage(AutoGenerator generator) {
PackageConfig packageConfig = new PackageConfig();
packageConfig.setModuleName(MODULE_NAME);
packageConfig.setParent(BASE_PACKAGE);//包路径
packageConfig.setController("controller");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
packageConfig.setEntity("entity");
packageConfig.setMapper("mapper");
packageConfig.setXml("mapper");
generator.setPackageInfo(packageConfig);
}
/**
* 策略配置
* @author kevin
* @param generator :
* @date 2021/2/8 13:34
*/
private static void configStrategy(AutoGenerator generator) {
// 策略配置
StrategyConfig strategy = new StrategyConfig();
//全局大写命名
//strategy.setCapitalMode(true)
//全局下划线命名
//strategy.setDbColumnUnderline(true)
//表的前缀
strategy.setTablePrefix(PREFIX);
//表名下划线转为驼峰
strategy.setNaming(NamingStrategy.underline_to_camel);
//字段名下划线转为驼峰
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//生成哪些表
strategy.setInclude(TABLES);
strategy.setControllerMappingHyphenStyle(true);
//设置模版引擎的类型 freemarker使用ftl文件,velocity使用vm文件
generator.setTemplateEngine(new FreemarkerTemplateEngine());
// generator.setTemplateEngine(new VelocityTemplateEngine());
//是否使用lombok
strategy.setEntityLombokModel(true);
//设置是否restful控制器
strategy.setRestControllerStyle(true);
//设置布尔类型字段是否去掉is前缀
strategy.setEntityBooleanColumnRemoveIsPrefix(true);
// 自定义实体父类
// strategy.setSuperEntityClass("com.baomidou.demo.TestEntity");
// 自定义实体,公共字段
// strategy.setSuperEntityColumns(new String[] { "test_id", "age" });
// 自定义 mapper 父类
// strategy.setSuperMapperClass("com.baomidou.demo.TestMapper");
// 自定义 service 父类
// strategy.setSuperServiceClass("com.baomidou.demo.TestService");
// 自定义 service 实现类父类
// strategy.setSuperServiceImplClass("com.baomidou.demo.TestServiceImpl");
// 自定义 controller 父类
// strategy.setSuperControllerClass("com.baomidou.demo.TestController");
// 【实体】是否生成字段常量(默认 false)
// public static final String ID = "test_id";
// strategy.setEntityColumnConstant(true);
// 【实体】是否为构建者模型(默认 false)
// public User setName(String name) {this.name = name; return this;}
// strategy.setEntityBuilderModel(true);
generator.setStrategy(strategy);
}
/**
* 自定义配置
* @author kevin
* @param generator :
* @param projectPath :
* @date 2021/2/8 13:55
*/
private static void cofnigCustom(AutoGenerator generator, String projectPath) {
// 自定义配置
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.concat("/src/main/resources/mapper/").concat(MODULE_NAME).concat("/")
.concat(tableInfo.getEntityName()).concat("Mapper").concat(StringPool.DOT_XML);
}
});
/* cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录");
return false;
}
});*/
cfg.setFileOutConfigList(focList);
generator.setCfg(cfg);
}
/**
* 模版引擎配置
* @author kevin
* @param generator :
* @date 2021/2/8 13:59
*/
private static void configTemplate(AutoGenerator generator) {
//模板引擎配置 默认是VelocityTemplateEngine
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
generator.setTemplate(templateConfig);
}
}
其实这样配置后就可右键运行生成代码了,只不过是最原始的代码,模版是官方的默认模版。
run与debug都行。运行过后就会自动生成代码结构,如下图:
三、编写自己的模版
可自己编写模版,也可以复制默认模版出来进行调整。默认模版在mybatis-generator包下
根据自己使用的模版引擎来编写模版,比如本文使用的freemarker,则编写ftl模版文件。模版在项目中存放到resources目录下的templates目录中,如图:
1.实体类模版
package ${package.Entity};
<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if swagger2>
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
</#if>
<#if entityLombokModel>
import lombok.Data;
import lombok.EqualsAndHashCode;
<#if chainModel>
import lombok.experimental.Accessors;
</#if>
</#if>
import com.baomidou.mybatisplus.annotation.KeySequence;
/**
* ${table.comment!}
* @author ${author}
* @since ${date}
*/
<#if entityLombokModel>
@Data
<#if superEntityClass??>
@EqualsAndHashCode(callSuper = true)
<#else>
@EqualsAndHashCode(callSuper = false)
</#if>
<#if chainModel>
@Accessors(chain = true)
</#if>
</#if>
<#if table.convert>
@TableName("${table.name}")
</#if>
<#if swagger2>
@ApiModel(value="${entity}对象" <#if table.comment??>, description="${table.comment}"</#if>)
</#if>
@KeySequence(value="SEQ_${table.name?upper_case}", clazz = Integer.class)
<#if superEntityClass??>
public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
<#elseif activeRecord>
public class ${entity} extends Model<${entity}> {
<#else>
public class ${entity} implements Serializable {
</#if>
<#if entitySerialVersionUID>
private static final long serialVersionUID = 1L;
</#if>
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field>
<#if field.keyFlag>
<#assign keyPropertyName="${field.propertyName}"/>
</#if>
/**
* ${field.comment}
*/
<#if field.comment!?length gt 0>
<#if swagger2>
@ApiModelProperty(value = "${field.comment}")
</#if>
</#if>
<#if field.keyFlag>
<#-- 主键 -->
<#if field.keyIdentityFlag && idType??>
@TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
<#elseif field.keyIdentityFlag>
@TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
<#elseif field.convert>
@TableId("${field.annotationColumnName}")
</#if>
<#-- 普通字段 -->
<#elseif field.fill??>
<#-- ----- 存在字段填充设置 ----->
<#if field.convert>
@TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
<#else>
@TableField(fill = FieldFill.${field.fill})
</#if>
<#elseif field.convert>
@TableField("${field.annotationColumnName}")
</#if>
<#-- 乐观锁注解 -->
<#if (versionFieldName!"") == field.name>
@Version
</#if>
<#-- 逻辑删除注解 -->
<#if (logicDeleteFieldName!"") == field.name>
@TableLogic
</#if>
private ${field.propertyType} ${field.propertyName};
</#list>
<#------------ END 字段循环遍历 ---------->
<#if !entityLombokModel>
<#list table.fields as field>
<#if field.propertyType == "boolean">
<#assign getprefix="is"/>
<#else>
<#assign getprefix="get"/>
</#if>
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
<#if chainModel>
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
<#else>
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
</#if>
this.${field.propertyName} = ${field.propertyName};
<#if chainModel>
return this;
</#if>
}
</#list>
</#if>
<#if entityColumnConstant>
<#list table.fields as field>
public static final String ${field.name?upper_case} = "${field.name}";
</#list>
</#if>
<#if activeRecord>
@Override
protected Serializable pkVal() {
<#if keyPropertyName??>
return this.${keyPropertyName};
<#else>
return null;
</#if>
}
</#if>
<#if !entityLombokModel>
@Override
public String toString() {
return "${entity}{" +
<#list table.fields as field>
<#if field_index==0>
"${field.propertyName}=" + ${field.propertyName} +
<#else>
", ${field.propertyName}=" + ${field.propertyName} +
</#if>
</#list>
"}";
}
</#if>
}
2.控制层controller模版
package ${package.Controller};
import ${package.Entity}.${entity};
import ${package.Service}.${table.serviceName};
<#if swagger2>
import io.swagger.annotations.ApiOperation;
</#if>
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
<#if restControllerStyle>
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
/**
* <p>
* ${table.comment!} 控制层
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName?? && 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} ${table.serviceName?lower_case};
<#if restControllerStyle>
@GetMapping("/list")
</#if>
<#if swagger2>
@ApiOperation(value = "${table.comment}列表查询",notes = "list")
</#if>
public List<${entity}> list(){
return ${table.serviceName?lower_case}.list();
}
<#if restControllerStyle>
@GetMapping("/get")
</#if>
<#if swagger2>
@ApiOperation(value = "${table.comment}详情查询",notes = "get")
</#if>
public ${entity} get(String id){
return ${table.serviceName?lower_case}.getById(id);
}
<#if restControllerStyle>
@PostMapping("/save")
</#if>
<#if swagger2>
@ApiOperation(value = "${table.comment}保存",notes = "save")
</#if>
public void save(${entity} ${entity?lower_case}){
${table.serviceName?lower_case}.save(${entity?lower_case});
}
<#if restControllerStyle>
@DeleteMapping("/delete")
</#if>
<#if swagger2>
@ApiOperation(value = "${table.comment}删除",notes = "delete")
</#if>
public void delete(List<String> ids){
${table.serviceName?lower_case}.removeByIds(ids);
}
}
</#if>