SpringBoot 集成MyBatis-Plus

SpringBoot 集成MyBatis-Plus

 

MyBatis-Plus简介

简介:

官网: https://baomidou.com/guide/

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作

  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求

  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错

  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题

  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作

  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )

  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用

  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询

  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库

  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询

  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

代码托管

Gitee (opens new window)| Github

相关注解

@Mapper

作用:在接口类上添加了@Mapper,在编译之后会生成相应的接口实现类

添加位置:接口类上面

如果想要每个接口都要变成实现类,那么需要在每个接口类上加上@Mapper注解,比较麻烦,解决这个问题用@MapperScan

 

@MapperScan

作用:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的接口实现类

添加位置:是在Springboot启动类上面添加

 

@TableName

表名注解

属性类型必须指定默认值描述
valueString""表名
schemaString""schema
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值)
resultMapString""xml 中 resultMap 的 id
autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入)
excludePropertyString[]{}需要排除的属性名(@since 3.3.1)

关于autoResultMap的说明:

mp会自动构建一个ResultMap并注入到mybatis里(一般用不上).下面讲两句: 因为mp底层是mybatis,所以一些mybatis的常识你要知道,mp只是帮你注入了常用crud到mybatis里 注入之前可以说是动态的(根据你entity的字段以及注解变化而变化),但是注入之后是静态的(等于你写在xml的东西) 而对于直接指定typeHandler,mybatis只支持你写在2个地方:

  1. 定义在resultMap里,只作用于select查询的返回结果封装

  2. 定义在insertupdatesql的#{property}里的property后面(例:#{property,typehandler=xxx.xxx.xxx}),只作用于设置值 而除了这两种直接指定typeHandler,mybatis有一个全局的扫描你自己的typeHandler包的配置,这是根据你的property的类型去找typeHandler并使用.

 

@TableId

主键注解

属性类型必须指定默认值描述
valueString""主键字段名
typeEnumIdType.NONE主键类型

 

IdType(opens new window)

描述
AUTO数据库ID自增
NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUTinsert前自行set主键值
ASSIGN_ID分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)
ID_WORKER分布式全局唯一ID 长整型类型(please use ASSIGN_ID)
UUID32位UUID字符串(please use ASSIGN_UUID)
ID_WORKER_STR分布式全局唯一ID 字符串类型(please use ASSIGN_ID)

 

@TableField

字段注解

属性类型必须指定默认值描述
valueString""数据库字段名
elString""映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分
existbooleantrue是否为数据库表字段
conditionString""字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window)
updateString""字段 update set 部分注入, 例如:update="%s+1":表示更新时会set version=version+1(该属性优先级高于 el 属性)
insertStrategyEnumNDEFAULT举例:NOT_NULL: insert into table_a(column) values (#{columnProperty})
updateStrategyEnumNDEFAULT举例:IGNORED: update table_a set column=#{columnProperty}
whereStrategyEnumNDEFAULT举例:NOT_EMPTY: where column=#{columnProperty}
fillEnumFieldFill.DEFAULT字段自动填充策略
selectbooleantrue是否进行 select 查询
keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC类型 (该默认值不代表会按照该值生效)
typeHandlerClass<? extends TypeHandler>UnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)
numericScaleString""指定小数点后保留的位数

关于jdbcTypetypeHandler以及numericScale的说明:

numericScale只生效于 update 的sql. jdbcTypetypeHandler如果不配合@TableName#autoResultMap = true一起使用,也只生效于 update 的sql. 对于typeHandler如果你的字段类型和set进去的类型为equals关系,则只需要让你的typeHandler让Mybatis加载到即可,不需要使用注解

FieldStrategy(opens new window)

描述
IGNORED忽略判断
NOT_NULL非NULL判断
NOT_EMPTY非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断)
DEFAULT追随全局配置

FieldFill(opens new window)

描述
DEFAULT默认不处理
INSERT插入时填充字段
UPDATE更新时填充字段
INSERT_UPDATE插入和更新时填充字段

 

@Version

乐观锁注解、标记 @Verison 在字段上

 

@EnumValue

枚举类注解(注解在枚举字段上)

 

@TableLogic

表字段逻辑处理注解(逻辑删除)

属性类型必须指定默认值描述
valueString""逻辑未删除值
delvalString""逻辑删除值

 

@KeySequence

序列主键策略 oracle

属性:value、resultMap

属性类型必须指定默认值描述
valueString""序列名
clazzClassLong.classid的类型, 可以指定String.class,这样返回的Sequence值是字符串"1"

 

