1 应用场景
假如有一张学生表,记录了学生信息和成绩。现需要分页查询该表的信息,同时能够根据参数控制排序规则。
比如,这次按语文、数学、英语成绩倒序排序。下次按数学、英语、语文成绩顺序排序。该怎么实现呢?
2 解决方案
2.1 Controller层代码
@PostMapping("/getStdMsgPage")
public JsonResult<Page<StudentMsg>> getStdMsgPage(@RequestBody PageQuery pageQuery){
Page<StudentMsg> stdMsgPage = studentMsgService.getStdMsgPage(pageQuery);
return new JsonResult<>(stdMsgPage);
}
2.2 Service层的业务代码
public Page<StudentMsg> getStdMsgPage(PageQuery pageQuery) {
Page<StudentMsg> pageResult = studentMsgMapper.getStdMsgPage(PageBuilder.build(pageQuery));
return pageResult;
}
2.3 Mapper层业务代码
@Mapper
public interface StudentMsgMapper {
Page<StudentMsg> getStdMsgPage(Page<Object> page);
}
mapper
<select id="getStdMsgPage" resultType="com.zou.studentmanager.entity.StudentMsg">
select *
from std_mes
</select>
代码很简单,重要的是那个PageBuilder类要怎么写。
3 类
3.1 请求参数PageQuery类
分页参数
@Data
@ApiModel("分页查询参数")
public class PageQuery {
@ApiModelProperty("当前页")
private Integer currentPage;
@ApiModelProperty("页大小")
private Integer pageSize;
@ApiModelProperty("升序排序的字段,用英文,分隔不同的字段")
private String ascs;
@ApiModelProperty("降序排序的字段,用英文,分隔不同的字段")
private String descs;
@ApiModelProperty("自定义排序字段列表")
private List<PageOrder> orders;
}
请求参数的json格式
{
"currentPage": 0,
"pageSize": 0,
"ascs": "",
"descs": "",
"orders": [
{
"column": "",
"orderType": "ASC"
}
]
}
@Data
@ApiModel("自定义排序字段")
public class PageOrder {
@ApiModelProperty("字段名称")
private String column;
@ApiModelProperty("")
private PageOrderTypeEnum orderType;
}
@Getter
@AllArgsConstructor
public enum PageOrderTypeEnum {
ASC("ASC", "升序"),
DESC("DESC", "降序");
/**
* code:代表是升序还是降序码
* msg:升序或者降序
*/
private String code;
private String msg;
}
3.2 自定义PageBuilder工具类
PageBuilder其作用在于创建Page
public class PageBuilder {
private static final Integer PAGE_DEFAULT_SIZE = 10;
private PageBuilder(){}
public static <T> Page<T> build(Integer current, Integer size){
if(Objects.isNull(size) || size <= 0){
size = PAGE_DEFAULT_SIZE;
}
if(Objects.isNull(current) || current <= 0){
current = 1;
}
return new Page<>(current, size);
}
/**
* Page建造器
* @param pageQuery 分页查询的基本请求参数
* @return 定义好的Page
* @param <T>
*/
public static <T> Page<T> build(PageQueryDTO pageQuery){
if(Objects.isNull(pageQuery)){
return build(1, PAGE_DEFAULT_SIZE);
}
Page<T> page = new Page<>(pageQuery.getCurrentPage(), pageQuery.getPageSize());
String ascs = pageQuery.getAscs();
if(StringUtils.hasText(ascs)){
List<String> columns = Arrays.asList(ascs.split(","));
List<OrderItem> list = columns.stream().map(item -> {
OrderItem orderItem = new OrderItem();
orderItem.setColumn(item);
orderItem.setAsc(true);
return orderItem;
}).collect(Collectors.toList());
page.addOrder(list);
}
String decs = pageQuery.getDescs();
if(StringUtils.hasText(decs)){
List<String> columns = Arrays.asList(decs.split(","));
List<OrderItem> list = columns.stream().map(item -> {
OrderItem orderItem = new OrderItem();
orderItem.setColumn(item);
orderItem.setAsc(false);
return orderItem;
}).collect(Collectors.toList());
page.addOrder(list);
}
if(!CollectionUtils.isEmpty(pageQuery.getOrders())){
page.setOrders(pageQuery.getOrders().stream().map(item->{
if(item.getOrderType().equals(PageOrderTypeEnum.ASC)){
return OrderItem.asc(PageBuilder.humpToUnderline(item.getColumn()));
}else{
return OrderItem.desc(PageBuilder.humpToUnderline(item.getColumn()));
}
}).collect(Collectors.toList()));
}
return page;
}
/**
* 驼峰转下划线
* @param humpName 驼峰字符串
* @return 下划线字符串
*/
public static String humpToUnderline(String humpName) {
char[] charArray = humpName.toCharArray();
StringBuilder buffer = new StringBuilder();
int i = 0;
for(int l = charArray.length; i < l; ++i) {
if (charArray[i] >= 'A' && charArray[i] <= 'Z') {
buffer.append("_").append(charArray[i] = (char)(charArray[i] + 32));
} else {
buffer.append(charArray[i]);
}
}
String result = buffer.toString();
return result;
}
}
4 实例
4.1 例一
根据数学、英语、语文的顺序进行降序排序。
传入的具体参数
{
"currentPage": 1,
"pageSize": 10,
"ases": "",
"descs": "math,english,chinese"
}
Service层的业务代码
public Page<StudentMsg> getStdMsgPage(PageQuery pageQuery) {
Page<StudentMsg> pageResult = studentMsgMapper.getStdMsgPage(PageBuilder.build(pageQuery));
return pageResult;
}
实际执行的sql
SELECT
*
FROM
std_mes
ORDER BY
math DESC,
english DESC,
chinese DESC LIMIT 10;
4.2 例二
与例一相同,还可以这么传。根据数学、英语、语文的顺序进行降序排序。
传入的具体参数。
{
"currentPage": 1,
"pageSize": 10,
"ase": "",
"desc": "",
"orders": [
{
"column": "math",
"orderType": "DESC"
},
{
"column": "english",
"orderType": "DESC"
},
{
"column": "chinese",
"orderType": "DESC"
}
]
}
实际执行的sql
SELECT
*
FROM
std_mes
ORDER BY
math DESC,
english DESC,
chinese DESC LIMIT 10;
从sql日志可以看到排序起作用了。
5 原理讲解
最本质还是用到了mybatisplus的分页方法。
mybatisplus的分页方法需要一个Page参数。源码中这个Page类叫做简单分页模型。
这个类定义了许多分页有关的基本参数,比如:
/**
* 查询数据列表
*/
protected List<T> records = Collections.emptyList();
/**
* 总数
*/
protected long total = 0;
/**
* 每页显示条数,默认 10
*/
protected long size = 10;
/**
* 当前页
*/
protected long current = 1;
/**
* 排序字段信息
*/
@Setter
protected List<OrderItem> orders = new ArrayList<>();
而本文内容的实现关键就是最后一个属性orders,排序字段信息。
而PageBuilder的设计就是为了更方便快捷地给这个排序属性orders赋值。