美文网首页Spring Webflux
Spring Webflux + r2dbc 分页查询 示例2

Spring Webflux + r2dbc 分页查询 示例2

作者: 这个世界是虚拟的 | 来源:发表于2020-06-08 17:27 被阅读0次

    1. 现有API 对offset 的支持

    我们可以看到, 如果使用R2dbc 已经实现的分页, 那么我们可以使用Pageable 进行分页查询, 但是如果我们需要使用offset 此时, 现有的支持也许并不够用, 那么我们需要自己来实现 Pageable 接口来实现offset分页

    2. 为什么要使用offset 来进行分页

    由于项目需要, 决策层决定只给API调用者提供获取下一页的功能, 而不是提供给API 调用者提供直接查询某一页的功能, 我个人理解是, 这样做可以直接让API调用方调用指定的需要的查询记录的位置而不是必须要页首.

    3. 具体实现

    @Value
    public class Offset implements Pageable {
    
        int offset;
        int limit;
        //避免重用 isPaged
        boolean pagingApplied;
    
        @Override
        public int getPageNumber() {
            return offset / limit;
        }
    
        @Override
        public int getPageSize() {
            return limit;
        }
    
        @Override
        public long getOffset() {
            return offset;
        }
    
        @Override
        public Sort getSort() {
            //这里暂时不进行排序
            return Sort.unsorted();
        }
    
        @Override
        public Pageable next() {
            if (!pagingApplied){
                return unpaged();
            }
            return new Offset(offset + limit, limit, true);
        }
    
        @Override
        public Pageable previousOrFirst() {
            if (!pagingApplied){
                return unpaged();
            }
            //这里都返回 offset对象
            return hasPrevious() ? new Offset(offset - limit, limit, true) : first();
        }
    
        @Override
        public Pageable first() {
            if (!pagingApplied){
                return unpaged();
            }
            return new Offset(0, limit, true);
        }
    
        @Override
        public boolean hasPrevious() {
            return offset >= limit;
        }
    
        public static Offset unpaged() {
            return new Offset(0, 0, false);
        }
    
        @Override
        public boolean isPaged() {
            return pagingApplied;
        }
    }
    

    这里我们就已经实现了所有需要的方法, 那么我们可以使用我们的实现来使用 Offset 类来进行分页查询, 这里笔者觉得如果Spring Pageable 提供泛型会更加灵活, 这样的话我们直接可以指定返回类型, 不过也有可能Spring 本身有其他考量在此.

    4. 使用Offset 类

    4.1 使用方法和之前的使用方法一致, 那么我们如果定义了一个Repository 接口

    MyRepository extends ReactiveCrudRepository<Employee, UUID>{
    ...
     Flux<Employee> getEmployeebyGender((@Param("gender") String gender, Pageable pageable)
    ...
    }
    

    4.2 调用

    ... ...
    myRepository.getEmployeebyGender("man", new Offset(8, 10, true) )
    

    4.3 构造函数

    public Offset(int offset, int limit, boolean pagingApplied) {
            this.offset = Math.max(offset, 0);
            this.limit = Math.max(limit, 0);
            this.pagingApplied = pagingApplied;
        }
    
        public Offset(int offset, int limit) {
            this(offset, limit, true);
       }
    

    但是这里还是有缺陷的, 如果外部调用构造函数, 例如 new Offset(5, 10, false), 那么势必,我们使用 pageable.isPaged() 会得到false, 那么我们接下来很可能会碰到一些问题, 但很显然我们需要使用new Offset(5, 10, true). 那么这里最后将构造函数私有, 然后提供,比如一个of的静态方法来让外部使用:

    public static Offset of(int offset, Integer limit) {
    //加入一些判断逻辑
            return new Offset(offset, limit, true);
        }
    

    5. 遗留的问题

    其实这里我们依然有一些问题存在, 例如, 如果控制层调用时, 提供的参数为空的情况, 我们就比较被动了, 以为我们使用的是int 型, 不允许为null, 所以有一种情况, 假设用户请求为: GET "/dosomting?limit=10", 此时, 我们获得的offset是空, 那么我们可能想设定offset = 0, 那么如果使用int 就办不到了, 所以我们需要 offset 为 Integer, 或者给offset 一个默认值等.

    6. 遗留的问题

    由于时间有限, 笔者没有进行过多的测试, 可能实现类中还有隐含问题待解决, 不过自己实现接口往往会遇到各种问题, 这也是很难避免的, 一般建议, 如果依赖包本身含有现成的实现类, 那么我们最好不要重复造轮子, 但是如果必须自己实现, 那良好的测试是必要的

    相关文章

      网友评论

        本文标题:Spring Webflux + r2dbc 分页查询 示例2

        本文链接:https://www.haomeiwen.com/subject/xyqrtktx.html