Mybatis-plus generator代码生成器的使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


Mybatis-plus generator代码生成器的使用


Mybatis-plus generator是Mybatis-plus的核心功能之一,CRUD接口同样用的很多先放在后面再进行整理,官网地址在这Mybatis-plus generator
看了下示例代码,各部分的点比较零散,准备重构一下方便后续使用。

一、Mybatis-plus generator代码生成器是什么?

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。其中主要使用到的就是这个AutoGenerator类,源码如下:

public class AutoGenerator {
    /**
     * 配置信息
     */
    protected ConfigBuilder config;
    /**
     * 注入配置
     */
    protected InjectionConfig injectionConfig;
    /**
     * 数据源配置
     */
    private DataSourceConfig dataSource;
    /**
     * 数据库表配置
     */
    private StrategyConfig strategy;
    /**
     * 包 相关配置
     */
    private PackageConfig packageInfo;
    /**
     * 模板 相关配置
     */
    private TemplateConfig template;
    //全局 相关配置
    private GlobalConfig globalConfig;
    /**
     * 模板引擎
     */
    private AbstractTemplateEngine templateEngine;

以上属性就是需要自行配置的,简单描述一下功能,后续会详细整理。

  1. GlobalConfig :配置需要生成的文件地址和文件类型,包括Entity、Controller、Service、ServiceImpl、Mapper
  2. PackageConfig :配置包信息,包括生成文件的父目录,模块名,实体类的包名
  3. DataSourceConfig :配置数据源信息,包括驱动类、url、用户名和密码
  4. TemplateConfig :配置模板信息,这里可以进行模板的加载,需要写好模板类,支持Velocity和Freemarker
  5. AbstractTemplateEngine :模板引擎,这里可以指定模板引擎,同样支持Velocity和Freemarker
  6. StrategyConfig :配置数据库表的读取策略,包括设置转换成以驼峰形式命名,设置Lombok、rest风格Controller等
  7. InjectionConfig :配置自定义信息,包括自定义配置Map对象,自定义输出文件等

二、使用步骤

1.引入库

这里先引入依赖,根据官方文档,Mybatis-plus从 3.0.3 版本之后已经移除了代码生成器和模板引擎的默认依赖,需要进行手动添加,这里模板选用的是velocity(使用指南),也可以选用Freemarker(使用指南)

		<!--MyBatis Plus 依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!--MyBatis Plus 代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!--Velocity模板引擎-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>

2.详细可用代码

public class MyBatisPlusGenerator {

    public static void main(String[] args) {
        //返回项目的真实路径地址
        String projectPath = System.getProperty("user.dir");
        String moduleName = scanner("模块名");
        String[] tableNames = scanner("请输入表名,多个以,分隔").split(",");
        //代码生成器
        AutoGenerator autoGenerator = new AutoGenerator();
        autoGenerator.setGlobalConfig(initGlobalConfig(projectPath));
        autoGenerator.setDataSource(initDataSourceConfig());
        autoGenerator.setPackageInfo(initPackageConfig(moduleName));
        autoGenerator.setCfg(initInjectionConfig(projectPath,moduleName));
        autoGenerator.setTemplate(initTemplateConfig());
        autoGenerator.setStrategy(initStrategyConfig(tableNames));
        autoGenerator.setTemplateEngine(new VelocityTemplateEngine());
        autoGenerator.execute();
    }
    /**
     * 读取控制台信息
     */
    private static String scanner(String tip) {
        Scanner sc = new Scanner(System.in);
        System.out.println(("请输入" + tip + ":"));
        if (sc.hasNext()) {
            String next = sc.next();
            if (!StringUtils.isEmpty(next)) {
                return next;
            }
        }
        throw new MybatisPlusException("请输入正确的"+tip+"!");
    }
    /**
     * 初始化全局配置
     */
    private static GlobalConfig initGlobalConfig(String projectPath) {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(projectPath+"/src/main/java");
        globalConfig.setAuthor("libowen");
        globalConfig.setOpen(true);
        //给实体类添加Swagger2注解
        globalConfig.setSwagger2(true);
        //在mapper中添加Map映射
        globalConfig.setBaseResultMap(true);
        //覆盖原文件
        globalConfig.setFileOverride(true);
        //%s表示占位符,用来读取表名
        globalConfig.setEntityName("%s");
        globalConfig.setMapperName("%sMapper");
        globalConfig.setXmlName("%sMapper");
        globalConfig.setServiceName("%sService");
        globalConfig.setServiceImplName("%sServiceImpl");
        globalConfig.setControllerName("%sController");
        globalConfig.setDateType(DateType.ONLY_DATE);
        return globalConfig;
    }
    /**
     * 初始化数据源配置
     */
    private static DataSourceConfig initDataSourceConfig() {
        Props props = new Props("generator.properties");
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl(props.getStr("dataSource.url"));
        dataSourceConfig.setUsername(props.getStr("dataSource.username"));
        dataSourceConfig.setPassword(props.getStr("dataSource.password"));
        dataSourceConfig.setDriverName(props.getStr("dataSource.driverName"));
        return dataSourceConfig;
    }
    /**
     * 初始化包配置
     */
    private static PackageConfig initPackageConfig(String modelName) {
        Props props = new Props("generator.properties");
        PackageConfig config = new PackageConfig();
        config.setModuleName(modelName);
        config.setParent(props.getStr("package.base"));
        config.setEntity("entity");
        return config;
    }

