Spring data Pageable and LIMIT/OFFSET

18

我正在考虑将我们传统的JPA/DAO解决方案迁移到Spring Data上。

然而,我们的某个前端是SmartGWT,他们的数据绑定组件仅使用limit/offset逐步加载数据,这使得使用Pageable变得困难。

这会导致问题,因为不确定limit/offset是否可以被均匀地转换成页码。(它可能因用户滚动、屏幕调整大小等而有所不同。)

我看了一下Slice等,但没能找到在任何地方使用limit/offset值的方法。

想知道有没有人有什么建议?最理想的情况是我想继续使用limit/offset,在我的Repository接口中使用它们,而不需要像现在这样编写实现并手动设置它们(query.setMaxResults等)

编辑:为了澄清我为什么有问题- limit/offset可能会在Smartgwt组件中的初始和后续数据获取之间有所不同。对于一个列表网格,第一次获取可能将限制设为89,例如,因为这是屏幕上可见行的数量,偏移量为0。然而,下一次请求可能会有偏移量89,以及限制为50,因为这是组件的“datapagesize”值为50,所以当我向下滚动时,它会获取这些数据。 如果我在释放之前滚动太远,它可能(取决于设置)会获取例如行159-209。基本上,没有保证偏移量是任何东西的倍数。很难将偏移量17和限制5转换为页码。


1
不限制大小,而偏移量只是页面 * 大小?这是默认的 Pageable 实现吗? - ikumen
不行,因为它可能会有所不同。比如我有一个Listgrid。SmartGWT逻辑将最初将偏移量设置为0,并设置足够大的限制以加载屏幕上可见的内容。这可以是50、79、99等,具体取决于屏幕大小、浏览器大小等。下一次,它将使用“pagesize”值,例如可能是50。然后,根据您滚动的方式,它可能会在下一次获取250-300行。我的问题是,我无法控制初始LIMIT值,基本上也无法控制smartgwt在后续请求中决定的偏移量。 - Mathias
2个回答

20

可分页实现确实使用limitoffset来创建分页。构造函数中的page值用于生成AbstractPageRequest类中的getOffset方法中的偏移量值:

public int getOffset() {
    return this.page * this.size;
}

如果您只想使用limitoffset,并从中排除page参数,请查看Spring Data文档中有关Web支持的部分,特别是有关覆盖默认配置的部分。您可以创建自己的Pageable实现,该实现将limitoffset作为构造函数参数,并实现自己的HandlerMethodArgumentResolver以替换标准的PageRequest解析。快速而简单的示例:
public class BetterPageRequest implements Pageable {

    public BetterPageRequest(int limit, int offset){
        this.limit = limit;
        this.offset = offset;
    }

    // Other method implementations

}

HandlerMethodArgumentResolver实现

public class BetterPageableResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter){
        return Pageable.class.equals(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container, NativeWebRequest request, WebDataBinderFactory factory){
        Map<String,String[]> params = request.getParameterMap();
        return new BetterPageRequest(params.get('limit')[0], params.get('offset')[0]);
    }

}

啊,实现自己的Pageable可能是我可以尝试的,谢谢!由于LIMIT/OFFSET是一个基本的数据库概念,我觉得它不是现成的有点奇怪。 - Mathias
但是你的代码实际上凸显了我在可分页性方面遇到问题,并引发了这个问题!例如,如果我收到一个偏移量为17和限制为5的请求,会怎样? - Mathias
配置和实现都不应该太难。这样做的好处是,不需要更改具有Pageable参数的方法的存储库功能,并且您的控制器中也不需要额外的代码来处理您的版本Pageable。如果您正在使用Spring HATEOAS,这也将非常有用。 - woemler
您不必使用查询参数 limitoffset,您可以让 HandlerMethodArgumentResolver 映射任何参数来创建您的 PageRequest 替换。没有理由不能将请求 http://myapp/search/stuff?startrow=100&endrow=200 翻译为 new BetterPageRequest(params.get('endrow')[0]-params.get('startrow')[0], params.get('startrow')[0]); - woemler
是的,我确实看到了那个,而且它会很不错。然而,smartGWT将这些参数作为XML文档的一部分发送到HTTP正文中,而不是作为URL参数。它非常专有,就这么说吧... - Mathias
显示剩余4条评论

13
public class OffsetLimitPageable extends PageRequest {
    private int offset;
    public OffsetLimitPageable(int offset, int limit){
        super(offset,limit);
        this.offset=offset;
    }
    @Override
    public long getOffset(){
        return this.offset;
    }
}

一个例子

Page<WashComment> washComments = washCommentRepository.findWashCommentByWashId_CarWashIdOrderByDateDesc(carWash, new OffsetLimitPageable(offsetNumberRepresentation,
                 limitNumberRepresentation > Config.getMaxLimitAmount() ? Config.getMaxLimitAmount() : limitNumberRepresentation));

如果这正是您想要的,请告诉我。


不错的解决方法。但值得一提的是,像previous()next()这样的其他PageRequest方法将无法正确运行。 因此,OffsetLimitPageable实例不是PageRequest的完整实现。 - chill appreciator
我在这里得到了答案 https://dev59.com/Crbna4cB1Zd3GeqPaWr7#63911746 - LuisComS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接