@InterceptorIgnore

详见 插件主体

 

配置

详见官网: https://baomidou.com/config/#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE

条件构造器

AbstractWrapper

我们主要说他的两个子类,QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) ,其主要用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件

image-20210425171623705

基本写法:基本写法如下,构造我们需要查询的条件,然后把wrapper传入对应的查询方法即可。

 ​
 QueryWrapper<User> wrapper = new QueryWrapper<>();
 wrapper.allEq(Map<R, V> params)
 wrapper.eq(R column, Object val)
 wrapper.ne(R column, Object val)
     .......
 wrapper.ge(R column, Object val)
 wrapper.lt(R column, Object val)
 //或者使用LambdaQueryWrapper 以链式调用
 //LambdaQueryWrapper<User> lambdaQueryWrapper = 
     Wrappers.lambdaQuery().allEq();
 //Wrappers.lambdaQuery().eq()
 //Wrappers.lambdaQuery().ne()
     ......
 //Wrappers.lambdaQuery().ge()
 //Wrappers.lambdaQuery().lt()
 ​

allEq

 allEq(Map<R, V> params)
 allEq(Map<R, V> params, boolean null2IsNull)
 allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
 allEq(BiPredicate<R, V> filter, Map<R, V> params)
 allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
 allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) 

 

假设我们要查询[id=1,username=李白] 的人,写法如下

 QueryWrapper<User> wrapper = new QueryWrapper<>();
 Map map = new HashMap<>();
 map.put("id",1);
 map.put("username","李白");
 wrapper.allEq(map);
 //或者使用LambdaQueryWrapper 以链式调用
 //LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery().allEq(map);
 //List<User> list = userService.list(lambdaQueryWrapper);
 List<User> list = userService.list(wrapper);

eq

 eq(R column, Object val)
 eq(boolean condition, R column, Object val)

示例:其他例子是如下写法,后边会简写

假设查询[username=李白] 的人,

 LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>().eq(User::getUsername,"李白");
 List<User> list = userService.list(lambdaQueryWrapper);
 //或者
 //QueryWrapper<User> wrapper = new QueryWrapper<User>();
 //wrapper.eq("username","李白");
 //List<User> list = userService.list(lambdaQueryWrapper);

ne

 ne(R column, Object val)
 ne(boolean condition, R column, Object val)
 //例:查询年龄不等于18的人--> wrapper.ne("age",18);

gt

 gt(R column, Object val)
 gt(boolean condition, R column, Object val)
 //例:查询年龄大于18的人--> wrapper.gt("age",18);

ge

 ge(R column, Object val)
 ge(boolean condition, R column, Object val)
 //例:查询年龄大于等于18的人--> wrapper.ge("age",18);

lt

 lt(R column, Object val)
 lt(boolean condition, R column, Object val)
 //例:查询年龄小于18的人--> wrapper.lt("age",18);

le

 le(R column, Object val)
 le(boolean condition, R column, Object val)
 //例:查询年龄小于等于18的人--> wrapper.le("age",18);

between

 between(R column, Object val1, Object val2)
 between(boolean condition, R column, Object val1, Object val2)
 //例:查询年龄范围在18-28的人--> wrapper.between("age",18,28);

notBetween

 notBetween(R column, Object val1, Object val2)
 notBetween(boolean condition, R column, Object val1, Object val2)
 //例:查询年龄范围不在18-28的人--> wrapper.notBetween("age",18,28);

like

 like(R column, Object val)
 like(boolean condition, R column, Object val)
 //wrapper.like("username","李") ---> username like '%李%'

notLike

 notLike(R column, Object val)
 notLike(boolean condition, R column, Object val)
 //wrapper.notLike("username","李") ---> username not like '%李%'

likeLeft

 likeLeft(R column, Object val)
 likeLeft(boolean condition, R column, Object val)
 //wrapper.likeLeft("username", "李") ---> name like '%李'

likeRight

 likeRight(R column, Object val)
 likeRight(boolean condition, R column, Object val)
 //wrapper.likeRight("username", "李") ---> name like '李%'

isNull

 isNull(R column)
 isNull(boolean condition, R column)
 //wrapper.isNull("username") ---> username is null

isNotNull

 isNotNull(R column)
 isNotNull(boolean condition, R column)
 //wrapper.isNotNull("username") ---> username is not null

