1 目录结构
├─src│ ├─main│ │ ├─java│ │ │ └─com│ │ │ └─hikktn│ │ │ ├─common│ │ │ │ ├─base│ │ │ │ ├─enums│ │ │ │ ├─exception│ │ │ │ ├─rest│ │ │ │ └─validator│ │ │ ├─content│ │ │ │ ├─controller│ │ │ │ ├─dao│ │ │ │ ├─entity│ │ │ │ └─service│ │ │ │ └─impl│ │ │ └─generator│ │ └─resources│ │ ├─mapper│ │ └─templates
2 示例
2.1 依赖引入
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mybatis-plus的springboot支持--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.1.0</version> </dependency> <!-- MP 核心库 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>3.1.0</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--简化代码的工具包--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- 模板引擎依赖Freemarker --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.29</version> </dependency> <!-- thymeleaf模板插件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3</version> </dependency> <!-- velocity --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.75</version> </dependency> </dependencies>
2.2 控制器 - controller.java.vm
package ${package.Controller};import ${package.Entity}.${entity};import ${package.Service}.${table.serviceName};import com.hikktn.common.base.PageDto;import com.hikktn.common.exception.RestException;import com.hikktn.common.rest.RestResponse;import org.apache.commons.lang.StringUtils;import org.springframework.web.bind.annotation.*;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.MediaType;#if(${superControllerClassPackage})import $!{superControllerClassPackage};#end/** * <p> * $!{table.comment} 前端控制器 * </p> * * @author ${author} * @since ${date} * @version ${cfg.version} */#set($entityName = ${entity.substring(0,1).toLowerCase()}+${entity.substring(1)})@RestController@RequestMapping(value = {"#if(${controllerMappingHyphenStyle})/api/${controllerMappingHyphen}#else /api/${table.entityPath}#end"}, produces = MediaType.APPLICATION_JSON_VALUE)@Api(value = "${table.controllerName}", description = "$!{table.comment}", produces = MediaType.APPLICATION_JSON_VALUE)public class ${table.controllerName} extends ${superControllerClass} { @Autowired private ${table.serviceName} ${entityName}Service; @ResponseBody @ApiOperation(value = "$!{table.comment}-分页查询", notes = "$!{table.comment}-分页查询") @RequestMapping(value = "/_search", method = RequestMethod.POST) public RestResponse search(@RequestBody PageDto<${entity}> page){ return RestResponse.success(); } @ResponseBody @ApiOperation(value = "$!{table.comment}-保存", notes = "$!{table.comment}-保存") @RequestMapping(value = "", method = RequestMethod.POST) public RestResponse<String> save(@RequestBody ${entity} $entityName){ ${entityName}Service.save($entityName); return RestResponse.success(); } @ResponseBody @ApiOperation(value = "$!{table.comment}-更新", notes = "$!{table.comment}-更新") @RequestMapping(value = "/{id}", method = RequestMethod.PUT) public RestResponse<String> update(@PathVariable String id, @RequestBody ${entity} $entityName){ if (StringUtils.isEmpty(id)){ throw new RestException("ID不能为空"); } ${entityName}Service.updateById($entityName); return RestResponse.success(); } @ResponseBody @ApiOperation(value = "$!{table.comment}-删除", notes = "$!{table.comment}-删除") @RequestMapping(value = "/{id}", method = RequestMethod.DELETE) public RestResponse<String> delete(@PathVariable String id){ ${entityName}Service.removeById(id); return RestResponse.success(); }}
2.3 领域对象 - entity.java.vm
package ${package.Entity};#foreach($pkg in ${table.importPackages})import ${pkg};#end#if(${entityLombokModel})import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;#end#if(${swagger2})import io.swagger.annotations.ApiModelProperty;#end## 表备注,作者,日期/** * <p> * $!{table.comment} * </p> * * @author ${author} * @since ${date} * @version ${cfg.version} */#if(${entityLombokModel})@Data@EqualsAndHashCode(callSuper = true)@Accessors(chain = true)#end@TableName("${table.name}")#if(${superEntityClass})public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {#elseif(${activeRecord})public class ${entity} extends Model<${entity}> {#elsepublic class ${entity} implements Serializable {#end private static final long serialVersionUID = 1L;## ---------- BEGIN 字段循环遍历 ----------## ---------- START 字段循环遍历 ----------#foreach($field in ${table.fields}) #if(${field.keyFlag}) #set($keyPropertyName=${field.propertyName}) #end #if("$!field.comment" != "") #if(${swagger2}) /** * ${field.comment} */ @ApiModelProperty(value = "${field.comment}") #else /** * ${field.comment} */ #end #end ## 主键 #if(${field.keyFlag}) #if(${field.keyIdentityFlag}) @TableId(value = "${field.name}", type = IdType.AUTO) #elseif(!$null.isNull(${idType}) && "$!idType" != "") @TableId(value = "${field.name}", type = IdType.${idType}) #elseif(${field.convert}) @TableId("${field.name}") #end ## 普通字段 #if(${field.fill}) ## ----- 存在字段填充设置 ----- #if(${field.convert}) @TableField(value = "${field.name}", fill = FieldFill.${field.fill}) #else @TableField(fill = FieldFill.${field.fill}) #end #elseif(${field.convert}) @TableField("${field.name}") #end #end ## 时间类型 #if(${field.name} == ${cfg.createTime}) @TableField(fill = FieldFill.INSERT) #elseif(${field.name} == ${cfg.updateTime}) @TableField(fill = FieldFill.INSERT_UPDATE) #end## 逻辑删除注解 #if(${cfg.logicDeleteFieldName}==${field.name}) @TableLogic #end private ${field.propertyType} ${field.propertyName};#end## ---------- END 字段循环遍历 ----------#if(!${entityLombokModel}) #foreach($field in ${table.fields}) #if(${field.propertyType.equals("boolean")}) #set($getprefix="is") #else #set($getprefix="get") #end public ${field.propertyType} ${getprefix}${field.capitalName}() { return ${field.propertyName}; } #if(${entityBuilderModel}) public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) { #else public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) { #end this.${field.propertyName} = ${field.propertyName}; #if(${entityBuilderModel}) return this; #end } #end ## --foreach end---#end## --end of#if(${entityColumnConstant}) #foreach($field in ${table.fields}) public static final String ${field.name.toUpperCase()} = "${field.name}"; #end#end #if(${activeRecord}) @Override protected Serializable pkVal() { #if(${keyPropertyName}) return this.${keyPropertyName}; #else return this.id; #end } #end #if(!${entityLombokModel}) @Override public String toString() { return "${entity}{" + #foreach($field in ${table.fields}) #if($!{velocityCount}==1) "${field.propertyName}=" + ${field.propertyName} + #else ", ${field.propertyName}=" + ${field.propertyName} + #end #end "}"; } #end}
2.4 Mapper接口 - mapper.java.vm
package ${package.Mapper};import ${package.Entity}.${entity};import ${superMapperClassPackage};import org.springframework.stereotype.Repository;/** * <p> * $!{table.comment} Mapper 接口 * </p> * * @author ${author} * @since ${date} * @version ${cfg.version} */@Repositorypublic interface ${table.mapperName} extends ${superMapperClass}<${entity}> {}
2.5 Mapper-XML - mapper.xml.vm
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="${package.Mapper}.${table.mapperName}"> #if(${enableCache}) <!-- 开启二级缓存 --> <cache type="org.mybatis.caches.ehcache.LoggingEhcache"/> #end #if(${baseResultMap}) <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="${package.Entity}.${entity}"> #foreach($field in ${table.fields}) #if(${field.keyFlag})##生成主键排在第一位 <id column="${field.name}" property="${field.propertyName}"/> #end #end #foreach($field in ${table.commonFields})##生成公共字段 <result column="${field.name}" property="${field.propertyName}"/> #end #foreach($field in ${table.fields}) #if(!${field.keyFlag})##生成普通字段 <result column="${field.name}" property="${field.propertyName}"/> #end #end </resultMap> #end #if(${baseColumnList}) <!-- 通用查询结果列 --> <sql id="Base_Column_List"> #foreach($field in ${table.commonFields}) #if(${field.name} == ${field.propertyName})${field.name}#else${field.name} AS ${field.propertyName}#end, #end ${table.fieldNames} </sql> #end</mapper>
2.6 业务层 - service.java.vm
package ${package.Service};import com.hikktn.common.base.PageDto;import ${package.Entity}.${entity};import ${superServiceClassPackage};/** * <p> * $!{table.comment} 服务类 * </p> * * @author ${author} * @since ${date} * @version ${cfg.version} */#set($entityName = ${entity.substring(0,1).toLowerCase()}+${entity.substring(1)})public interface ${table.serviceName} extends ${superServiceClass}<${entity}> { /** * 添加 * @param $entityName */ @Override boolean save(${entity} $entityName); /** * 分页查询 * @param pageDto 分页 * @return */ PageDto<${entity}> page(PageDto<${entity}> pageDto);}
2.7 业务实现层 - serviceImpl.java.vm
package ${package.ServiceImpl};import ${package.Entity}.${entity};import ${package.Mapper}.${table.mapperName};import ${package.Service}.${table.serviceName};import ${superServiceImplClassPackage};import com.hikktn.common.base.PageDto;import org.springframework.stereotype.Service;import com.hikktn.common.validator.ValidatorUtils;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;/** * <p> * $!{table.comment} 服务实现类 * </p> * * @author ${author} * @since ${date} * @version ${cfg.version} */#set($entityName = ${entity.substring(0,1).toLowerCase()}+${entity.substring(1)})@Servicepublic class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} { @Override public boolean save(${entity} $entityName) { ValidatorUtils.validateEntity($entityName); return this.save($entityName); } @Override public PageDto<${entity}> page(PageDto<${entity}> pageDto) { QueryWrapper<${entity}> ew = new QueryWrapper<>(); return new PageDto<>(super.page(pageDto.getDbPage(), ew)); }}
2.8 appliaction.yml
spring: application: name: mybatis-plus-demo datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/my_mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true username: root password: 123456#logging:# level:# root: debugmybatis-plus: # 读取mybatis配置文件# config-location: classpath:mybatis/mybatis-config.xml # 读取mapper文件# mapper-locations: classpath*:mybatis/mapper/*Mapper.xml # 别名配置,在mybatis.xml文件resultType属性可以不指定类的全路径# type-aliases-package: com.hikktn.pojo # 开启驼峰映射,注意:配置configuration.map-underscore-to-camel-case则不能配置config-location# configuration:# map-underscore-to-camel-case: true# 日志 configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 逻辑删除 global-config: db-config: logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
2.9 生成类
package com.hikktn.generator;import com.baomidou.mybatisplus.annotation.DbType;import com.baomidou.mybatisplus.annotation.IdType;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 com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;import org.springframework.core.io.ClassPathResource;import java.util.*;/** * @ClassName MpGenerator * @Description Mybatis-Plus代码生成器 * @Author lisonglin * @Date 2021/5/30 15:09 * @Version 1.0 */public class MyGenerator { // TODO 修改服务名以及数据表名 /** * 顶层包名 */ private static final String SERVICE_NAME = "content"; /** * 最终包路径 */ private static final StringBuilder FINAL_PATH = new StringBuilder(); /** * 多个数据表名 */ private static final String[] TABLE_NAMES = new String[]{"tb_user", "t_area"}; /** * <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); if (scanner.hasNext()) { String ipt = scanner.next(); if (StringUtils.isNotEmpty(ipt)) { return ipt; } } throw new MybatisPlusException("请输入正确的" + tip + "!"); } /** * 代码生成器 */ public static void main(String[] args) { // 目标数据表名 String[] tableName = scanner("表名,多个英文逗号分割").split(","); generateByTables(tableName); } private static void generateByTables(String... tableNames) { // 选择 freemarker 引擎,默认 Velocity AutoGenerator mpg = new AutoGenerator(); // mpg.setTemplateEngine(new FreemarkerTemplateEngine()); mpg.setTemplateEngine(new VelocityTemplateEngine()); // 全局配置 GlobalConfig gc = globalGenerate(); // 包配置 PackageConfig pc = packageGenerate(); // 文件路径输出配置 List<FileOutConfig> foc = fileOutGenerate(pc); // 其他参数 InjectionConfig cfg = injectionGenerate(foc); // 数据库配置 DataSourceConfig dsc = dataSourceGenerate(); // 自定义模板 TemplateConfig tc = templateGenerate(); // 策略配置 StrategyConfig strategy = strategyGenerate(tableNames); mpg.setGlobalConfig(gc); mpg.setDataSource(dsc); mpg.setPackageInfo(pc); mpg.setCfg(cfg); mpg.setTemplate(tc); mpg.setStrategy(strategy); mpg.execute(); } /** * 数据库配置 * * @return 数据源 */ private static DataSourceConfig dataSourceGenerate() { YamlPropertiesFactoryBean yamlMapFactoryBean = new YamlPropertiesFactoryBean(); yamlMapFactoryBean.setResources(new ClassPathResource("application.yml")); //获取yml里的参数 Properties properties = yamlMapFactoryBean.getObject(); String url = properties.getProperty("spring.datasource.url"); String driver = properties.getProperty("spring.datasource.driver-class-name"); String username = properties.getProperty("spring.datasource.username"); String password = properties.getProperty("spring.datasource.password"); // 数据库配置 DataSourceConfig dsc = new DataSourceConfig(); //数据类型 dsc.setDbType(DbType.MYSQL); dsc.setUrl(url); dsc.setDriverName(driver); dsc.setUsername(username); dsc.setPassword(password); return dsc; } /** * 全局配置 * * @return 全局配置 */ private static GlobalConfig globalGenerate() { // 全局配置 GlobalConfig gc = new GlobalConfig(); //是否覆盖文件 gc.setFileOverride(true); // 获取顶层目录 String projectPath = System.getProperty("user.dir"); // 获取子项目目录 String path = MyGenerator.class.getClassLoader().getResource("").getPath(); String levelPath = path.substring(0, path.indexOf("target") - 1); if (!projectPath.equals(levelPath)) { FINAL_PATH.append(levelPath); } else { FINAL_PATH.append(projectPath); } //输出路径 gc.setOutputDir(FINAL_PATH + "/src/main/java"); //作者名称 gc.setAuthor("hikktn"); //生成后是否自动打开文件 gc.setOpen(false); // XML 二级缓存 gc.setEnableCache(false); //是否使用swagger2 gc.setSwagger2(true); // 自定义文件命名,注意 %s 会自动填充表实体属性! gc.setControllerName("%sController"); gc.setServiceName("%sService"); gc.setServiceImplName("%sServiceImpl"); gc.setMapperName("%sMapper"); gc.setXmlName("%sMapper"); //mapper.xml中生成基础resultMap gc.setBaseResultMap(true); //mapper.xml中生成基础columnList gc.setBaseColumnList(true); // 主键类型 gc.setIdType(IdType.ID_WORKER); return gc; } /** * 策略配置 * 主要的表字段映射 * * @param tableName 表名 * @return 策略配置 */ private static StrategyConfig strategyGenerate(String[] tableName) { // 策略配置 StrategyConfig strategy = new StrategyConfig(); //表名映射到实体策略,带下划线的转成 驼峰 strategy.setNaming(NamingStrategy.underline_to_camel); //列名映射到类型属性策略,带下划线的转成驼峰 strategy.setColumnNaming(NamingStrategy.underline_to_camel); // 表名和字段名是否大小写 strategy.setCapitalMode(false); //实体类使用lombok strategy.setEntityLombokModel(false); //controller使用rest接口模式 strategy.setRestControllerStyle(true); // 继承顶层controller strategy.setSuperControllerClass("com.hikktn.common.base.BaseController"); //设置表名 strategy.setInclude(tableName); //strategy.setInclude(TABLE_NAMES); //表名映射到实体名称去掉前缀 strategy.setTablePrefix("tb_"); // Boolean类型字段是否移除is前缀处理 strategy.setEntityBooleanColumnRemoveIsPrefix(true); // 驼峰转连字符 strategy.setControllerMappingHyphenStyle(true); // 建造者模式 strategy.setEntityBuilderModel(true); return strategy; } /** * 自定义模板 * * @return 模板 */ private static TemplateConfig templateGenerate() { // 设置模板 TemplateConfig tc = new TemplateConfig(); tc.setController("templates/controller.java.vm") .setEntity("templates/entity.java.vm") .setService("templates/service.java.vm") .setServiceImpl("templates/serviceImpl.java.vm") .setMapper("templates/mapper.java.vm") // 不要源码包内的mapper .setXml(null); return tc; } /** * 文件路径输出配置 * * @param pc 包配置 * @return 文件路径输出配置 */ private static List<FileOutConfig> fileOutGenerate(PackageConfig pc) { 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 FINAL_PATH + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); return focList; } /** * 其他参数,在velocity使用的参数,格式:${cfg.version} * * @param focList 文件路径输出配置 * @return 其他参数 */ private static InjectionConfig injectionGenerate(List<FileOutConfig> focList) { InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { Map<String, Object> map = new HashMap<>(10); // 查询参数名 map.put("version", "1.0"); // 逻辑删除 map.put("logicDeleteFieldName","is_deleted"); // 创建时间(自动生成时间) map.put("createTime","create_time"); // 修改时间 map.put("updateTime","update_time"); this.setMap(map); } }; cfg.setFileOutConfigList(focList); return cfg; } /** * 包配置 * * @return 包配置 */ private static PackageConfig packageGenerate() { // 包配置 PackageConfig pc = new PackageConfig(); pc.setModuleName(SERVICE_NAME); pc.setParent("com.hikktn"); pc.setEntity("entity"); pc.setService("service"); pc.setServiceImpl("service.impl"); pc.setMapper("dao"); // 不要设置包目录,否则会生成到源码包内 pc.setXml(null); return pc; }}