目录
3.2 方法二:修改若依框架的代码生成部分以实现MP代码生成
一、依赖变更
1. MybatisPlus依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-extension</artifactId> <version>3.5.2</version> <scope>compile</scope> </dependency>
建议使用3.5.1及以上版本,3.4.x版分页有问题
2. pagehelper依赖修改
pagehelper依赖中不引用Mybatis相关依赖(MP依赖中自带Mybatis依赖),这样pagehelper分页依然可用
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <exclusions> <exclusion> <artifactId>mybatis-spring</artifactId> <groupId>org.mybatis</groupId> </exclusion> <exclusion> <artifactId>mybatis</artifactId> <groupId>org.mybatis</groupId> </exclusion> </exclusions> </dependency>
二、相关配置
1. yml配置
1.1 注释掉原Mybatis配置
# MyBatis配置 #mybatis: # # 搜索指定包别名 # typeAliasesPackage: com.bsd.**.domain # # 配置mapper的扫描,找到所有的mapper.xml映射文件 # mapperLocations: classpath*:mapper/**/*Mapper.xml # # 加载全局的配置文件 # configLocation: classpath:mybatis/mybatis-config.xml
1.2 加入MybatisPlus的配置
mybatis-plus: # Mapper.xml 文件位置 Maven 多模块项目的扫描路径需以 classpath*: 开头 mapper-locations: classpath*:mapper/**/*Mapper.xml # #MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名 实体扫描,多个package用逗号或者分号分隔 type-aliases-package: com.bsd.**.domain # config-location: classpath:mybatis/mybatis-config.xml # #通过父类(或实现接口)的方式来限定扫描实体 # typeAliasesSuperType: com.vanhr.user.dao.entity.baseEntity # #枚举类 扫描路径 如果配置了该属性,会将路径下的枚举类进行注入,让实体类字段能够简单快捷的使用枚举属性 # typeEnumsPackage: com.vanhr.user.dao.enums # 启动时是否检查 MyBatis XML 文件的存在,默认不检查 仅限spring boot 使用 checkConfigLocation : true # #通过该属性可指定 MyBatis 的执行器,MyBatis 的执行器总共有三种: # # ExecutorType.SIMPLE:该执行器类型不做特殊的事情,为每个语句的执行创建一个新的预处理语句(PreparedStatement) # # ExecutorType.REUSE:该执行器类型会复用预处理语句(PreparedStatement) # # ExecutorType.BATCH:该执行器类型会批量执行所有的更新语句 # executorType: SIMPLE # # 指定外部化 MyBatis Properties 配置,通过该配置可以抽离配置,实现不同环境的配置部署 # configurationProperties: configuration: # MyBatis 原生支持的配置 # 是否开启自动驼峰命名规则(camel case)映射 map-underscore-to-camel-case: true # 枚举处理类,如果配置了该属性,枚举将统一使用指定处理器进行处理 # org.apache.ibatis.type.EnumTypeHandler : 存储枚举的名称 # org.apache.ibatis.type.EnumOrdinalTypeHandler : 存储枚举的索引 # com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler : 枚举类需要实现IEnum接口或字段标记@EnumValue注解.(3.1.2以下版本为EnumTypeHandler) # defaultEnumTypeHandler: com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler # 配置JdbcTypeForNull, oracle数据库必须配置 jdbc-type-for-null: null log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: # 全局策略配置 # 是否控制台 print mybatis-plus 的 LOGO banner: true db-config: # id类型 id-type: auto # 表名是否使用下划线命名,默认数据库表使用下划线命名 table-underline: true #是否开启大写命名,默认不开启 # capital-mode: false # #逻辑已删除值,(逻辑删除下有效) 需要注入逻辑策略LogicSqlInjector 以@Bean方式注入 # logic-not-delete-value: 0 # #逻辑未删除值,(逻辑删除下有效) # logic-delete-value: 1
1.3 注释掉原MybatisConfig.class
位置:com/bsd/framework/config/MyBatisConfig.java
建议先别删除,若出现问题还可以退回去使用Mybatis
此时MybatisPlus已经可以正常使用了,下面再记录一下其他常用配置
三、其他配置及功能实现
1. 自动补全create_time等信息
配置一个组件类,实现MP的MetaObjectHandler类,重写里面的方法即可
package com.bsd.framework.config; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.bsd.common.utils.SecurityUtils; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; @Component @Slf4j public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { String operator = null; try { operator = SecurityUtils.getUsername(); } catch (Exception e) { log.error(e.getMessage(), e); } this.setFieldValByName("createBy", operator, metaObject); this.setFieldValByName("createTime", new Date(), metaObject); this.setFieldValByName("updateBy", operator, metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); } @Override public void updateFill(MetaObject metaObject) { String operator = null; try { operator = SecurityUtils.getUsername(); } catch (Exception e) { log.error(e.getMessage(), e); } this.setFieldValByName("updateBy", operator, metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); } }
2. 实现MP分页
创建一个MyBatisPlusConfig类,将MP的拦截器交由Spring管理
package com.bsd.framework.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisPlusConfig { /** * 分页插件 * @return */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
3. 实现MybatisPlus代码生成
3.1 方法一:使用MP自带的代码生成方法
3.1.1 引入MP代码生成依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.2</version> </dependency>
因为MP代码生成需要连接数据库,所以还要引入数据库连接依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency>
3.1.2 使用MP的方法生成代码
创建MPCodeGenerator类,在generation方法中进行相关配置,再在main方法中调用generation方法,传入相关参数后执行main方法实现生成代码
package com.bsd.generator.util; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.generator.FastAutoGenerator; import com.baomidou.mybatisplus.generator.config.OutputFile; import com.baomidou.mybatisplus.generator.config.TemplateType; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.bsd.common.core.domain.BaseEntity; import com.bsd.common.utils.StringUtils; import java.util.Collections; import java.util.HashMap; import java.util.Map; public class MPCodeGenerator { public static void main(String[] args) { String filePath = System.getProperty("user.dir") + "/src/main/java"; generation("ljf", filePath,"d_test", "d_record_annex"); } /** * 根据表名生成相应结构代码 * * @param author 作者名 * @param tableName 表名 */ public static void generation(String author, String filePath, String... tableName) { FastAutoGenerator.create("jdbc:mysql://xxxxxxx:3306/safety?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8", "XXXX", "XXXXX") .globalConfig(builder -> { builder.author(author) //启用swagger .enableSwagger() .dateType(DateType.TIME_PACK) //指定输出目录 .outputDir(filePath); }) .packageConfig(builder -> { builder.entity("domain")//实体类包名 .parent("com.bsd.device")//父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名 .controller("controller")//控制层包名 .mapper("mapper")//mapper层包名 //.other("dto")//生成dto目录 可不用 .service("service")//service层包名 .serviceImpl("service.impl")//service实现类包名 //自定义mapper.xml文件输出目录 .pathInfo(Collections.singletonMap(OutputFile.xml, filePath + "/resources/mapper/device")); }) .strategyConfig(builder -> { //设置要生成的表名 builder.addInclude(tableName) .addTablePrefix("d_")//设置表前缀过滤 .entityBuilder() .enableLombok() .enableChainModel() .superClass(BaseEntity.class)//设置父类 .enableTableFieldAnnotation()//开启生成实体时生成字段注解 .naming(NamingStrategy.underline_to_camel)//数据表映射实体命名策略:默认下划线转驼峰underline_to_camel .columnNaming(NamingStrategy.underline_to_camel)//表字段映射实体属性命名规则:默认null,不指定按照naming执行 .idType(IdType.AUTO)//添加全局主键类型 .formatFileName("%s")//格式化实体名称,%s取消首字母I, .mapperBuilder() .enableMapperAnnotation()//开启mapper注解 .enableBaseResultMap()//启用xml文件中的BaseResultMap 生成 .enableBaseColumnList()//启用xml文件中的BaseColumnList .formatMapperFileName("%sMapper")//格式化Dao类名称 .formatXmlFileName("%sMapper")//格式化xml文件名称 .serviceBuilder() // .formatServiceFileName("sService")//格式化 service 接口文件名称 .formatServiceImplFileName("%sServiceImpl")//格式化 service 接口文件名称 .controllerBuilder() .enableRestStyle(); }) // .injectionConfig(consumer -> { // Map<String, String> customFile = new HashMap<>(); // // 配置DTO(需要的话)但是需要有能配置Dto的模板引擎,比如freemarker,但是这里我们用的VelocityEngine,因此不多作介绍 // customFile.put("DTO.java", "/templates/entityDTO.java.ftl"); // consumer.customFile(customFile); // }) .execute(); } }
3.2 方法二:修改若依框架的代码生成部分以实现MP代码生成
因为若依的代码生成是使用velocity确定模版,再根据模版来生成代码,所以只要将MP相关代码部分(主要是一些注解和继承接口)添加到velocity模版即可。
Velocity语法教学:Java Velocity模板引擎详解
下面将修改好的vm文件贴出(包括domain、mapper、service、serviceImpl):
domain.java.vm
package ${packageName}.domain; #foreach ($import in $importList) import ${import}; #end import com.bsd.common.annotation.Excel; import lombok.Data; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableId; #if($table.crud || $table.sub) import com.bsd.common.core.domain.BaseEntity; #elseif($table.tree) import com.bsd.common.core.domain.TreeEntity; #end /** * ${functionName}对象 ${tableName} * * @author ${author} * @date ${datetime} */ #if($table.crud || $table.sub) #set($Entity="BaseEntity") #elseif($table.tree) #set($Entity="TreeEntity") #end @Data @TableName("${tableName}") public class ${ClassName} extends ${Entity} { private static final long serialVersionUID=1L; #foreach ($column in $columns) #if(!$table.isSuperColumn($column.javaField)) /** $column.columnComment */ #if($column.list) #set($parentheseIndex=$column.columnComment.indexOf("(")) #if($parentheseIndex != -1) #set($comment=$column.columnComment.substring(0, $parentheseIndex)) #else #set($comment=$column.columnComment) #end #if($parentheseIndex != -1) @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") #elseif($column.javaType == 'Date') @JsonFormat(pattern = "yyyy-MM-dd") @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") #else @Excel(name = "${comment}") #end #end #if($column.javaField == 'id') @TableId(type = IdType.AUTO) #end private $column.javaType $column.javaField; #end #end #if($table.sub) /** $table.subTable.functionName信息 */ private List<${subClassName}> ${subclassName}List; #end }
mapper.java.vm
package ${packageName}.mapper; import java.util.List; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import ${packageName}.domain.${ClassName}; #if($table.sub) import ${packageName}.domain.${subClassName}; #end /** * ${functionName}Mapper接口 * * @author ${author} * @date ${datetime} */ public interface ${ClassName}Mapper extends BaseMapper<${ClassName}> { /** * 查询${functionName} * * @param ${pkColumn.javaField} ${functionName}主键 * @return ${functionName} */ public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); /** * 查询${functionName}列表 * * @param ${className} ${functionName} * @return ${functionName}集合 */ public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); /** * 新增${functionName} * * @param ${className} ${functionName} * @return 结果 */ public int insert${ClassName}(${ClassName} ${className}); /** * 修改${functionName} * * @param ${className} ${functionName} * @return 结果 */ public int update${ClassName}(${ClassName} ${className}); /** * 删除${functionName} * * @param ${pkColumn.javaField} ${functionName}主键 * @return 结果 */ public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); /** * 批量删除${functionName} * * @param ${pkColumn.javaField}s 需要删除的数据主键集合 * @return 结果 */ public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); #if($table.sub) /** * 批量删除${subTable.functionName} * * @param ${pkColumn.javaField}s 需要删除的数据主键集合 * @return 结果 */ public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); /** * 批量新增${subTable.functionName} * * @param ${subclassName}List ${subTable.functionName}列表 * @return 结果 */ public int batch${subClassName}(List<${subClassName}> ${subclassName}List); /** * 通过${functionName}主键删除${subTable.functionName}信息 * * @param ${pkColumn.javaField} ${functionName}ID * @return 结果 */ public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField}); #end }
service.java.vm
package ${packageName}.service; import java.util.List; import com.baomidou.mybatisplus.extension.service.IService; import ${packageName}.domain.${ClassName}; /** * ${functionName}Service接口 * * @author ${author} * @date ${datetime} */ public interface I${ClassName}Service extends IService<${ClassName}> { /** * 查询${functionName} * * @param ${pkColumn.javaField} ${functionName}主键 * @return ${functionName} */ public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); /** * 查询${functionName}列表 * * @param ${className} ${functionName} * @return ${functionName}集合 */ public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); /** * 新增${functionName} * * @param ${className} ${functionName} * @return 结果 */ public int insert${ClassName}(${ClassName} ${className}); /** * 修改${functionName} * * @param ${className} ${functionName} * @return 结果 */ public int update${ClassName}(${ClassName} ${className}); /** * 批量删除${functionName} * * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合 * @return 结果 */ public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); /** * 删除${functionName}信息 * * @param ${pkColumn.javaField} ${functionName}主键 * @return 结果 */ public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); }
serviceImpl.java.vm
package ${packageName}.service.impl; import java.util.List; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; #foreach ($column in $columns) #if($column.javaField == 'createTime' || $column.javaField == 'updateTime') import com.bsd.common.utils.DateUtils; #break #end #end import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; #if($table.sub) import java.util.ArrayList; import com.bsd.common.utils.StringUtils; import org.springframework.transaction.annotation.Transactional; import ${packageName}.domain.${subClassName}; #end import ${packageName}.mapper.${ClassName}Mapper; import ${packageName}.domain.${ClassName}; import ${packageName}.service.I${ClassName}Service; /** * ${functionName}Service业务层处理 * * @author ${author} * @date ${datetime} */ @Service public class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}> implements I${ClassName}Service { @Autowired private ${ClassName}Mapper ${className}Mapper; /** * 查询${functionName} * * @param ${pkColumn.javaField} ${functionName}主键 * @return ${functionName} */ @Override public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}) { return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}); } /** * 查询${functionName}列表 * * @param ${className} ${functionName} * @return ${functionName} */ @Override public List<${ClassName}> select${ClassName}List(${ClassName} ${className}) { return ${className}Mapper.select${ClassName}List(${className}); } /** * 新增${functionName} * * @param ${className} ${functionName} * @return 结果 */ #if($table.sub) @Transactional #end @Override public int insert${ClassName}(${ClassName} ${className}) { #foreach ($column in $columns) #if($column.javaField == 'createTime') ${className}.setCreateTime(DateUtils.getNowDate()); #end #end #if($table.sub) int rows = ${className}Mapper.insert${ClassName}(${className}); insert${subClassName}(${className}); return rows; #else return ${className}Mapper.insert${ClassName}(${className}); #end } /** * 修改${functionName} * * @param ${className} ${functionName} * @return 结果 */ #if($table.sub) @Transactional #end @Override public int update${ClassName}(${ClassName} ${className}) { #foreach ($column in $columns) #if($column.javaField == 'updateTime') ${className}.setUpdateTime(DateUtils.getNowDate()); #end #end #if($table.sub) ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}()); insert${subClassName}(${className}); #end return ${className}Mapper.update${ClassName}(${className}); } /** * 批量删除${functionName} * * @param ${pkColumn.javaField}s 需要删除的${functionName}主键 * @return 结果 */ #if($table.sub) @Transactional #end @Override public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s) { #if($table.sub) ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s); #end return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s); } /** * 删除${functionName}信息 * * @param ${pkColumn.javaField} ${functionName}主键 * @return 结果 */ #if($table.sub) @Transactional #end @Override public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}) { #if($table.sub) ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField}); #end return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}); } #if($table.sub) /** * 新增${subTable.functionName}信息 * * @param ${className} ${functionName}对象 */ public void insert${subClassName}(${ClassName} ${className}) { List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List(); ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}(); if (StringUtils.isNotNull(${subclassName}List)) { List<${subClassName}> list = new ArrayList<${subClassName}>(); for (${subClassName} ${subclassName} : ${subclassName}List) { ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField}); list.add(${subclassName}); } if (list.size() > 0) { ${className}Mapper.batch${subClassName}(list); } } } #end }
有关MybatisPlus的其他问题,或者上面未说明的问题,均可查看MybatisPlus官网指南:简介 | MyBatis-Plus