我希望如春天般的你,身着白色的婚纱,向我奔赴而来,我愿意用全世界最温情的目光,朝着你的方向望去——姗姗来迟。
https://baomidou.com/pages/2976a3/#mybatisplusinterceptor 官方文档
首先,我们都知道Mybatis Plus
是Mybatis
的升级版,只做了功能增强,不做代码变动,现在我们就对于Mybatis Plus
的分页实现做一个介绍概括!
MyBatis-Plus
分页实现主要通过Page
对象来实现,该对象封装了分页相关的信息,例如当前页码、每页记录数等。以下是MyBatis-Plus分页实现的概述:
Page对象: MyBatis-Plus使用Page
对象来表示分页信息。这个对象包含了当前页码、每页记录数、总记录数等信息。
分页查询方法: 在进行查询时,你可以通过传递Page
对象来告诉MyBatis-Plus你需要进行分页查询。MyBatis-Plus会在执行查询语句时,根据Page
对象的信息生成对应的分页SQL语句。
分页插件: MyBatis-Plus提供了分页插件,可以在项目配置中进行配置。这个插件会在执行SQL前自动拦截,根据Page
对象的信息生成对应的分页SQL,并在查询结果中封装到Page
对象中。
返回结果: 分页查询的结果将被封装到Page
对象中,你可以通过该对象获取分页相关的信息,例如总记录数、总页数等,以及实际的查询结果列表。
总体而言,MyBatis-Plus
分页实现简化了分页查询的操作,通过传递Page
对象即可轻松实现分页查询,无需手动编写复杂的分页SQL语句。这使得分页操作更加方便,同时也提高了代码的可维护性。
依赖导入
首先,要想完成代码演示和功能实现,我们需要再pom文件中加入如下依赖
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>com.mysqlgroupId>
<artifactId>mysql-connector-jartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.2.20version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.3.1version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>jakarta.validationgroupId>
<artifactId>jakarta.validation-apiartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.8.22version>
dependency>
<dependency>
<groupId>com.github.yulichanggroupId>
<artifactId>mybatis-plus-join-coreartifactId>
<version>1.4.7version>
dependency>
dependencies>
当然,让我们逐个介绍这些依赖项:
org.springframework.boot:spring-boot-starter-web:
org.springframework.boot:spring-boot-starter-test:
com.mysql:mysql-connector-j:
com.alibaba:druid-spring-boot-starter:1.2.20:
com.baomidou:mybatis-plus-boot-starter:3.5.3.1:
org.projectlombok:lombok:
jakarta.validation:jakarta.validation-api:2.0.2:
cn.hutool:hutool-all:5.8.22:
com.github.yulichang:mybatis-plus-join-core:1.4.7:
基础配置
server:
port: 8181
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/yudao?useUnicode=true&characterEncoding=UTF-8
username: root
password: root
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
typeAliasesPackage: com.cnbai.*.*
global-config:
db-config:
id-type: AUTO
# 数据库字段驼峰下划线转换
db-column-underline: true
refresh-mapper: true
configuration:
# 自动驼峰命名
map-underscore-to-camel-case: true
# 查询结果中包含空值的列,在映射的时候,不会映射这个字段
call-setters-on-nulls: true
# 开启 sql 日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 关闭 sql 日志
# log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
这是一个Spring Boot项目的配置文件,主要包含了服务器端口、数据库连接信息以及MyBatis-Plus的配置。下面是对其中的关键配置项的解读:
server.port
: 配置了应用的端口号,这里设置为8181。
spring.datasource
: 配置了数据源相关信息。
driver-class-name
: 指定了数据库驱动的类名。url
: 指定了数据库连接的URL,包括数据库类型、主机地址、端口号以及数据库名称等。username
和 password
: 指定了数据库的用户名和密码。mybatis-plus.mapper-locations
: 指定了MyBatis Mapper XML 文件的位置。
mybatis-plus.typeAliasesPackage
: 指定了MyBatis扫描实体类别名的包路径。
mybatis-plus.global-config
: 全局配置,包括数据库配置和刷新映射器。
db-config.id-type
: 设置主键生成策略,这里设定为自动增长。db-config.db-column-underline
: 数据库字段驼峰下划线转换,设置为true表示启用。db-config.refresh-mapper
: 刷新映射器,设置为true表示刷新XML中的缓存。mybatis-plus.configuration
: MyBatis 配置项。
map-underscore-to-camel-case
: 开启自动驼峰命名。call-setters-on-nulls
: 查询结果中包含空值的列,在映射时不会映射这个字段,设置为true表示调用setter方法设置null值。log-impl
: 开启 SQL 日志,这里设置为在控制台输出。总体而言,这份配置文件包括了服务器端口、数据库连接信息,以及MyBatis-Plus的配置,其中包含了数据库驱动、URL、用户名、密码、Mapper XML 文件位置、实体类别名扫描包路径等。 MyBatis-Plus的配置包括了全局配置和MyBatis的一些常用配置,如主键生成策略、字段命名策略、映射器刷新等。
这是一个使用MyBatis-Plus的配置类,主要用于配置分页插件。让我对这段代码进行解读一下:
@Configuration
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
return interceptor;
}
}
@Configuration
: 这个注解表示这是一个配置类,会被Spring容器扫描并加载。
@Bean
: 这个注解标志着这是一个Bean的定义方法,它将返回一个被Spring管理的对象。
MybatisPlusInterceptor
: 这是MyBatis-Plus提供的插件拦截器,用于自定义MyBatis的行为。
mybatisPlusInterceptor()
: 这个方法用于创建并配置MybatisPlusInterceptor
的实例。
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL))
: 这行代码添加了一个内部插件,即PaginationInnerInterceptor
,用于实现分页功能。DbType.MYSQL
指定了数据库类型为MySQL。如果有多个插件,要确保分页插件是最后一个添加,以确保正确的执行顺序。
总体来说,这段配置代码的作用是创建一个MyBatis-Plus的拦截器,配置了分页插件,确保在进行数据库查询时自动添加分页的功能。这样,你在使用MyBatis-Plus进行分页查询时就无需手动编写分页SQL,而是通过配置实现了分页的自动化。
PageParam
分页基础实体类import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
@Data
public class PageParam implements Serializable {
private static final Integer PAGE_NO = 1;
private static final Integer PAGE_SIZE = 10;
/**
* 每页条数 - 不分页
*
* 例如说,导出接口,可以设置 {@link #pageSize} 为 -1 不分页,查询所有数据。
*/
public static final Integer PAGE_SIZE_NONE = -1;
@NotNull(message = "页码不能为空")
@Min(value = 1, message = "页码最小值为 1")
private Integer pageNo = PAGE_NO;
@NotNull(message = "每页条数不能为空")
@Min(value = 1, message = "每页条数最小值为 1")
@Max(value = 100, message = "每页条数最大值为 100")
private Integer pageSize = PAGE_SIZE;
}
这个类定义了用于分页查询的参数,通过 Lombok 注解减少了冗长的 getter 和 setter 方法的编写,而通过 Bean Validation 注解确保了参数的合法性。其中,通过静态常量和注释提供了对默认分页参数和不分页情况的解释
PageResult
分页基础实体类import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Data
public final class PageResult<T> implements Serializable {
private List<T> list;
private Long total;
public PageResult() {
}
public PageResult(List<T> list, Long total) {
this.list = list;
this.total = total;
}
public PageResult(Long total) {
this.list = new ArrayList<>();
this.total = total;
}
public static <T> PageResult<T> empty() {
return new PageResult<>(0L);
}
public static <T> PageResult<T> empty(Long total) {
return new PageResult<>(total);
}
}
这是一个用于表示分页查询结果的 Java 类 PageResult
,使用 Lombok 的 @Data
注解简化了 getter、setter、toString 等方法的编写。下面是对该类的解读:
PageResult
是一个泛型类,使用了
来表示泛型类型,用于表示分页查询的结果。
list
属性:表示分页查询的结果列表,其中的泛型 T
表示每个元素的类型。
total
属性:表示总记录数,即满足查询条件的所有记录的数量。
有多个构造方法:
PageResult
对象。List list, Long total
):用于接收查询结果列表和总记录数。Long total
):用于接收总记录数,结果列表初始化为空列表。静态方法:
empty()
: 返回一个空的 PageResult
,总记录数为 0。empty(Long total)
: 返回一个空的 PageResult
,可以指定总记录数。这个类的设计主要是用于封装分页查询的结果,提供了一些方便的构造方法和静态方法,使得在业务代码中使用起来更加简洁。
在MyBatis Plus 的 BaseMapper 的基础上拓展
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.interfaces.MPJBaseJoin;
import com.page.demo.common.mybatis.core.query.MyBatisUtils;
import com.page.demo.common.pojo.PageParam;
import com.page.demo.common.pojo.PageResult;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
/**
* 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
*
* 1. {@link BaseMapper} 为 MyBatis Plus 的基础接口,提供基础的 CRUD 能力
* 2. {@link MPJBaseMapper} 为 MyBatis Plus Join 的基础接口,提供连表 Join 能力
*/
public interface BaseMapperX<T> extends MPJBaseMapper<T> {
default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
// 特殊:不分页,直接查询全部
if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageNo())) {
List<T> list = selectList(queryWrapper);
return new PageResult<>(list, (long) list.size());
}
// MyBatis Plus 查询
IPage<T> mpPage = MyBatisUtils.buildPage(pageParam);
selectPage(mpPage, queryWrapper);
// 转换返回
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
}
default <DTO> PageResult<DTO> selectJoinPage(PageParam pageParam, Class<DTO> resultTypeClass, MPJBaseJoin<T> joinQueryWrapper) {
IPage<DTO> mpPage = MyBatisUtils.buildPage(pageParam);
selectJoinPage(mpPage, resultTypeClass, joinQueryWrapper);
// 转换返回
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
}
default T selectOne(String field, Object value) {
return selectOne(new QueryWrapper<T>().eq(field, value));
}
default T selectOne(SFunction<T, ?> field, Object value) {
return selectOne(new LambdaQueryWrapper<T>().eq(field, value));
}
default T selectOne(String field1, Object value1, String field2, Object value2) {
return selectOne(new QueryWrapper<T>().eq(field1, value1).eq(field2, value2));
}
default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
}
default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
SFunction<T, ?> field3, Object value3) {
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
.eq(field3, value3));
}
default Long selectCount() {
return selectCount(new QueryWrapper<>());
}
default Long selectCount(String field, Object value) {
return selectCount(new QueryWrapper<T>().eq(field, value));
}
default Long selectCount(SFunction<T, ?> field, Object value) {
return selectCount(new LambdaQueryWrapper<T>().eq(field, value));
}
default List<T> selectList() {
return selectList(new QueryWrapper<>());
}
default List<T> selectList(String field, Object value) {
return selectList(new QueryWrapper<T>().eq(field, value));
}
default List<T> selectList(SFunction<T, ?> field, Object value) {
return selectList(new LambdaQueryWrapper<T>().eq(field, value));
}
default List<T> selectList(String field, Collection<?> values) {
if (CollUtil.isEmpty(values)) {
return CollUtil.newArrayList();
}
return selectList(new QueryWrapper<T>().in(field, values));
}
default List<T> selectList(SFunction<T, ?> field, Collection<?> values) {
if (CollUtil.isEmpty(values)) {
return CollUtil.newArrayList();
}
return selectList(new LambdaQueryWrapper<T>().in(field, values));
}
@Deprecated
default List<T> selectList(SFunction<T, ?> leField, SFunction<T, ?> geField, Object value) {
return selectList(new LambdaQueryWrapper<T>().le(leField, value).ge(geField, value));
}
default List<T> selectList(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
return selectList(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
}
/**
* 批量插入,适合大量数据插入
*
* @param entities 实体们
*/
default void insertBatch(Collection<T> entities) {
Db.saveBatch(entities);
}
/**
* 批量插入,适合大量数据插入
*
* @param entities 实体们
* @param size 插入数量 Db.saveBatch 默认为 1000
*/
default void insertBatch(Collection<T> entities, int size) {
Db.saveBatch(entities, size);
}
default void updateBatch(T update) {
update(update, new QueryWrapper<>());
}
default void updateBatch(Collection<T> entities) {
Db.updateBatchById(entities);
}
default void updateBatch(Collection<T> entities, int size) {
Db.updateBatchById(entities, size);
}
default void insertOrUpdate(T entity) {
Db.saveOrUpdate(entity);
}
default void insertOrUpdateBatch(Collection<T> collection) {
Db.saveOrUpdateBatch(collection);
}
default int delete(String field, String value) {
return delete(new QueryWrapper<T>().eq(field, value));
}
default int delete(SFunction<T, ?> field, Object value) {
return delete(new LambdaQueryWrapper<T>().eq(field, value));
}
}
这是一个自定义的 MyBatis Plus 的 Mapper 接口 BaseMapperX
,该接口继承了 MPJBaseMapper
。下面是对该接口的主要内容进行解读:
BaseMapperX
继承了 MPJBaseMapper
,这表示该 Mapper 接口扩展了 MyBatis Plus 的基础 Mapper 接口,并具有更多的能力。
接口中包含了一系列的默认方法,这些方法提供了更方便的数据库操作。以下是其中的几个方法的说明:
selectPage
: 根据传入的分页参数和查询条件,进行分页查询并返回 PageResult
。
selectJoinPage
: 进行关联查询,支持连表 Join 操作,返回 PageResult
,其中 DTO 是关联查询结果的数据传输对象。
selectOne
系列方法:根据传入的条件查询单个对象。
selectCount
系列方法:根据条件查询符合条件的记录数量。
selectList
系列方法:根据条件查询符合条件的记录列表。
insertBatch
系列方法:批量插入数据。
updateBatch
系列方法:批量更新数据。
insertOrUpdate
和 insertOrUpdateBatch
:插入或更新数据。
delete
系列方法:根据条件删除数据。
该接口中使用了一些 MyBatis Plus 的条件构造器,如 QueryWrapper
和 LambdaQueryWrapper
,用于构建查询条件。
在一些批量操作方法中,使用了 Db
类提供的方法,该类提供了一些数据库操作的工具方法,例如批量插入、批量更新等。
总体而言,BaseMapperX
接口提供了一组扩展的数据库操作方法,使得在使用 MyBatis Plus 进行数据库操作时更加方便和灵活。
LambdaQueryWrapperX
优化构建器import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import org.springframework.util.StringUtils;
import java.util.Collection;
/**
* 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能:
*
* 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。
*
* @param 数据类型
*/
public class LambdaQueryWrapperX<T> extends LambdaQueryWrapper<T> {
public LambdaQueryWrapperX<T> likeIfPresent(SFunction<T, ?> column, String val) {
if (StringUtils.hasText(val)) {
return (LambdaQueryWrapperX<T>) super.like(column, val);
}
return this;
}
public LambdaQueryWrapperX<T> inIfPresent(SFunction<T, ?> column, Collection<?> values) {
if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
return (LambdaQueryWrapperX<T>) super.in(column, values);
}
return this;
}
public LambdaQueryWrapperX<T> inIfPresent(SFunction<T, ?> column, Object... values) {
if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
return (LambdaQueryWrapperX<T>) super.in(column, values);
}
return this;
}
public LambdaQueryWrapperX<T> eqIfPresent(SFunction<T, ?> column, Object val) {
if (ObjectUtil.isNotEmpty(val)) {
return (LambdaQueryWrapperX<T>) super.eq(column, val);
}
return this;
}
public LambdaQueryWrapperX<T> neIfPresent(SFunction<T, ?> column, Object val) {
if (ObjectUtil.isNotEmpty(val)) {
return (LambdaQueryWrapperX<T>) super.ne(column, val);
}
return this;
}
public LambdaQueryWrapperX<T> gtIfPresent(SFunction<T, ?> column, Object val) {
if (val != null) {
return (LambdaQueryWrapperX<T>) super.gt(column, val);
}
return this;
}
public LambdaQueryWrapperX<T> geIfPresent(SFunction<T, ?> column, Object val) {
if (val != null) {
return (LambdaQueryWrapperX<T>) super.ge(column, val);
}
return this;
}
public LambdaQueryWrapperX<T> ltIfPresent(SFunction<T, ?> column, Object val) {
if (val != null) {
return (LambdaQueryWrapperX<T>) super.lt(column, val);
}
return this;
}
public LambdaQueryWrapperX<T> leIfPresent(SFunction<T, ?> column, Object val) {
if (val != null) {
return (LambdaQueryWrapperX<T>) super.le(column, val);
}
return this;
}
public LambdaQueryWrapperX<T> betweenIfPresent(SFunction<T, ?> column, Object val1, Object val2) {
if (val1 != null && val2 != null) {
return (LambdaQueryWrapperX<T>) super.between(column, val1, val2);
}
if (val1 != null) {
return (LambdaQueryWrapperX<T>) ge(column, val1);
}
if (val2 != null) {
return (LambdaQueryWrapperX<T>) le(column, val2);
}
return this;
}
// ========== 重写父类方法,方便链式调用 ==========
@Override
public LambdaQueryWrapperX<T> eq(boolean condition, SFunction<T, ?> column, Object val) {
super.eq(condition, column, val);
return this;
}
@Override
public LambdaQueryWrapperX<T> eq(SFunction<T, ?> column, Object val) {
super.eq(column, val);
return this;
}
@Override
public LambdaQueryWrapperX<T> orderByDesc(SFunction<T, ?> column) {
super.orderByDesc(true, column);
return this;
}
@Override
public LambdaQueryWrapperX<T> last(String lastSql) {
super.last(lastSql);
return this;
}
@Override
public LambdaQueryWrapperX<T> in(SFunction<T, ?> column, Collection<?> coll) {
super.in(column, coll);
return this;
}
}
这是一个拓展了 MyBatis Plus 的 LambdaQueryWrapper
类的 LambdaQueryWrapperX
类。主要增加了一些方法,用于在条件拼接时判断值是否存在,从而决定是否拼接到条件中。以下是对该类的解读:
LambdaQueryWrapperX
继承了 LambdaQueryWrapper
,表示该类是对 LambdaQueryWrapper
的拓展。
该类提供了一系列的拓展方法,如 likeIfPresent
、inIfPresent
、eqIfPresent
等,这些方法都带有 IfPresent
后缀,表示当值存在时才进行条件拼接,避免了值为 null 或空时拼接条件。
这些拓展方法在条件拼接时先判断了值的存在性,如果值存在才进行条件拼接,否则不拼接。
重写了父类的一些方法,以方便链式调用,例如 eq
、orderByDesc
、last
、in
等。
总体而言,该类通过增加带有 IfPresent
后缀的拓展方法,使得在使用 LambdaQueryWrapper
进行条件拼接时更加方便,减少了空值或 null 值导致的冗余条件拼接。
@Data
@TableName(value = "test_student")
public class Student {
@TableId
private Long stuId;
private String stuName;
private Long stuAge;
private String className;
}
@Data
@EqualsAndHashCode(callSuper = true)
public class StudentPageReqVO extends PageParam {
private String stuName;
private String className;
}
在这里有必要做一个解释,为什么创建一个请求视图对象
创建请求视图对象(Request View Object,简称Request VO)有几个主要原因,尤其在Web开发中:
封装请求参数: Request VO 提供了一种将请求参数封装到一个对象中的方式。这样做有助于减少控制器(Controller)层中的方法签名中的参数数量。在处理复杂的请求,特别是包含多个参数的请求时,将它们组织成一个对象可以提高代码的清晰度和可读性。
传递前端数据: 在Web应用中,前端通常以 JSON 或其他数据格式将数据传递给后端。Request VO 用于在前端和后端之间传递数据,尤其是在处理复杂的表单提交或查询条件时。通过使用 Request VO,可以更方便地将前端的数据映射到后端的处理逻辑中。
解耦前后端: Request VO 有助于解耦前端和后端的实现细节。前端可以更自由地修改请求参数的结构,而后端的处理逻辑不会受到太大影响,只需保证 Request VO 中的字段与后端期望的数据结构相匹配即可。
提高代码复用性: Request VO 可以作为方法参数,提高了代码的复用性。例如,多个控制器方法可能需要相似的请求参数,通过使用相同的 Request VO,可以减少重复的代码。
易于维护: 维护 Request VO 可以更方便地处理接口变更。如果请求参数的结构发生变化,只需更新 Request VO 中的字段,而无需修改控制器方法的签名。
总体而言,创建请求视图对象是一种良好的实践,有助于组织和管理请求参数,提高代码的可读性、可维护性,并支持前后端的解耦。
extends PageParam
表示一个类继承了 PageParam
,这种情况通常发生在使用某个框架或库提供的分页功能时。
import com.page.demo.common.mybatis.core.query.LambdaQueryWrapperX;
import com.page.demo.common.mybatis.core.query.mapper.BaseMapperX;
import com.page.demo.common.pojo.PageResult;
import com.page.demo.domain.Student;
import com.page.demo.domain.StudentPageReqVO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface StudentMapper extends BaseMapperX<Student> {
default PageResult<Student> getStudentList(StudentPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<Student>()
.likeIfPresent(Student::getStuName, reqVO.getStuName())
.likeIfPresent(Student::getClassName, reqVO.getClassName())
.orderByDesc(Student::getStuId));
}
}
在这里我们可以看到,我们有三个自定义的基础工具类
com.page.demo.common.mybatis.core.query.LambdaQueryWrapperX; com.page.demo.common.mybatis.core.query.mapper.BaseMapperX; com.page.demo.common.pojo.PageResult;
就是我们首先创建的工具对象。
这是一个在 StudentMapper
接口中定义的默认方法,用于获取学生列表并返回分页结果 PageResult
。以下是对该方法的解读:
方法签名:
default PageResult<Student> getStudentList(StudentPageReqVO reqVO)
PageResult
,表示分页查询的结果,其中 Student
是学生实体类。getStudentList
,用于获取学生列表。StudentPageReqVO reqVO
,是一个请求视图对象,用于传递查询条件。方法实现:
return selectPage(reqVO, new LambdaQueryWrapperX<Student>()
.likeIfPresent(Student::getStuName, reqVO.getStuName())
.likeIfPresent(Student::getClassName, reqVO.getClassName())
.orderByDesc(Student::getStuId));
selectPage
是在 BaseMapperX
接口中定义的方法,用于执行分页查询。reqVO
作为查询条件传入。new LambdaQueryWrapperX()
创建了一个带有条件判断的 LambdaQueryWrapper 实例,该实例是对 MyBatis Plus 的 LambdaQueryWrapper 进行了扩展,使得条件在值存在时才拼接到查询条件中。.likeIfPresent(Student::getStuName, reqVO.getStuName())
:如果 reqVO.getStuName()
不为空,则添加一个类似于 like
的条件,即根据学生姓名模糊查询。.likeIfPresent(Student::getClassName, reqVO.getClassName())
:如果 reqVO.getClassName()
不为空,则添加一个类似于 like
的条件,即根据班级名称模糊查询。.orderByDesc(Student::getStuId)
:按照学生编号降序排列结果。返回结果:
PageResult
中。总体而言,这个方法实现了根据给定的条件(从 reqVO
中获取)进行学生列表的分页查询,使用了 MyBatis Plus 提供的分页查询功能,并且在查询条件拼接时使用了自定义的 LambdaQueryWrapperX
类,确保只有在条件值存在的情况下才进行条件的拼接。
import com.baomidou.mybatisplus.extension.service.IService;
import com.page.demo.common.pojo.PageResult;
import com.page.demo.domain.Student;
import com.page.demo.domain.StudentPageReqVO;
public interface IStudentService extends IService<Student> {
PageResult<Student> getStudentList(StudentPageReqVO reqVO);
}
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.page.demo.common.pojo.PageResult;
import com.page.demo.domain.Student;
import com.page.demo.domain.StudentPageReqVO;
import com.page.demo.mapper.StudentMapper;
import com.page.demo.service.IStudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements IStudentService {
@Resource
private StudentMapper studentMapper;
@Override
public PageResult<Student> getStudentList(StudentPageReqVO reqVO) {
return studentMapper.getStudentList(reqVO);
}
}
import cn.hutool.json.JSONObject;
import com.page.demo.common.pojo.PageResult;
import com.page.demo.domain.Student;
import com.page.demo.domain.StudentPageReqVO;
import com.page.demo.service.IStudentService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/api/stu")
public class StudentController {
@Resource
private IStudentService studentService;
@GetMapping("/list")
public JSONObject getStudentList(StudentPageReqVO reqVO) {
PageResult<Student> pageResult = studentService.getStudentList(reqVO);
JSONObject jsonObject = new JSONObject();
jsonObject.set("data", pageResult);
jsonObject.set("status", 200);
return jsonObject;
}
}
这段代码展示了一个基于Spring Boot和MyBatis Plus的后端服务的典型架构,主要涉及到以下方面:
mysql-connector-j
,数据源使用了druid
,MyBatis Plus作为持久层框架。lombok
简化实体类的代码。hutool
和mybatis-plus-join-core
,用于增强开发效率和提供一些扩展功能。PaginationInnerInterceptor
实现分页功能。MybatisPlusConfig
类,配置了分页插件,并将其注入到Spring容器中。Student
实体类,用于映射数据库中的学生表。PageParam
类,作为分页查询的请求参数对象,包含了页码、每页条数等信息。BaseMapperX
接口,继承了MyBatis Plus的BaseMapper
和自定义的MPJBaseMapper
,提供了一系列对数据库操作的方法,包括分页查询、条件查询等。StudentMapper
接口继承了BaseMapperX
,用于学生表的数据库操作。StudentServiceImpl
实现了IStudentService
接口,提供了具体的业务逻辑,包括分页查询学生列表。LambdaQueryWrapperX
类,对MyBatis Plus的LambdaQueryWrapper
进行了拓展,增加了一系列条件拼接的方法,根据条件值的存在性来动态拼接查询条件。IStudentService
接口中定义了一个默认方法getStudentList
,接受一个StudentPageReqVO
对象作为查询条件,通过调用selectPage
方法实现学生列表的分页查询。总体而言,这个项目展示了一个典型的后端服务架构,具备良好的可读性、可维护性和可扩展性。