1 应用场景

mysql 与mybatisplus 排序 null放最后_java

假如有一张学生表,记录了学生信息和成绩。现需要分页查询该表的信息,同时能够根据参数控制排序规则。
比如,这次按语文、数学、英语成绩倒序排序。下次按数学、英语、语文成绩顺序排序。该怎么实现呢?

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类叫做简单分页模型。

mysql 与mybatisplus 排序 null放最后_List_02

这个类定义了许多分页有关的基本参数,比如:

/**
     * 查询数据列表
     */
    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赋值。