You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 2.1.1 HAL自链接缺失分页参数问题咨询

问题分析与解决方案

首先要明确:你遇到的self链接模板缺失参数的情况,是Spring Data REST 2.1.x版本里的默认行为,不算严格意义上的Bug,但确实不符合客户端复用链接的需求。

当时的设计逻辑是:如果请求中已经明确传入了某个分页参数(比如你这里的size=10),生成self链接时会把这个参数从模板中移除,只保留未被指定的参数(也就是sort)。但这种设计会破坏客户端的跳转流程——比如用户想修改page页码或者调整size时,没法直接基于返回的self模板做修改,必须手动拼接参数,确实很不方便。

针对Spring Boot 2.1.1(对应Spring Data REST 2.1.x),这里有两种可行的解决方式:

方案1:自定义分页资源组装器(PagedResourcesAssembler)

我们可以重写默认的PagedResourcesAssembler,手动控制self链接的生成逻辑,让它保留所有分页参数的模板(page、size、sort),不管请求中是否指定了这些参数。

步骤如下:

  • 创建一个自定义的PagedResourcesAssembler实现类,注册为Spring Bean,替换默认的实现:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.rest.webmvc.support.PagedResourcesAssembler;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.UriTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.stream.Collectors;

@Component
public class CustomPagedResourcesAssembler extends PagedResourcesAssembler<Object> {

    public CustomPagedResourcesAssembler(HateoasPageableHandlerMethodArgumentResolver resolver,
                                        UriComponentsBuilder baseUri) {
        super(resolver, baseUri);
    }

    @Override
    protected void addPaginationLinks(Resources<?> resources, Page<?> page, UriComponentsBuilder builder) {
        // 构建包含所有分页参数的self模板链接
        String selfUri = builder.build().toUriString() + "{?page,size,sort}";
        resources.add(new Link(new UriTemplate(selfUri), Link.REL_SELF));

        // 手动添加其他分页链接(上一页、下一页、首页、末页)
        if (page.hasPrevious()) {
            resources.add(buildPageLink(page.previousPageable(), Link.REL_PREVIOUS));
        }
        if (page.hasNext()) {
            resources.add(buildPageLink(page.nextPageable(), Link.REL_NEXT));
        }
        resources.add(buildPageLink(page.firstPageable(), Link.REL_FIRST));
        resources.add(buildPageLink(page.lastPageable(), Link.REL_LAST));
    }

    private Link buildPageLink(Pageable pageable, String rel) {
        UriComponentsBuilder builder = getUriComponentsBuilder().cloneBuilder();
        builder.queryParam("page", pageable.getPageNumber());
        builder.queryParam("size", pageable.getPageSize());
        
        // 处理排序参数
        if (pageable.getSort().isSorted()) {
            builder.queryParam("sort", pageable.getSort().stream()
                    .map(order -> order.getProperty() + "," + order.getDirection())
                    .collect(Collectors.toList()));
        }
        
        return new Link(builder.build().toUriString(), rel);
    }
}

这个自定义类会强制self链接保留page、size、sort三个参数的模板,不管请求中是否传入了其中的某个参数,完全符合你的预期。

方案2:升级Spring Data REST版本

这个问题在Spring Data REST 2.2.x及以后的版本中已经被优化,链接生成逻辑做了调整:当请求中指定了部分分页参数时,self链接会保留当前参数的具体值,同时保留未指定参数的模板。比如你访问http://localhost:8080/admin/levels?size=10后,返回的self链接会变成:

"self": { "href": "http://localhost:8080/admin/levels?page=0&size=10{&sort}", "templated": true }

这正好是你想要的效果。如果你的项目允许升级依赖版本,这是最省心的解决方案——只需要把Spring Boot版本升级到2.2.x及以上(对应Spring Data REST 2.2.x+),就能自动修复这个问题,不需要写任何自定义代码。

补充说明

你之前找到的旧解决方案无效,是因为那些方案针对的是更早的Spring Data REST版本,而2.1.x的链接生成逻辑已经做了调整,所以旧方案不适用。如果暂时没法升级或者自定义组件,客户端只能临时拼接链接,但确实不如服务端返回正确的模板便捷。

内容的提问来源于stack exchange,提问作者gillesB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:49:52