    /**
     * 初始化模板设置
     */
    private static TemplateConfig initTemplateConfig() {
        TemplateConfig templateConfig = new TemplateConfig();
        //可以对Controller、Entity、Service模板进行设置
        //mapper.xml需要单独设置
        templateConfig.setXml(null);
//        templateConfig.setEntity("templates/entity2.java");
        return templateConfig;
    }
    /**
     * 初始化策略设置
     */
    private static StrategyConfig initStrategyConfig(String[] tableNames) {
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setEntityLombokModel(true);
        strategyConfig.setRestControllerStyle(true);
        //当表名中带*号时可以启用通配符模式
        if (tableNames.length == 1 && tableNames[0].contains("*")) {
            String[] likeStr = tableNames[0].split("_");
            String likePrefix = likeStr[0] + "_";
            strategyConfig.setLikeTable(new LikeTable(likePrefix));
        } else {
            strategyConfig.setInclude(tableNames);
        }
        return strategyConfig;
    }
    /**
     * 初始化自定义配置
     */
    private static InjectionConfig initInjectionConfig(String projectPath, String moduleName) {
        InjectionConfig injectionConfig = new InjectionConfig() {
            @Override
            public void initMap() {
                //可以用于自定义属性
            }
        };
        //模板引擎是velocity
        String templatePath = "/templates/mapper.xml.vm";
        //自定义输出配置
        List<FileOutConfig> fileOutConfigs = new ArrayList<>();
        fileOutConfigs.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath+"/src/main/resource/mapper"+moduleName+"/"
                    +tableInfo.getEntityName()+"Mapper"+ StringPool.DOT_XML;
            }
        });
        injectionConfig.setFileOutConfigList(fileOutConfigs);
        return injectionConfig;
    }
}

三.各配置信息类与代码实现

1、GlobalConfig 全局配置类

public class GlobalConfig {

    private String outputDir = "D://";		//配置文件输出目录
    private boolean fileOverride = false;	//是否允许覆盖
    private boolean open = true;			//是否自动打开输出目录
    private boolean enableCache = false;	//是否在xml中添加二级缓存配置
    private String author;					//添加作者
    private boolean swagger2 = false;		//是否支持swagger2
    private boolean baseResultMap = false;	//是否创建baseResultMap
    private DateType dateType = DateType.TIME_PACK;		//数据库类型到实体的类型对应策略
    private String entityName;		//%s作为占位符
    private String mapperName;		//%sMapper
    private String xmlName;			//%s.xml
    private String serviceName;		//%sService
    private String serviceImplName;	//%sServiceImpl
    private String controllerName;  //%sController
    private IdType idType;		//指定生成的主键的Id类型
}

这里需要注意的是,使用如entityName时,可以使用 ‘’%s‘’ 作为占位符,例如: %sAction 生成 UserAction,mapperName设置成%sMapper等。

2、PackageConfig 包配置类

public class PackageConfig {

    private String parent = "com.baomidou";			//这里配置父包名
    private String moduleName = "";					//配置模块包名
    private String entity = "entity";				//配置实体包名
    private String service = "service";				//配置service包名
    private String serviceImpl = "service.impl";	//配置serviceImpl报名
    private String mapper = "mapper";				//配置mapper包名
    private String xml = "mapper.xml";				//配置mapper.xml包名
    private String controller = "controller";		//配置controller包名
    private Map<String, String> pathInfo;			//配置路径信息
    public String getParent() {						//获取服包名
        if (StringUtils.isNotBlank(moduleName)) {
            return parent + StringPool.DOT + moduleName;
        }
        return parent;
    }
}

包配置文件配置方法如下:

import cn.hutool.setting.dialect.Props;
private static PackageConfig initPackageConfig(String modelName) { 
   	//...
    PackageConfig config = new PackageConfig();
    config.setModuleName(modelName);
    config.setParent("这里填包名"); 		//如com.xxx.edu.model
    config.setEntity("entity");
    return config;
 }

这里没有设置controller、service、serviceImpl、mapper等信息,使用默认名称生成对应包名即可。

Props类的使用,Hutool包中的Props对象封装了一些使用Properties的方法,并添加了PropsUtil相关工具类,用于对properties我文件进行缓存。

Props加载properties文件的流程大致如下,省略了部分代码

public class MyPropertiesLoader extends Properties {
	... 
    public MyPropertiesLoader(String path, Charset charset) {
        if (StringUtils.isBlank(path)) {
            Assert.notBlank(path, "Blank properties file path !");
        }
        //ResourceUtil.getReader 会以相对于classpath绝对路径以文件流的形式返回URL
       	//根据路径创建File对象并创建FileResource流
        BufferedReader reader = ResourceUtil.getReader(path,charset);
        this.load(reader);
    }

    public void load(BufferedReader reader) {
        try {
        	//调用Properties类的load方法,加载properties文件
            super.load(reader);	
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取properties文件中的key
    public String getStr(String key) {
        return getProperty(key);
    }
}

3、DataSourceConfig :配置数据源信息,包括驱动类、url、用户名和密码

public class DataSourceConfig {

    private IDbQuery dbQuery;				//数据库信息查询
    private DbType dbType;					//数据库类型
    private String schemaName;				//PostgreSQL schemaName
    private ITypeConvert typeConvert;				//类型转换
    private IKeyWordsHandler keyWordsHandler;		//关键字处理器
    private String url;		//驱动连接的URL
    private String driverName;		//驱动名称
    private String username;	//数据库连接用户名
    private String password;	//数据库连接密码
	
	...
}

在设置url和driverName时也是有坑存在,引入一篇比较好的回答,这里就不再赘述

> mysql-connector-java与mysql驱动冲突问题

4、TemplateConfig :模板信息配置类

public class TemplateConfig {

    @Getter(AccessLevel.NONE)
    private String entity = ConstVal.TEMPLATE_ENTITY_JAVA;		//对应路径"/templates/entity.java"
    private String entityKt = ConstVal.TEMPLATE_ENTITY_KT;		//对应路径"/templates/entity.kt";
    private String service = ConstVal.TEMPLATE_SERVICE;			//对应路径"/templates/mapper.java";
    private String serviceImpl = ConstVal.TEMPLATE_SERVICE_IMPL;
    private String mapper = ConstVal.TEMPLATE_MAPPER;
    private String xml = ConstVal.TEMPLATE_XML;
    private String controller = ConstVal.TEMPLATE_CONTROLLER;
    ...
 }

之后找到templates下的模板
在这里插入图片描述

5、AbstractTemplateEngine :模板引擎类

该抽象类下有三种实现方式,根据所加载的引擎类型加载对应的文件类型。
在这里插入图片描述

6、StrategyConfig :数据库表读取策略

由于该类下的属性太多,选择部分列出

public class StrategyConfig {
    /**
     * 数据库表映射到实体的命名策略
     */
    private NamingStrategy naming = NamingStrategy.no_change;
    /**
     * 数据库表映射到实体的命名策略
     */
    private NamingStrategy naming = NamingStrategy.no_change;
    /**
     * 数据库表字段映射到实体的命名策略
     * <p>未指定按照 naming 执行</p>
     */
    private NamingStrategy columnNaming = null;
    /**
     * 表前缀
     */
    @Setter(AccessLevel.NONE)
    private String[] tablePrefix;
    /**
     * 字段前缀
     */
    @Setter(AccessLevel.NONE)
    private String[] fieldPrefix;
    /**
     * 【实体】是否为lombok模型(默认 false)<br>
     * <a href="https://projectlombok.org/">document</a>
     */
    private boolean entityLombokModel = false;
    /**
     * @Controller->@RestControlle
     */
    private boolean restControllerStyle = false;
    /**
     * 驼峰转连字符
	 * @RequestMapping("/managerUserActionHistory") ---> @RequestMapping("/manager-user-action-history")
     */
    private boolean controllerMappingHyphenStyle = false;
    /**
     * 是否生成实体时,生成字段注解
     */
    private boolean entityTableFieldAnnotationEnable = false;
    /**
     * 乐观锁属性名称
     */
    private String versionFieldName;
	
	...
}

经常会使用到其中驼峰转字符的方法,需要同时配置才可以实现该功能

strategyConfig.setNaming(NamingStrategy.underline_to_camel);		
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);	

7、InjectionConfig :自定义信息配置

代码如下:

public abstract class InjectionConfig {

    /**
     * 全局配置
     */
    private ConfigBuilder config;

    /**
     * 自定义返回配置 Map 对象
     */
    private Map<String, Object> map;

    /**
     * 自定义输出文件
     */
    private List<FileOutConfig> fileOutConfigList;

    /**
     * 自定义判断是否创建文件
     */
    private IFileCreate fileCreate;

    /**
     * 注入自定义 Map 对象,针对所有表的全局参数
     */
    public abstract void initMap();
    
	...
}

在这里配置xml使用的模板样式,以及输出xml文件的目录


四、总结

在日常开发当中,使用代码生成器可以大大降低开发工作中的机械任务,把工作重心放在业务逻辑的处理上。每一项技术的诞生总有它能解决的问题,类似人工智能所说,没有最好的算法,只有最适合解决当前问题的算法。本文只对代码生成器中的部分应用进行总结,还有更多应用场景需要之后补充。

此文主要根据Github上的mall项目进行学习,此后也将陆续学习该项目中各模板的使用流程和细节,力求从需求设计、业务逻辑、架构设计等多方面进行掌握。

mall learning网站
mall github 地址
mybatis-plus官网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值