in

 in(R column, Collection<?> value)
 in(boolean condition, R column, Collection<?> value)
 //wrapper.in("age",{18,19,20}) ---> age in (18,19,20)
 in(R column, Object... values)
 in(boolean condition, R column, Object... values)
 //wrapper.in("age", 18,19,20) ---> age in (18,19,20)

notIn

notIn(R column, Collection<?> value)
notIn(boolean condition, R column, Collection<?> value)
//wrapper.in("age",{18,19,20}) ---> age in (18,19,20)
notIn(R column, Object... values)
notIn(boolean condition, R column, Object... values)
//wrapper.notIn("age", 18,19,20) ---> age not in (18,19,20)

inSql

inSql(R column, String inValue)
inSql(boolean condition, R column, String inValue)
//wrapper.inSql("age", "1,2,3,4,5,6") ---> age in (1,2,3,4,5,6)
//wrapper.inSql("id", "select id from user where id < 3") ---> id in (select id from user where id < 3)

notInSql

notInSql(R column, String inValue)
notInSql(boolean condition, R column, String inValue)
//wrapper.notInSql("age", "1,2,3,4,5,6") ---> age in (1,2,3,4,5,6)
//wrapper.notInSql("id", "select id from user where id < 3") ---> id not in (select id from user where id < 3)

groupBy

groupBy(R... columns)
groupBy(boolean condition, R... columns)
//wrapper.groupBy("id", "username") ---> group by id,username

orderByAsc

orderByAsc(R... columns)
orderByAsc(boolean condition, R... columns)
//wrapper.orderByAsc("id", "username") ---> order by id ASC,username ASC

orderByDesc

orderByDesc(R... columns)
orderByDesc(boolean condition, R... columns)
//wrapper.orderByDesc("id", "username") ---> order by id DESC,username DESC

orderBy

orderBy(boolean condition, boolean isAsc, R... columns)
//wrapper.orderBy(true, true, "id", "username") ---> order by id ASC,username ASC

having

having(String sqlHaving, Object... params)
having(boolean condition, String sqlHaving, Object... params)
//wrapper.having("sum(age) > 10") ---> having sum(age) > 10
//wrapper.having("sum(age) > {0}", 11) ---> having sum(age) > 11

func

func(Consumer<Children> consumer)
func(boolean condition, Consumer<Children> consumer)
//主要方便在出现if...else下调用不同方法能不断链
//wrapper.func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})

or

or拼接

or()
or(boolean condition)
//wrapper.eq("id",1).or().eq("username","李白")--->id = 1 or username = '李白'

or嵌套

or(Consumer<Param> consumer)
or(boolean condition, Consumer<Param> consumer)
//wrapper.or(i -> i.eq("username", "李白").ne("age", 18)) ---> or (username = '李白' and age <> 18)

and

and(Consumer<Param> consumer)
and(boolean condition, Consumer<Param> consumer)
//wrapper.and(i -> i.eq("username", "李白").ne("age", 18)) ---> and (username = '李白' and age <> 18)

nested

nested(Consumer<Param> consumer)
nested(boolean condition, Consumer<Param> consumer)
//正常嵌套 不带 AND 或者 OR
//wrapper.nested(i -> i.eq("username", "李白").ne("age", 18)) ---> (username = '李白' and age <> 18)

apply

apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)

拼接 sql

注意事项:

该方法可用于数据库函数 动态入参的params对应前面applySql内部的{index}部分.这样是不会有sql注入风险的,反之会有!

//wrapper.apply("id = 1") ---> id = 1
//wrapper.apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'") ---> date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
//wrapper.apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08") ---> date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

last

last(String lastSql)
last(boolean condition, String lastSql)
//wrapper.last("limit 1")
  • 无视优化规则直接拼接到 sql 的最后

    注意事项:

    只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用

exists

exists(String existsSql)
exists(boolean condition, String existsSql)
//wrapper.exists("select id from table where age = 18") ---> exists (select id from table where age = 18)

notExists

notExists(String existsSql)
notExists(boolean condition, String existsSql)
//wrapper.notExists("select id from table where age = 18") ---> not exists (select id from table where age = 18)

QueryWrapper

说明:

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件 及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取

select

设置查询字段

select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
//wrapper.select("id", "name", "age")

说明:

以上方法分为两类. 第二类方法为:过滤查询字段(主键除外),入参不包含 class 的调用前需要wrapper内的entity属性有值! 这两类方法重复调用以最后一次为准

UpdateWrapper

说明:

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件 及 LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!

set

set(String column, Object val)
set(boolean condition, String column, Object val)
//wrapper.set("name", "李白")

