MyBatis-Plus (简称 MP,下文就使用简称啦)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 有以下特性:
接下来本文会围绕Spring Boot
整合Mybatis-plus
,从引入、配置、使用等几个方面进行总结汇总,足以覆盖我们日常开发中绝大部分使用场景
使用IDEA创建一个Spring Boot项目,添加如下依赖:
<!-- MySQL连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!-- mp依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
配置文件添加数据源:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/db_test?&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
启动项目服务如下所示即为成功
首先先在数据库添加一个用户表:tb_user
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_no` varchar(255) NOT NULL COMMENT '编号',
`nickname` varchar(255) DEFAULT NULL COMMENT '昵称',
`email` varchar(255) DEFAULT NULL COMMENT '邮箱',
`phone` varchar(255) NOT NULL COMMENT '手机号',
`gender` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0:男生 1:女生',
`birthday` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '出生日期',
`is_delete` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标志 0:否 1:是',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
在项目服务中添加对应的实体类:User
@Data
@TableName(value = "tb_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String userNo;
private String nickname;
private String email;
private String phone;
private Integer gender;
private Date birthday;
private Integer isDelete;
private Date createTime;
private Date updateTime;
}
创建对应的mapper接口:UserDAO
,这里我以DAO结尾,平时习惯使用这个了
public interface UserDAO extends BaseMapper<User> {
}
最后启动类添加配置扫描:
@SpringBootApplication
@MapperScan(basePackages = "com.shepherd.mybatisplus.demo.dao")
public class MybatisPlusDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusDemoApplication.class, args);
}
}
添加测试类:
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTest {
@Resource
private UserService userService;
@Resource
private UserDAO userDAO;
/**
* 添加一条记录
*/
@Test
public void testAdd() {
User user = User.builder()
.id(1L)
.userNo("001")
.nickname("大哥")
.email("shepherd@qq.com")
.phone("1234556")
.birthday(new Date())
.build();
userDAO.insert(user);
}
/**
* 查询所有记录
*/
@Test
public void testList() {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
List<User> users = userDAO.selectList(queryWrapper);
System.out.println(users);
}
}
执行testAdd
插入方法之后,再执行testList
,控制台输出如下:
2023-11-08 16:50:58.514 INFO 12636 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2023-11-08 16:50:58.720 INFO 12636 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2023-11-08 16:50:58.734 DEBUG 12636 --- [ main] c.s.m.demo.dao.UserDAO.selectList : ==> Preparing: SELECT id,user_no,nickname,email,phone,gender,birthday,is_delete,create_time,update_time FROM tb_user
2023-11-08 16:50:58.763 DEBUG 12636 --- [ main] c.s.m.demo.dao.UserDAO.selectList : ==> Parameters:
2023-11-08 16:50:58.792 DEBUG 12636 --- [ main] c.s.m.demo.dao.UserDAO.selectList : <== Total: 1
[User(id=1, userNo=001, nickname=大哥, email=shepherd@qq.com, phone=1234556, gender=0, birthday=Wed Nov 08 16:26:58 CST 2023, isDelete=0, createTime=Wed Nov 08 16:26:58 CST 2023, updateTime=Wed Nov 08 16:26:58 CST 2023)]
上面的示例就是我们平时开发过程单表的基本CRUD操作,只需要创建好实体类,并创建一个继承自BaseMapper
的接口即可,是不是很简单,不需要我们有过多的编码和配置操作啥的。因为mp会自动做了数据库表名、字段名映射,Java类的驼峰命名和下划线字段之间的转化。
项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用
Github地址:https://github.com/plasticene/plasticene-boot-starter-parent
Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent
微信公众号:Shepherd进阶笔记
交流探讨qun:Shepherd_126
mp封装了很多注解供我们使用,下面我们就可以来看看常用的注解:
@TableName
表名注解,标识实体类对应的表,实体类的类名(转成小写后)和数据库表名相同时,可以不指定该注解。定义如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
public @interface TableName {
/**
* 实体对应的表名,实体类的类名(转成小写后)和数据库表名相同时,可以不指定
*/
String value() default "";
/**
* schema
*/
String schema() default "";
/**
* 是否保持使用全局的 tablePrefix 的值,只生效于 既设置了全局的 tablePrefix 也设置了上面 {@link #value()} 的值
* @since 3.1.1
*/
boolean keepGlobalPrefix() default false;
/**
* 实体映射结果集,
* 只生效与 mp 自动注入的 method
*/
String resultMap() default "";
/**
* 是否自动构建 resultMap 并使用,
* 只生效与 mp 自动注入的 method,
* 如果设置 resultMap 则不会进行 resultMap 的自动构建并注入,
* 只适合个别字段 设置了 typeHandler 或 jdbcType 的情况
*
* @since 3.1.2
*/
boolean autoResultMap() default false;
/**
* 需要排除的属性名
*/
String[] excludeProperty() default {};
}
这里对 autoResultMap
这个属性做如下说明强调:
MP 会自动构建一个 resultMap
并注入到 MyBatis 里(一般用不上),请注意以下内容:
因为 MP 底层是 MyBatis,所以 MP 只是帮您注入了常用 CRUD 到 MyBatis 里,注入之前是动态的(根据您的 Entity 字段以及注解变化而变化),但是注入之后是静态的(等于 XML 配置中的内容)。
而对于 typeHandler
属性,MyBatis 只支持写在 2 个地方:
insert
和 update
语句的 #{property}
中的 property
后面(例:#{property,typehandler=xxx.xxx.xxx}
),并且只作用于当前 设置值
除了以上两种直接指定 typeHandler
的形式,MyBatis 有一个全局扫描自定义 typeHandler
包的配置,原理是根据您的 property
类型去找其对应的 typeHandler
并使用。
综上所述,我们对实体类的某个字段自定义了typeHandler
,一定要开启autoResultMap=true
才能生效,如下所示:
@Data
@TableName(autoResultMap = true)
public class DataSource extends BaseDO implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private String host;
private String port;
@TableField(typeHandler = JsonStringSetTypeHandler.class)
private Set<String> databaseList;
private String userName;
@TableField(typeHandler = EncryptTypeHandler.class)
private String password;
private Integer type;
private Integer status;
}
@TableId
主键注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableId {
/**
* 字段值(驼峰命名方式,该值可无)
*/
String value() default "";
/**
* 主键ID
* {@link IdType}
*/
IdType type() default IdType.NONE;
}
名称 | 描述 |
---|---|
AUTO | 数据库自增ID |
NONE | 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) |
INPUT | 用户自己设置的ID |
ASSIGN_ID | 当用户传入为空时,自动分配类型为Number或String的主键(雪花算法) |
ASSIGN_UUID | 当用户传入为空时,自动分配类型为String的主键 |
@TableField
字段注解(非主键)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableField {
/**
* 数据库字段值
* <p>
* 不需要配置该值的情况:
* <li> 当 {@link com.baomidou.mybatisplus.core.MybatisConfiguration#mapUnderscoreToCamelCase} 为 true 时,
* (mp下默认是true,mybatis默认是false), 数据库字段值.replace("_","").toUpperCase() == 实体属性名.toUpperCase() </li>
* <li> 当 {@link com.baomidou.mybatisplus.core.MybatisConfiguration#mapUnderscoreToCamelCase} 为 false 时,
* 数据库字段值.toUpperCase() == 实体属性名.toUpperCase() </li>
*/
String value() default "";
/**
* 是否为数据库表字段
* <p>
* 默认 true 存在,false 不存在
*/
boolean exist() default true;
/**
* 字段 where 实体查询比较条件
* <p>
* 默认 {@link SqlCondition#EQUAL}
*/
String condition() default "";
/**
* 字段 update set 部分注入, 该注解优于 el 注解使用
* <p>
* 例1:@TableField(.. , update="%s+1") 其中 %s 会填充为字段
* 输出 SQL 为:update 表 set 字段=字段+1 where ...
* <p>
* 例2:@TableField(.. , update="now()") 使用数据库时间
* 输出 SQL 为:update 表 set 字段=now() where ...
*/
String update() default "";
/**
* 字段验证策略之 insert: 当insert操作时,该字段拼接insert语句时的策略
* <p>
* IGNORED: 直接拼接 insert into table_a(column) values (#{columnProperty});
* NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
* NOT_EMPTY: insert into table_a(<if test="columnProperty != null and columnProperty!=''">column</if>) values (<if test="columnProperty != null and columnProperty!=''">#{columnProperty}</if>)
* NOT_EMPTY 如果针对的是非 CharSequence 类型的字段则效果等于 NOT_NULL
*
* @since 3.1.2
*/
FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;
/**
* 字段验证策略之 update: 当更新操作时,该字段拼接set语句时的策略
* <p>
* IGNORED: 直接拼接 update table_a set column=#{columnProperty}, 属性为null/空string都会被set进去
* NOT_NULL: update table_a set <if test="columnProperty != null">column=#{columnProperty}</if>
* NOT_EMPTY: update table_a set <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
* NOT_EMPTY 如果针对的是非 CharSequence 类型的字段则效果等于 NOT_NULL
*
* @since 3.1.2
*/
FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;
/**
* 字段验证策略之 where: 表示该字段在拼接where条件时的策略
* <p>
* IGNORED: 直接拼接 column=#{columnProperty}
* NOT_NULL: <if test="columnProperty != null">column=#{columnProperty}</if>
* NOT_EMPTY: <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
* NOT_EMPTY 如果针对的是非 CharSequence 类型的字段则效果等于 NOT_NULL
*
* @since 3.1.2
*/
FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;
/**
* 字段自动填充策略
* <p>
* 在对应模式下将会忽略 insertStrategy 或 updateStrategy 的配置,等于断言该字段必有值
*/
FieldFill fill() default FieldFill.DEFAULT;
/**
* 是否进行 select 查询
* <p>
* 大字段可设置为 false 不加入 select 查询范围
*/
boolean select() default true;
/**
* 是否保持使用全局的 columnFormat 的值
* <p>
* 只生效于 既设置了全局的 columnFormat 也设置了上面 {@link #value()} 的值
* 如果是 false , 全局的 columnFormat 不生效
*
* @since 3.1.1
*/
boolean keepGlobalFormat() default false;
/**
* {@link ResultMapping#property} and {@link ParameterMapping#property}
*
* @since 3.4.4
*/
String property() default "";
/**
* JDBC类型 (该默认值不代表会按照该值生效),
* 只生效于 mp 自动注入的 method,
* 建议配合 {@link TableName#autoResultMap()} 一起使用
* <p>
* {@link ResultMapping#jdbcType} and {@link ParameterMapping#jdbcType}
*
* @since 3.1.2
*/
JdbcType jdbcType() default JdbcType.UNDEFINED;
/**
* 类型处理器 (该默认值不代表会按照该值生效),
* 只生效于 mp 自动注入的 method,
* 建议配合 {@link TableName#autoResultMap()} 一起使用
* <p>
* {@link ResultMapping#typeHandler} and {@link ParameterMapping#typeHandler}
*
* @since 3.1.2
*/
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
/**
* 只在使用了 {@link #typeHandler()} 时判断是否辅助追加 javaType
* <p>
* 一般情况下不推荐使用
* {@link ParameterMapping#javaType}
*
* @since 3.4.0 @2020-07-23
*/
boolean javaType() default false;
/**
* 指定小数点后保留的位数,
* 只生效于 mp 自动注入的 method,
* 建议配合 {@link TableName#autoResultMap()} 一起使用
* <p>
* {@link ParameterMapping#numericScale}
*
* @since 3.1.2
*/
String numericScale() default "";
}
其他注解就不一一叙述,想了解更多直接查看官网文档即可,上面是我们日常开发经常使用的,足够了。
mp封装了一些最基础的CRUD方法,只需要直接继承mp提供的接口,无需编写任何SQL,即可食用。mp提供了两套接口,分别是Mapper CRUD
接口和Service CRUD
接口。并且mp还提供了条件构造器Wrapper
,可以方便地组装SQL语句中的WHERE条件。
通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行
remove 删除
list 查询集合
page 分页
首先,新建一个接口,继承IService
public interface UserService extends IService<User> {
}
创建这个接口的实现类,并继承ServiceImpl
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserDAO, User> implements UserService {
}
最后使用userSerive
就可以调用相关方法
mp将常用的CRUD接口封装成了BaseMapper
接口,我们只需要在自己的Mapper中继承它就可以了:
@Mapper
public interface UserDAO extends BaseMapper<User> {
}
mp让我觉得极其方便的一点在于其提供了强大的条件构造器Wrapper
,可以非常方便的构造WHERE条件。条件构造器封装抽象类:AbstractWrapper
,他是QueryWrapper(LambdaQueryWrapper)
和 UpdateWrapper(LambdaUpdateWrapper)
的父类
用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件。
allEq
allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNul
全部eq(或个别isNull)
个别参数说明:
params
: key
为数据库字段名,value
为字段值null2IsNull
: 为true
则在map
的value
为null
时调用 isNull 方法,为false
时则忽略value
为null
的
例1: allEq({id:1,name:"老王",age:null})
--->id = 1 and name = '老王' and age is null
例2: allEq({id:1,name:"老王",age:null}, false)
--->id = 1 and name = '老王'
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)
个别参数说明:
filter
: 过滤函数,是否允许字段传入比对条件中params
与 null2IsNull
: 同上
allEq((k,v) -> k.contains("a"), {id:1,name:"老王",age:null})
--->name = '老王' and age is null
allEq((k,v) -> k.contains("a"), {id:1,name:"老王",age:null}, false)
--->name = '老王'
eq
eq(R column, Object val)
eq(boolean condition, R column, Object val)
eq("name", "老王")
--->name = '老王'
ne
ne(R column, Object val)
ne(boolean condition, R column, Object val)
ne("name", "老王")
--->name <> '老王'
gt
gt(R column, Object val)
gt(boolean condition, R column, Object val)
gt("age", 18)
--->age > 18
ge
ge(R column, Object val)
ge(boolean condition, R column, Object val)
ge("age", 18)
--->age >= 18
lt
lt(R column, Object val)
lt(boolean condition, R column, Object val)
lt("age", 18)
--->age < 18
le
le(R column, Object val)
le(boolean condition, R column, Object val)
le("age", 18)
--->age <= 18
between
between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)
between("age", 18, 30)
--->age between 18 and 30
notBetween
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
notBetween("age", 18, 30)
--->age not between 18 and 30
like
like(R column, Object val)
like(boolean condition, R column, Object val)
like("name", "王")
--->name like '%王%'
notLike
notLike(R column, Object val)
notLike(boolean condition, R column, Object val)
notLike("name", "王")
--->name not like '%王%'
likeLeft
likeLeft(R column, Object val)
likeLeft(boolean condition, R column, Object val)
likeLeft("name", "王")
--->name like '%王'
likeRight
likeRight(R column, Object val)
likeRight(boolean condition, R column, Object val)
likeRight("name", "王")
--->name like '王%'
notLikeLeft
notLikeLeft(R column, Object val)
notLikeLeft(boolean condition, R column, Object val)
notLikeLeft("name", "王")
--->name not like '%王'
notLikeRight
notLikeRight(R column, Object val)
notLikeRight(boolean condition, R column, Object val)
notLikeRight("name", "王")
--->name not like '王%'
isNull
isNull(R column)
isNull(boolean condition, R column)
isNull("name")
--->name is null
isNotNull
isNotNull(R column)
isNotNull(boolean condition, R column)
isNotNull("name")
--->name is not null
in
in(R column, Collection<?> value)
in(boolean condition, R column, Collection<?> value)
in("age",{1,2,3})
--->age in (1,2,3)
in(R column, Object... values)
in(boolean condition, R column, Object... values)
in("age", 1, 2, 3)
--->age in (1,2,3)
notIn
notIn(R column, Collection<?> value)
notIn(boolean condition, R column, Collection<?> value)
notIn("age",{1,2,3})
--->age not in (1,2,3)
notIn(R column, Object... values)
notIn(boolean condition, R column, Object... values)
notIn("age", 1, 2, 3)
--->age not in (1,2,3)
inSql
inSql(R column, String inValue)
inSql(boolean condition, R column, String inValue)
inSql("age", "1,2,3,4,5,6")
--->age in (1,2,3,4,5,6)
inSql("id", "select id from table where id < 3")
--->id in (select id from table where id < 3)
notInSql
notInSql(R column, String inValue)
notInSql(boolean condition, R column, String inValue)
notInSql("age", "1,2,3,4,5,6")
--->age not in (1,2,3,4,5,6)
notInSql("id", "select id from table where id < 3")
--->id not in (select id from table where id < 3)
groupBy
groupBy(R... columns)
groupBy(boolean condition, R... columns)
groupBy("id", "name")
--->group by id,name
orderByAsc
orderByAsc(R... columns)
orderByAsc(boolean condition, R... columns)
orderByAsc("id", "name")
--->order by id ASC,name ASC
orderByDesc
orderByDesc(R... columns)
orderByDesc(boolean condition, R... columns)
orderByDesc("id", "name")
--->order by id DESC,name DESC
orderBy
orderBy(boolean condition, boolean isAsc, R... columns)
orderBy(true, true, "id", "name")
--->order by id ASC,name ASC
having
having(String sqlHaving, Object... params)
having(boolean condition, String sqlHaving, Object... params)
having("sum(age) > 10")
--->having sum(age) > 10
having("sum(age) > {0}", 11)
--->having sum(age) > 11
func
func(Consumer<Children> consumer)
func(boolean condition, Consumer<Children> consumer)
func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})
or
or()
or(boolean condition)
拼接 OR
注意事项:
主动调用or
表示紧接着下一个方法不是用and
连接!(不调用or
则默认为使用and
连接)
例: eq("id",1).or().eq("name","老王")
--->id = 1 or name = '老王'
or(Consumer<Param> consumer)
or(boolean condition, Consumer<Param> consumer)
or(i -> i.eq("name", "李白").ne("status", "活着"))
--->or (name = '李白' and status <> '活着')
and
and(Consumer<Param> consumer)
and(boolean condition, Consumer<Param> consumer)
and(i -> i.eq("name", "李白").ne("status", "活着"))
--->and (name = '李白' and status <> '活着')
nested
nested(Consumer<Param> consumer)
nested(boolean condition, Consumer<Param> consumer)
nested(i -> i.eq("name", "李白").ne("status", "活着"))
--->(name = '李白' and status <> '活着')
exists
exists(String existsSql)
exists(boolean condition, String existsSql)
exists("select id from table where age = 1")
--->exists (select id from table where age = 1)
notExists
notExists(String notExistsSql)
notExists(boolean condition, String notExistsSql)
notExists("select id from table where age = 1")
--->not exists (select id from table where age = 1)
QueryWrapper
说明:
继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件 及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取
select
select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
设置查询字段
说明:
以上方法分为两类.
第二类方法为:过滤查询字段(主键除外),入参不包含 class 的调用前需要wrapper
内的entity
属性有值! 这两类方法重复调用以最后一次为准
例: select("id", "name", "age")
例: select(i -> i.getProperty().startsWith("test"))
UpdateWrapper
说明:
继承自 AbstractWrapper
,自身的内部属性 entity
也用于生成 where 条件
及 LambdaUpdateWrapper
, 可以通过 new UpdateWrapper().lambda()
方法获取!
set
set(String column, Object val)
set(boolean condition, String column, Object val)
set("name", "老李头")
set("name", "")
--->数据库字段值变为空字符串set("name", null)
--->数据库字段值变为null
lambda
LambdaWrapper
在QueryWrapper
中是获取LambdaQueryWrapper
在UpdateWrapper
中是获取LambdaUpdateWrapper
分页
使用分页话需要增加分页插件的配置
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
最后来个示例看看上面的条件构造器是怎么用的:
@Override
public List<BrandDTO> getList(BrandQuery query) {
LambdaQueryWrapper<Brand> queryWrapper = new LambdaQueryWrapper<>();
if (query.getCategoryId() != null) {
queryWrapper.eq(Brand::getCategoryId, query.getCategoryId());
}
if (StringUtils.isNotBlank(query.getLetter())) {
queryWrapper.eq(Brand::getLetter, query.getLetter());
}
if (StringUtils.isNotBlank(query.getName())) {
queryWrapper.likeRight(Brand::getName, query.getName());
}
List<BrandDTO> brandDTOList = brandDAO.selectList(queryWrapper).stream().map(brand -> toBrandDTO(brand)).collect(Collectors.toList());
return brandDTOList;
}
本文系作者在时代Java发表,未经许可,不得转载。
如有侵权,请联系nowjava@qq.com删除。