MyBatis-Plus 的分页插件 PaginationInnerInterceptor
提供了强大的分页功能,支持多种数据库,使得分页查询变得简单高效。
一.配置方法
在 Spring Boot 项目中,可以通过 Java 配置来添加分页插件:
一般在config包下定义配置类
/**
* 配置MP的分页插件
*/
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor myInterceptor(){
//1.定义mp拦截器
MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
//2.添加具体的拦截器
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mpInterceptor;
}
}
二.Controller层
在使用SSM框架时,进行查询操作需要根据前端传过来的数据 如(当前页码,每页显示条数,查询条件)先调用Controller层,下面是Controller层代码实现:
/**
* 分页查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
//构造分页构造器
Page pageInfo=new Page(page,pageSize);
//构造条件过滤器
LambdaQueryWrapper<Employee> queryWrapper=new LambdaQueryWrapper<>();
//添加过滤条件
queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
//添加排序条件
queryWrapper.orderByDesc(Employee::getUpdateTime);
//执行查询
employeeService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
这里根据前端需求不同设置不同返回值(这里我返回的是一个R类响应对象),这里的代码实现:
1.首先构造了分页构造器Page类是由分页插件 PaginationInnerInterceptor
提供的自己不用写,如果你需要实现自己的分页模型,可以继承 Page
类或实现 IPage
类。构造了Page对象,将前端传来的当前页码及每页条数封装到这个对象中。
2.创建了一个 LambdaQueryWrapper
对象 queryWrapper
,用于构建查询条件。LambdaQueryWrapper
是 MyBatis-Plus 提供的条件构造器,使用 Lambda 表达式简化条件的拼接。
3.使用 queryWrapper
对象的 like
方法添加了一个模糊查询条件。这里的意思是,如果 name
不为空,则按照 Employee
实体类的 getName
方法进行模糊查询,匹配 name
变量的值。
4.调用 queryWrapper
对象的 orderByDesc
方法,根据 Employee
实体类的 getUpdateTime
方法设定降序排序。这表示查询结果将按照 updateTime
字段的值,从新到旧进行排序。
5.调用 employeeService
的 page
方法进行分页查询。通常情况下,employeeService
是一个服务类,封装了业务逻辑和数据访问。page
方法接收两个参数:
pageInfo
:分页信息对象,用于指定当前页码、每页大小等信息。queryWrapper
:查询条件对象,包含了通过LambdaQueryWrapper
构建的条件和排序信息。
三.Service层
上面的employeeService.page(pageInfo,queryWrapper),page方法是Service 层的,下面是Service层实现:
//Service层接口
public interface EmployeeService extends IService<Employee> {
}
//Service层实现类
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
}
我们可以看出Service层并没有代码,那page方法是哪里来的呢?
我们可以看到Service继承了IService和ServiceImpl,下面说一下二者的关系:
在使用 MyBatis-Plus(或简称为 MP)时,通常会看到类似 com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
的类,这是 MyBatis-Plus 框架提供的一个服务实现类,它实现了一个通用的服务层接口,常用于简化开发过程。下面解释一下 ServiceImpl
和 IService
之间的关系以及使用它们的好处:
1. IService(服务接口)的作用:
- 定义业务接口:
IService
通常是一个业务接口,用于定义服务层的业务方法,包括增删改查等操作。 - 抽象业务逻辑: 通过接口的定义,将业务逻辑抽象出来,与具体的数据访问逻辑分离,增强代码的可维护性和可测试性。
- 规范代码结构: 使用接口定义服务层的方法,有助于团队成员理解和遵循统一的业务逻辑约定。
2. ServiceImpl(服务实现类)的作用:
- 实现具体业务逻辑:
ServiceImpl
是IService
接口的具体实现类,负责实现业务接口中定义的各种方法。 - 集成 MyBatis-Plus 的 CRUD 功能:
ServiceImpl
继承自 MyBatis-Plus 提供的Service
抽象类,已经包含了常见的 CRUD 操作方法,如save
、updateById
、removeById
等。 - 简化开发: 通过继承
ServiceImpl
,开发者可以直接使用其中封装好的通用方法,减少重复代码,提高开发效率。
使用它们的好处:
- 分层架构清晰: 使用
IService
和ServiceImpl
遵循了经典的分层架构模式,将业务逻辑与数据访问层分离,提高了代码的可维护性和扩展性。 - 开发效率提升:
ServiceImpl
提供了常用的数据库操作方法,减少了手动编写 CRUD 的工作量,使开发者可以更专注于业务逻辑的实现。 - 代码规范化: 规范了业务层代码的编写方式,使得团队成员可以快速理解和交流,减少因为编码风格不一致而引发的问题。
总之,使用 ServiceImpl
和 IService
结合 MyBatis-Plus,能够有效地提升项目的开发效率和代码质量,是现代 Java Web 开发中常见的最佳实践之一。
回归正轨,这里的page方法正是IService接口提供的默认方法,下面就是此方法(可以根据传的参数选择不同方法,这里使用的是带有查询条件的):
public interface IService<T> {
int DEFAULT_BATCH_SIZE = 1000;
BaseMapper<T> getBaseMapper();
default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectPage(page, queryWrapper);
}
default <E extends IPage<T>> E page(E page) {
return this.page(page, Wrappers.emptyWrapper());
}
}
四.Dao/Mapper层
在Service层中我们看见其调用了BaseMapper<T>中的selectPage(page, queryWrapper)方法,下面是Mapper层代码:
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}
我们看到里面也没有方法,正是继承了BaseMapper,下面解释一下BaseMapper:
BaseMapper
是 MyBatis-Plus 框架提供的核心接口之一,用于简化与数据库的交互操作。让我们来详细解释一下 BaseMapper
的作用和功能:
1. 概述
BaseMapper
是一个泛型接口,定义了一组对数据库的基本操作方法,包括插入、更新、删除、查询等操作。它为开发者提供了一种基于接口编程的方式来操作数据库,避免了手动编写大量的 CRUD(Create, Read, Update, Delete)操作代码。
2. 主要方法
以下是 BaseMapper
接口通常会提供的一些方法:
-
插入数据
int insert(T entity)
:插入一条数据。int insertBatch(@Param("list") Collection<T> entityList)
:批量插入数据。
-
更新数据
int updateById(T entity)
:根据主键更新一条数据。int update(T entity, @Param("updateWrapper") Wrapper<T> updateWrapper)
:根据条件更新实体包含的字段。
-
删除数据
int deleteById(Serializable id)
:根据主键删除数据。int delete(@Param("queryWrapper") Wrapper<T> queryWrapper)
:根据条件删除数据。
-
查询数据
T selectById(Serializable id)
:根据主键查询数据。List<T> selectBatchIds(@Param("idList") Collection<? extends Serializable> idList)
:根据主键集合批量查询。List<T> selectList(@Param("queryWrapper") Wrapper<T> queryWrapper)
:根据条件查询列表。
-
分页查询
IPage<T> selectPage(IPage<T> page, @Param("queryWrapper") Wrapper<T> queryWrapper)
:根据条件分页查询数据,并返回分页信息。
我们这里正是使用了分页查询这个方法,下面就是此方法:
public interface BaseMapper<T> extends Mapper<T> {
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
最后这个分页查询就这样完成了,我们看到我们好像配置了个分页插件 PaginationInnerInterceptor,然后在
Controller层写了方法,好像SQL语句都没有,就这么实现了?
没错,这就是MyBatis-Plus的强大之处,这里使用了MyBatis-Plus强大的 CRUD(创建、读取、更新、删除) 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求,BaseMapper<T>
接口中已经定义了一些通用的 CRUD 方法,如 insert
、updateById
、deleteById
、selectById
等,这些方法可以直接使用而无需手动编写 SQL。