setSql

setSql(String sql)
//wrapper.setSql("name = '李白'")

lambda

  • 获取 LambdaWrapperQueryWrapper中是获取LambdaQueryWrapperUpdateWrapper中是获取LambdaUpdateWrapper

使用 Wrapper 自定义SQL

注意事项:

需要mybatis-plus版本 >= 3.0.7 param 参数名要么叫ew,要么加上注解@Param(Constants.WRAPPER) 使用${ew.customSqlSegment} 不支持 Wrapper 内的entity生成where语句

用注解

@Select("select * from mysql_data ${ew.customSqlSegment}")
List<MysqlData> getAll(@Param(Constants.WRAPPER) Wrapper wrapper);

用XML

List<MysqlData> getAll(Wrapper ew);
<select id="getAll" resultType="MysqlData">
	SELECT * FROM mysql_data ${ew.customSqlSegment}
</select>

SpringBoot 集成 MyBatis-Plus

1、新建工程

image-20210425101629801

 

image-20210425101702083

image-20210425102213328

2、改pom文件

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!--数据源已MySQL为例-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>
    <!-- mybatis plus 代码生成器依赖 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.4.1</version>
    </dependency>
    <!-- 代码生成器模板 -->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.31</version>
    </dependency>
</dependencies>

3、编写yml文件

#指定端口,默认8080
server:
  port: 9000
#配置数据源
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://127.0.0.1:3306/demo?characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false&useSSL=true
    username: root
    password: root

#配置mybatisplus
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true #开启驼峰功能
    auto-mapping-behavior: full #mybatis核心配置文件中settings中配置,指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。默认是partial,这是一种全局设置
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: true #是否控制台 print mybatis-plus 的 LOGO
    db-config:
      id-type: auto #id 类型
      table-underline: true #表名是否使用下划线命名,默认数据库表使用下划线命名
#      logic-delete-value: 1 #逻辑已删除值默认1
#      logic-not-delete-value: 0 #逻辑未删除值默认0
  mapper-locations: classpath*:mapper/**/*Mapper.xml
  type-aliases-package: com.lovemio.mybatisplus.entity #实体的包路径,写resultType时可以直接写类名,不用再写全类名

#设置日志输出级别
logging:
  level:
    root: info
    com.lovemio.mybatisplus: debug

4、启动类

启动类添加注解@MapperScan 扫描mapper路径

@SpringBootApplication
@MapperScan("com.lovemio.mybatisplus.mapper")
public class SpringbootMybatisPlusApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisPlusApplication.class, args);
    }

}

5、配置分页插件

分页插件从3.4.0版本对此部分有更新,如果是旧版本升级,会出现分页失效问题,详见官网:

https://baomidou.com/guide/interceptor.html#mybatisplusinterceptor

/**
 * 配置分页插件
 *
 */
@Configuration
@MapperScan("com.lovemio.mybatisplus.mapper")//mapper所在位置
public class MybatisPlusConfig {

    /**3.4.0版本对此部分有更新,如果是旧版本升级,会出现分页失效问题,
     * 同时idea会提示PaginationInterceptor过时,新版本改用了MybatisPlusInterceptor
     * 旧版本配置
     * 分页插件
     */
   /*@Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }*/

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
     */
    @Bean
    public MybatisPlusInterceptor myBatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }
}

6、代码生成

