mybatis和mybatis-plus实现分页查询套路总结
(进一步完善版本)
需要的类补充
/**
* 后端统一返回结果
* @param <T>
*/
@Data
public class Result<T> implements Serializable {
private Integer code; //编码:1成功,0和其它数字为失败
private String msg; //错误信息
private T data; //数据
public static <T> Result<T> success() {
Result<T> result = new Result<T>();
result.code = 1;
return result;
}
public static <T> Result<T> success(T object) {
Result<T> result = new Result<T>();
result.data = object;
result.code = 1;
return result;
}
public static <T> Result<T> error(String msg) {
Result result = new Result();
result.msg = msg;
result.code = 0;
return result;
}
}
/**
* 封装分页查询结果
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {
private long total; //总记录数
private List records; //当前页数据集合
}
@Data
public class DishPageQueryDTO implements Serializable {
private int page;
private int pageSize;
private String name;
//分类id
private Integer categoryId;
//状态 0表示禁用 1表示启用
private Integer status;
}
pagehelper依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DishVO implements Serializable {
private Long id;
//菜品名称
private String name;
//菜品分类id
private Long categoryId;
//菜品价格
private BigDecimal price;
//图片
private String image;
//描述信息
private String description;
//0 停售 1 起售
private Integer status;
//更新时间
private LocalDateTime updateTime;
//分类名称 需要的
private String categoryName;
//菜品关联的口味
private List<DishFlavor> flavors = new ArrayList<>();
//private Integer copies;
}
一.mybatis分页查询
依赖拉取不多赘述,主要学习架构的思维 之前有位大佬告诉过我,有时候架构设计的思维,要比代码有用,如果你有了这样的思维,代码可以通过各种方式给写出来实现功能
controller
@GetMapping("/page")
@ApiOperation("菜品分页查询")
public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO){
log.info("菜品分页查询,{}",dishPageQueryDTO);
PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
return Result.success(pageResult);
}
service
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO);
impl**(泛型自行替换即可)** 此处的泛型就是需要返回给用户的数据集合,vo视图,因为controller层返回PageResult,而他是通过service层实现的业务逻辑,所以是通过一步步查询vo集合数据然后分页查询得到需要返回的数据集合vo
可能比较绕,但是记住泛型指的是什么就好
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
@Override
public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {
PageHelper.startPage(dishPageQueryDTO.getPage(),dishPageQueryDTO.getPageSize());
Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);
return new PageResult(page.getTotal(), page.getResult());
}
mapper
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
Page<DishVO> pageQuery(DishPageQueryDTO dishPageQueryDTO);
mapper.xml
<select id="pageQuery" resultType="com.sky.vo.DishVO">
select d.* , c.name as categoryName from sky_take_out. dish d left join sky_take_out.category c
on d.category_id = c.id
<where>
<if test="name != null">
and d.name like concat('%',#{name},'%')
</if>
<if test="categoryId != null">
and d.category_id = #{categoryId}
</if>
<if test="status != null">
and d.status = #{status}
</if>
</where>
order by d.create_time desc
</select><select id="pageQuery" resultType="com.sky.entity.Category">
select * from category
<where>
<if test="name != null and name != ''">
and name like concat('%',#{name},'%')
</if>
<if test="type != null">
and type = #{type}
</if>
</where>
order by sort asc , create_time desc
</select>
二.mybatis-plus实现分页查询
以下所有操作都是在完成mp基础实现继承等基本操作之后的行为,如果不会就去官网学习
导入swagger和hutool依赖等其他依赖,这里就不展开说了
主要学习的是这种设计思路,按照三层架构设计
1.书写分页配置类
config
@Configuration
public class MyBatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 1.创建分页插件
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
//自己设置条件 官网是简化写法
paginationInnerInterceptor.setMaxLimit(1000L);
// 2.添加分页插件
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
2**.抽离两个分页实体类**
PageDTO
@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {
@ApiModelProperty("总条数")
private Long total;
@ApiModelProperty("总页数")
private Long pages;
@ApiModelProperty("集合")
private List<T> list;
public static <PO, VO> PageDTO<VO> of(Page<PO> p, Class<VO> clazz){
PageDTO<VO> dto = new PageDTO<>();
// 1.总条数
dto.setTotal(p.getTotal());
// 2.总页数
dto.setPages(p.getPages());
// 3.当前页数据
List<PO> records = p.getRecords();
if (CollUtil.isEmpty(records)) {
dto.setList(Collections.emptyList());
return dto;
}
// 4.拷贝user的VO
dto.setList(BeanUtil.copyToList(records, clazz));
// 5.返回
return dto;
}
public static <PO, VO> PageDTO<VO> of(Page<PO> p, Function<PO, VO> convertor){
PageDTO<VO> dto = new PageDTO<>();
// 1.总条数
dto.setTotal(p.getTotal());
// 2.总页数
dto.setPages(p.getPages());
// 3.当前页数据
List<PO> records = p.getRecords();
if (CollUtil.isEmpty(records)) {
dto.setList(Collections.emptyList());
return dto;
}
// 4.拷贝user的VO
dto.setList(records.stream().map(convertor).collect(Collectors.toList()));
// 5.返回
return dto;
}
}
PageQuery
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {
@ApiModelProperty("页码")
private Integer pageNo = 1;
@ApiModelProperty("页码")
private Integer pageSize = 5;
@ApiModelProperty("排序字段")
private String sortBy;
@ApiModelProperty("是否升序")
private Boolean isAsc = true;
public <T> Page<T> toMpPage(OrderItem ... items){
// 1.分页条件
Page<T> page = Page.of(pageNo, pageSize);
// 2.排序条件
if(StrUtil.isNotBlank(sortBy)){
// 不为空
page.addOrder(new OrderItem(sortBy, isAsc));
}else if(items != null){
// 为空,默认排序
page.addOrder(items);
}
return page;
}
public <T> Page<T> toMpPage(String defaultSortBy, Boolean defaultAsc){
return toMpPage(new OrderItem(defaultSortBy, defaultAsc));
}
public <T> Page<T> toMpPageDefaultSortByCreateTime(){
return toMpPage(new OrderItem("create_time", false));
}
public <T> Page<T> toMpPageDefaultSortByUpdateTime(){
return toMpPage(new OrderItem("update_time", false));
}
}
3.实现业务
准备其他需要用到的实体类示例,复用时请自己设计
UserQuery
注意:
@EqualsAndHashCode(callSuper = true)
该注解用于子类对象之间进行比较的时候
不加该注解的影响:子类对象属性值一致,但其继承的父类对象属性值不一致,在比较的时候会出现比较结果不对的情况。比如赋予同样的name值,但他们有一个属性是不同的,但是比较两个对象的结果却是true
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(description = "用户查询条件实体")
public class UserQuery extends PageQuery {
@ApiModelProperty("用户名关键字")
private String name;
@ApiModelProperty("用户状态:1-正常,2-冻结")
private Integer status;
@ApiModelProperty("余额最小值")
private Integer minBalance;
@ApiModelProperty("余额最大值")
private Integer maxBalance;
UserVo
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {
@ApiModelProperty("用户id")
private Long id;
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("详细信息")
private UserInfo info;
@ApiModelProperty("使用状态(1正常 2冻结)")
private UserStatus status;
@ApiModelProperty("账户余额")
private Integer balance;
@ApiModelProperty("用户的收获地址")
private List<AddressVO> addresses;
}
User
@Data
@TableName(value = "user", autoResultMap = true)
public class User {
/**
* 用户id
*/
// @TableId(type = IdType.AUTO)
private Long id;
/**
* 用户名
*/
// @TableField("`username`")
private String username;
/**
* 密码
*/
// @TableField(exist = false)
private String password;
/**
* 注册手机号
*/
private String phone;
/**
* 详细信息
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private UserInfo info;
/**
* 使用状态(1正常 2冻结)
*/
private UserStatus status;
/**
* 账户余额
*/
private Integer balance;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}
三层架构开始
controller
@ApiOperation("根据条件分页查询用户接口")
@GetMapping("/page")
public PageDTO<UserVO> queryUsersPage(UserQuery query){
return userService.queryUsersPage(query);
}
}
service
PageDTO<UserVO> queryUsersPage(UserQuery query);
impl
@Override
public PageDTO<UserVO> queryUsersPage(UserQuery query) {
String name = query.getName();
Integer status = query.getStatus();
// 1.构建分页条件
Page<User> page = query.toMpPageDefaultSortByUpdateTime();
// 2.分页查询
Page<User> p = lambdaQuery()
.like(name != null, User::getUsername, name)
.eq(status != null, User::getStatus, status)
.page(page);
// 3.封装VO结果
return PageDTO.of(p,user -> {
// 1.拷贝基础属性
UserVO vo = BeanUtil.copyProperties(user, UserVO.class);
// 2.处理特殊逻辑
vo.setUsername(vo.getUsername().substring(0, vo.getUsername().length() - 2) + "**");
return vo;
});
}
}
最后的处理特殊逻辑不必过度注意,这里只是一个示例,具体业务实现可能更加复杂,只要会使用框架就行。具体业务实现还是要靠你的架构思维
还有一些基本增删改查在mp官网讲的很详细,在未来可能也会出一期专门讲增删改查操作的笔记,也是我自己的复习,也希望能帮助到一些初学者打开mybatis等框架的大门。
最后一段就是po转vo的逻辑
Function<PO, VO> convertor转换器
其实分页查询还能进一步解耦合,具体如何实现还是得根据业务,没有什么万能解法