我们已讲解了MyBatis-Plus的几个核心功能,本章节我们再给各位同伴们讲解一个核心功能-代码生成器AutoGenerator。
AutoGenerator是MyBatis-Plus的代码生成器,通过AutoGenerator可以快速生成Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
我们在项目中新建CodeGenerator 类,将官网的生成器代码复制进来。
public class CodeGenerator {
/**
*
* 读取控制台内容
*
*/
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 + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("jobob");
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("密码");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.baomidou.ant");
mpg.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 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);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setSuperEntityClass("com.baomidou.ant.common.BaseEntity");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
strategy.setSuperControllerClass("com.baomidou.ant.common.BaseController");
// 写于父类中的公共字段
strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
MyBatis-Plus 从 3.0.3
之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖,我们MyBatis-Plus当前版本为3.1.2,生成器版本保持一致:
com.baomidou
mybatis-plus-generator
3.1.2
添加模板引擎依赖,MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎,我们以freemarker模板引擎进行讲解,故这里导入freemarker ja包依赖:
org.freemarker
freemarker
2.3.29
依赖加入后,我们先将代码相关类手动导入下。再对数据源以及相关包名进行配置以及注释掉不需要代码。简单配置下后,我们来测试下看看是否可以生成我们所需要的代码。启动main方法,启动后在控制台提示我们输入模块名,回车后再输入表名,多张表以逗号分割,以这些表进行映射,生成相关代码。
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:C:\Program
请输入模块名:
temp
请输入表名,多个英文逗号分割:
t_sys_log
我们输入以上信息后回车,可以看控制台打印生成代码的目录及模板信息
20:22:44.811 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================准备生成文件...==========================
20:22:45.284 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 创建目录: [E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\entity]
20:22:45.285 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 创建目录: [E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\controller]
20:22:45.287 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 创建目录: [E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\service]
20:22:45.289 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 创建目录: [E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\mapper]
20:22:45.289 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 创建目录: [E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\service\impl]
20:22:45.469 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/entity.java.ftl; 文件:E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\entity\TSysLog.java
20:22:45.474 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/mapper.java.ftl; 文件:E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\mapper\TSysLogMapper.java
20:22:45.479 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/service.java.ftl; 文件:E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\service\ITSysLogService.java
20:22:45.482 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/serviceImpl.java.ftl; 文件:E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\service\impl\TSysLogServiceImpl.java
20:22:45.488 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/controller.java.ftl; 文件:E:\ideaproject\boot/src/main/java\com\banxun\demo\temp\controller\TSysLogController.java
20:22:45.488 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================文件生成完成!!!==========================
Process finished with exit code 0
再来看下项目,我们发现在配置的包下生成了我们刚输入的temp模块,以及模块里的controller、entity、mapper、service以及service实现等类。
我们发现生成的代码与类名等信息不是我们想要的,我们需要对生成代码器进行定制。MyBatis-Plus的代码生成器提供了大量的自定义参数供用户选择,能够满足绝大部分人的使用需求。接下来,我们对代码生成器的几个主要类的配置参数进行讲解。
//生成文件的输出目录
private String outputDir = "D://";
//是否覆盖已有文件 默认值:false
private boolean fileOverride = false;
//是否打开输出目录 默认值:true
private boolean open = true;
//是否在生成xml文件中添加二级缓存配置
private boolean enableCache = false;
//开发人员信息
private String author;
//开启 Kotlin 模式
private boolean kotlin = false;
开启 swagger2 模式
private boolean swagger2 = false;
//开启 ActiveRecord 模式
private boolean activeRecord = false;
//是否在生成xml文件中生成属性与字段的映射
private boolean baseResultMap = false;
//时间类型对应策略 默认值:TIME_PACK即生成的entity时间类型默认为JDK8 time包里时间类,如果需要util时间类,可设为ONLY_DATE
private DateType dateType;
//是否在生成xml文件中生成baseColumnList
private boolean baseColumnList;
//entity类名 例如:%sEntity 生成 UserEntity %s为点位符,取配置后的表名
private String entityName;
//mapper接口名
private String mapperName;
//xml映射文件名
private String xmlName;
//servicer接口名
private String serviceName;
//service实现类名
private String serviceImplName;
//controller类名
private String controllerName;
//指定生成的主键的ID类型
private IdType idType;
DataSourceConfig是对数据源进行相关配置,我们来看下该类的配置属性
//数据库信息查询类
//默认由dbType类型决定选择对应数据库内置实现
//实现IDbQuery接口自定义数据库查询 SQL语句定制化返回自己需要的内容
private IDbQuery dbQuery;
//数据库类型
//可以不用设置,未设置则自动根据数据库驱动类或连接地址识别
private DbType dbType;
//数据库 schema name
private String schemaName;
//类型转换 可以自定义实体属性类型与表字段类型转换
private ITypeConvert typeConvert;
//数据库连接地址
private String url;
//数据库驱动类
private String driverName;
//数据库用户名
private String username;
//数据库密码
private String password;
PackageConfig是对生成类与接口的包路径进行相关配置,我们来看下该类的配置属性
//父包名
//如果为空,将下面子包名必须写全部, 否则就只需写子包名 如com.banxue.demo
private String parent = "com.baomidou";
//父包模块名 如系统模块 sys,可以不配置
private String moduleName = null;
//实体类所在包名, 实体类最终所在包路径为 parent+moduleName+entity
private String entity = "entity";
//Service包名
private String service = "service";
//Service实现类包名
private String serviceImpl = "service.impl";
//Mapper接口包名
private String mapper = "mapper";
//Mapper xml映射文件包名
private String xml = "mapper.xml";
//Controller包名
private String controller = "controller";
// 路径配置信息
private Map pathInfo;
各位同伴应该看到以上属性名都好理解,可能不明白路径配置信息pathInfo的使用。这个是Map集合,那么集合里又放什么。我们来看这个属性的作用。
通过打断点,我们点位到这个属性是在ConfigBuilder类有判断pathInfo是否为空。
private void handlerPackage(TemplateConfig template, String outputDir, PackageConfig config) {
this.packageInfo = new HashMap(8);
this.packageInfo.put("ModuleName", config.getModuleName());
this.packageInfo.put("Entity", this.joinPackage(config.getParent(), config.getEntity()));
this.packageInfo.put("Mapper", this.joinPackage(config.getParent(), config.getMapper()));
this.packageInfo.put("Xml", this.joinPackage(config.getParent(), config.getXml()));
this.packageInfo.put("Service", this.joinPackage(config.getParent(), config.getService()));
this.packageInfo.put("ServiceImpl", this.joinPackage(config.getParent(), config.getServiceImpl()));
this.packageInfo.put("Controller", this.joinPackage(config.getParent(), config.getController()));
Map configPathInfo = config.getPathInfo();
//判断pathInfo属性是为null,不为null则只pathInfo里的配置
if (null != configPathInfo) {
this.pathInfo = configPathInfo;
} else {
this.pathInfo = new HashMap(6);
this.setPathInfo(this.pathInfo, template.getEntity(this.getGlobalConfig().isKotlin()), outputDir, "entity_path", "Entity");
this.setPathInfo(this.pathInfo, template.getMapper(), outputDir, "mapper_path", "Mapper");
this.setPathInfo(this.pathInfo, template.getXml(), outputDir, "xml_path", "Xml");
this.setPathInfo(this.pathInfo, template.getService(), outputDir, "service_path", "Service");
this.setPathInfo(this.pathInfo, template.getServiceImpl(), outputDir, "service_impl_path", "ServiceImpl");
this.setPathInfo(this.pathInfo, template.getController(), outputDir, "controller_path", "Controller");
}
}
private void setPathInfo(Map pathInfo, String template, String outputDir, String path, String module) {
//pathInfo元素拼接了生成文件的输出目录,自定义pathInfo元素需手动添加输出目录
if (StringUtils.isNotEmpty(template)) {
pathInfo.put(path, this.joinPath(outputDir, (String)this.packageInfo.get(module)));
}
}
通过测试,这里直接给下使用方式:
pathInfo可定制各类的包路径,如果给pathInfo集合赋值,财PackageConfig其他包属性的设值则无效。如果我们只想生成entity实体,则在pathInfo配置一个元素:
map.put("entity_path", "E:/ideaplace/demo/src/main/java/com.banxue.demo.sys");
注意,这里需要生成文件完整的包路径,并且元素key名分别为entity_path、mapper_path、xml_path、service_pathservice_impl_path、controller_path
//entity java实体类模板所在路径
private String entity = "/templates/entity.java";
//entity Kotin实体类模板所在路径
private String entityKt = "/templates/entity.kt";
//servicey接口模板所在路径
private String service = "/templates/service.java";
//service实现类模板所在路径
private String serviceImpl = "/templates/serviceImpl.java";
//mapper接口模板所在路径
private String mapper = "/templates/mapper.java";
//xml映射文件模板所在路径
private String xml = "/templates/mapper.xml";
//controller类模板所在路径
private String controller = "/templates/controller.java";
MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎,继续AbstractTemplateEngine抽象类。如果您选择了非默认引擎,需要在 AutoGenerator 中 设置模板引擎。
AutoGenerator mpg = new AutoGenerator();
mpg.setTemplateEngine(new XXXTemplateEngine()); //自定义的模板引擎
生成器jar包里已配置支持各类模板引擎模板
如我们需要自定义代码生成的模板,实现个性化操作,只需要将我们对应模板引擎的默认模板复制一份放入项目资源文件下。例如,我们前面已经配置了freemarkerjar依赖,接着在resources下新建freemarker目录,将默认模板entity.java.ftl文件复制进去,并对模板文件进行更改我们所需要的。
自定义模板不需要模板文件后缀如.ftl,生成器会根据模板引擎自动识别
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setEntity("/freemarker/entity.java");
mpg.setTemplate(templateConfig);
通过该配置,可注入自定义参数等操作以实现个性化操作
//配置构建类,里面可以生成器所需要的配置信息
private ConfigBuilder config;
//自定义返回配置 Map 对象
//该对象可以传递到模板引擎通过 cfg.xxx 引用
private Map map;
//自定义输出文件
//配置 FileOutConfig 指定模板文件、输出文件达到自定义文件生成目的
private List fileOutConfigList;
//自定义判断是否创建文件 实现 IFileCreate 接口
//该配置用于判断某个类是否需要覆盖创建,当然你可以自己实现差异算法 merge 文件
private IFileCreate fileCreate;
//注入自定义 Map 对象(注意需要setMap放进去)
public abstract void initMap();
默认方法initMap可以让我们自定义属性并注入在.ftl(或者是.vm)模板中,通过${cfg.属性名}获取属性值
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
Map map = new HashMap<>();
map.put("email", "[email protected]");
//setMap进去
this.setMap(map);
}
};
我们还可以通过fileOutConfigList将自定义的模板输出到指定的路径
// 复制默认模板进行个性修改
String templatePath = "/templates/mapper.xml.ftl";
// 自定义输出配置
List 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.setFileOutConfigList(focList);
//是否大写命名
private boolean isCapitalMode = false;
//是否跳过视图
private boolean skipView = false;
//命名转换
private INameConvert nameConvert;
//数据库表映射到实体的命名策略
private NamingStrategy naming;
//数据库表字段映射到实体的命名策略, 未指定按照 naming 执行
private NamingStrategy columnNaming;
//表前缀
private String[] tablePrefix;
//字段前缀
private String[] fieldPrefix;
//自定义继承的Entity类全称,带包名
private String superEntityClass;
//自定义基础的Entity类,公共字段
private String[] superEntityColumns;
//自定义继承的Mapper类全称,带包名
private String superMapperClass;
//自定义继承的Service类全称,带包名
private String superServiceClass;
//自定义继承的ServiceImpl类全称,带包名
private String superServiceImplClass;
//自定义继承的Mapper类全称,带包名
private String superControllerClass;
//需要包含的表名,允许正则表达式(与exclude二选一配置)
private String[] include;
//需要排除的表名,允许正则表达式
private String[] exclude;
//entity实体类是否继承Serialable接口
private boolean entitySerialVersionUID;
//【实体】是否生成字段常量(默认 false)
private boolean entityColumnConstant;
//【实体】是否为构建者模型(默认 false)
private boolean entityBuilderModel;
//【实体】是否为lombok模型(默认 false)
private boolean entityLombokModel;
//Boolean类型字段是否移除is前缀(默认 false)
private boolean entityBooleanColumnRemoveIsPrefix;
//生成 @RestController 控制器
private boolean restControllerStyle;
//驼峰转连字符
private boolean controllerMappingHyphenStyle;
//是否生成实体时,生成字段注解
private boolean entityTableFieldAnnotationEnable;
//乐观锁属性名称
private String versionFieldName;
//逻辑删除属性名称
private String logicDeleteFieldName;
//表填充字段
private List tableFillList;
MyBatis-Plus提供的代码生成器配置包含了大部分用户的常用配置,其中一部分为 MyBatis 原生所支持的配置。使用代码生成器能快速生成各模块类,开发更便捷,极大的提升了开发效率。提供的大量自定义参数供用户选择,能够满足绝大部分人的使用需求。同伴们在开发使用过程,如有问题,欢迎留言探讨。
扫描下方二维码,关注微信公众号,掌握最新动态。与关注的同伴们一起学习,一起编程!