测试表:user

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `nickname` varchar(255) DEFAULT NULL,
  `user_status` tinyint(4) DEFAULT NULL,
  `dep_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

代码生成器相关配置: https://baomidou.com/config/generator-config.html#datasource

官网有详细实例,参考: https://baomidou.com/guide/generator.html#%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B

注意:如果是子module形式,生成代码的位置需要加当前子Module的项目名

String projectPath = System.getProperty("user.dir")+"/springboot-mybatis-plus";//子项目名为springboot-mybatis-plus

public class CodeGenerator {

        /**
         * <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.toString());
            if (scanner.hasNext()) {
                String ipt = scanner.next();
                if (StringUtils.isNotBlank(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")+"/springboot-mybatis-plus";//如果是子项目,加上子项目名称,不然无法定位到当前项目的位置;
            gc.setOutputDir(projectPath + "/src/main/java");
            gc.setAuthor("lwj");
            gc.setOpen(false);//生成后打开文件目录
            //覆盖文件
            gc.setFileOverride(false);
            // gc.setSwagger2(true); 实体属性 Swagger2 注解
            mpg.setGlobalConfig(gc);

            // 数据源配置
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("jdbc:mysql://localhost:3306/demo?useUnicode=true&useSSL=false&characterEncoding=utf8");
            // dsc.setSchemaName("public");
            dsc.setDriverName("com.mysql.cj.jdbc.Driver");
            dsc.setUsername("root");
            dsc.setPassword("root");
            mpg.setDataSource(dsc);

            // 包配置
            PackageConfig pc = new PackageConfig();
//            pc.setModuleName(scanner("模块名"));
            pc.setParent("com.lovemio.mybatisplus");
            pc.setEntity("entity");
            pc.setMapper("mapper");
            pc.setService("service");
            pc.setServiceImpl("service.impl");
            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<FileOutConfig> 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("调用默认方法创建的目录,自定义目录用");
                if (fileType == FileType.MAPPER) {
                    // 已经生成 mapper 文件判断存在,不想重新生成返回 false
                    return !new File(filePath).exists();
                }
                // 允许生成模板文件
                return true;
            }
        });
        */
            cfg.setFileOutConfigList(focList);
            mpg.setCfg(cfg);

            // 配置模板
            TemplateConfig templateConfig = new TemplateConfig();

            // 配置自定义输出模板
            //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
            // templateConfig.setEntity("templates/entity2.java");
            // templateConfig.setService();
            // templateConfig.setController();
            templateConfig.setController("/ftl/controller.java");//如不自定义,注释即可

            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.mybatisplus.extension.activerecord.Model");//父类Entity,没有注释即可
            strategy.setEntityLombokModel(true);
            strategy.setRestControllerStyle(true);
            // 公共父类
//            strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
            // 写于父类中的公共字段
            strategy.setSuperEntityColumns("id");
            strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
            strategy.setControllerMappingHyphenStyle(true);
            strategy.setTablePrefix(pc.getModuleName() + "_");
            mpg.setStrategy(strategy);
            mpg.setTemplateEngine(new FreemarkerTemplateEngine());
            mpg.execute();
        }

    }

执行main方法,在控制台输入表名即可,表必须存在啊,不然生成个寂寞啊。

自定义模板示例:可根据自己需求生成对应的方法,具体写法可参考下边模板。

package ${package.Controller};


 import org.springframework.web.bind.annotation.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import com.lovemio.mybatisplus.service.${table.serviceName};
 import com.lovemio.mybatisplus.entity.${entity};
 import lombok.extern.slf4j.Slf4j;
 import com.lovemio.mybatisplus.utils.Result;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import java.util.List;
<#if restControllerStyle>
 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}
 * @version v1.0
 */
<#if restControllerStyle>
 @RestController
<#else>
 @Controller
</#if>
 @Slf4j
 @RequestMapping("<#if 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?substring(1))?uncap_first};

 /**
 * 查询分页数据
 */
 @RequestMapping(value = "/list")
 public Result findListByPage(@RequestParam(name = "pageNum", defaultValue = "1") int pageNum,@RequestParam(name = "pageSize", defaultValue = "20") int pageSize){
     Page<${entity}> page = ${(table.serviceName?substring(1))?uncap_first}.page(new Page<>(pageNum, pageSize));
     return Result.success(page);
 }


 /**
 * 根据id查询
 */
 @RequestMapping(value = "/getById")
 public Result getById(@RequestParam("id") String id){
    return Result.success(${(table.serviceName?substring(1))?uncap_first}.getById(id));
}

/**
* 新增
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Result add(@RequestBody ${entity} ${entity?uncap_first}){
    return Result.success(${(table.serviceName?substring(1))?uncap_first}.save(${entity?uncap_first}));
}

/**
* 删除
*/
@RequestMapping(value = "/del")
public Result del(@RequestParam("id") Integer id){
    return Result.success(${(table.serviceName?substring(1))?uncap_first}.removeById(id));
}

/**
* 批量删除
*/
@RequestMapping(value = "/batchDel")
public Result batchDel(@RequestParam("ids") List<String> ids){
return Result.success(${(table.serviceName?substring(1))?uncap_first}.removeByIds(ids));
}

/**
* 修改
*/
@RequestMapping(value = "/update", method = RequestMethod.POST)
public Result update(@RequestBody ${entity} ${entity?uncap_first}){
    return Result.success(${(table.serviceName?substring(1))?uncap_first}.saveOrUpdate(${entity?uncap_first}));
}

}
</#if>

其中,模板位置在resources/ftl 目录下

生成示例

image-20210425162758524

7、效果展示

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值