一.通用分页实体与MP转换
回顾我们之前写的代码,在查询出分页结果后,数据的非空校验,数据的vo转换都是模板代码,编写起来很麻烦。我们完全可以将其封装到PageQueryDTO的工具方法中,简化整个过程:
package com.itheima.mp.domain.dto;import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.mp.domain.po.User;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "分页查询条件实体")
public class PageQueryDTO {@ApiModelProperty("当前页码")private Integer pageNum;@ApiModelProperty("每页记录数")private Integer pageSize;@ApiModelProperty("排序字段")private String sort;@ApiModelProperty("排序方式:asc-升序,desc-降序")private Boolean isAsc;// 封装成MyBatis Plus的Page对象public <T> Page<T> toMpPage(OrderItem ... orderItems) {// 1.创建Page对象,指定当前页码和每页记录数Page<T> page = new Page<>(pageNum, pageSize);// 2.设置排序字段和排序方式if (sort != null) {page.addOrder(new OrderItem(sort, isAsc));} else if (orderItems != null){// 没有排序字段,要传入默认排序字段是什么,按照默认的排序字段进行排序page.addOrder(orderItems);}return page;}// 封装成MyBatis Plus的Page对象,按照create_time进行排序public <T> Page<T> toMpPageOrderByCreateTime() {return toMpPage(new OrderItem("create_time", false));}// 封装成MyBatis Plus的Page对象,按照create_time进行排序public <T> Page<T> toMpPageOrderByUpdateTime() {return toMpPage(new OrderItem("update_time", false));}// 封装成MyBatis Plus的Page对象,按照指定字段进行排序。不用传入OrderItem对象,直接传入字段名和排序方式即可public <T> Page<T> toMpPage(String defaultSortBy, Boolean defaultIsAsc) {return toMpPage(new OrderItem(defaultSortBy, defaultIsAsc));}
}
首先在封装时为了封装为Page对象,我们定义一个toMpPage()方法,该方法的返回值是一个存储类型为泛型的Page对象,用来剥离实际业务进行开发。其中传入参数为可变参数,为OrderItem类型,用来指定排序字段。如果UserQueryDTO中没有排序字段,则按照指定的排序字段进行排序。用户需要创建一个OrderItem对象来指定排序字段。
我们还定义了按照create_time和update_time来排序的方法。以及如果用户不想创建OrderItem对象,但是又想进行排序的话,要求他传入排序字段defaultSortBy和排序顺序字段defaultIsAsc,我们为其创建一个OrderItem类型的对象进行排序。
改造后的代码如下:
@Overridepublic PageVO<UserVO> queryListPage(UserQueryDTO userQueryDTO) {Page<User> page = userQueryDTO.toMpPageOrderByUpdateTime();// 3.将Page查询条件封装进QueryWrapperPage<User> p = lambdaQuery().like(User::getUsername, userQueryDTO.getName()).eq(User::getStatus, userQueryDTO.getStatus()).page(page);}
二.Page<User>对象转为Page<UserVO>对象
此外,我们的代码中创建Page<UserVO>对象,并将Page<User>对象转为Page<UserVO>对象的逻辑也可以将其封装到PageVO的工具方法中:
package com.itheima.mp.domain.vo;import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.mp.domain.po.User;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;@Data
@ApiModel(description = "分页VO实体")
// 定义一个统一的分页结果
public class PageVO<T> {@ApiModelProperty("总记录数")private Long total;@ApiModelProperty("总页数")private Long pages;@ApiModelProperty("当前页数据")private List<T> records;public static <VO, PO> PageVO<VO> of(Page<PO> p, Function<PO, VO> convertor) {// 4.获取查询结果// 4.1 获取总页数Long pages = p.getPages();// 4.2 获取总记录数Long total = p.getTotal();// 4.3 获取当前页数据List<PO> records = p.getRecords();// 5.封装PageVOPageVO<VO> pageVO = new PageVO<>();pageVO.setPages(pages);pageVO.setTotal(total);if (records == null) {pageVO.setRecords(Collections.emptyList());return pageVO;}// 使用stream流和map方法以及函数式语法将当前页数据转换成UserVO,其中函数式编程满足用户特殊的转换需求(解决PO和VO属性名不一致的问题)pageVO.setRecords(records.stream().map(convertor).collect(Collectors.toList()));return pageVO;}
}
我们首先将第一步生成好的Page<PO>对象传入,并获取其属性赋值给Page<VO>对象。接下来就进行最为关键的一步。将Page<PO>对象的当前页数据集合List<PO>转换为List<VO>,并将其封装在Page<VO>对象中。
如果PO和VO的属性名称和类型一样,我们可以使用BeanUtil工具类完成。但是如果两者不一样,那么我们就要进行定制化处理。为了解决这一问题,我们提供一个函数式编程参数,让用户自己去编写转换方法。其中map方法中传入的就是一个函数式编程参数,将其结果返回并收集到List集合中。该List集合作为Page<VO>的当前页数据,将Page<VO>返回。
最终方法如下:
@Overridepublic PageVO<UserVO> queryListPage(UserQueryDTO userQueryDTO) {Page<User> page = userQueryDTO.toMpPageOrderByUpdateTime();// 3.将Page查询条件封装进QueryWrapperPage<User> p = lambdaQuery().like(User::getUsername, userQueryDTO.getName()).eq(User::getStatus, userQueryDTO.getStatus()).page(page);return PageVO.of(p, new Function<User, UserVO>() {@Overridepublic UserVO apply(User user) {UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);// 对用户名进行脱敏userVO.setUsername(user.getUsername().substring(0,user.getUsername().length() - 2) + "**");return userVO;}});}
最终查询的结果如下: