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

Spring Boot 3.1开启one-indexed-parameters后分页异常求助

Spring Boot 3.1分页异常修复方案

问题原因分析

  1. spring.data.web.pageable.one-indexed-parameters=true仅负责将请求传入的1-based页码转换为Spring内部使用的0-based页码,但Spring默认返回的Page对象(如PageImpl)中的number字段仍然是0-based的,所以响应里的页码会比请求值小1。
  2. 当请求page=0时,Spring会将其强制转换为0(转换后页码不能小于0),导致和page=1转换后的0页码逻辑一致,返回相同结果。

修复方案

1. 修正响应中的页码为1-based

方案一:自定义分页响应DTO(推荐)

创建包装类,将Page对象的0-based页码转换为1-based后返回:

public class CustomPage<T> {
    private int totalPages;
    private long totalElements;
    private int size;
    private int number; // 1-based页码
    private int numberOfElements;
    private boolean empty;
    private boolean first;
    private boolean last;
    private boolean sorted;
    private List<T> content;

    // 从Page对象转换构造
    public CustomPage(Page<T> page) {
        this.totalPages = page.getTotalPages();
        this.totalElements = page.getTotalElements();
        this.size = page.getSize();
        this.number = page.getNumber() + 1; // 0转1
        this.numberOfElements = page.getNumberOfElements();
        this.empty = page.isEmpty();
        this.first = page.isFirst();
        this.last = page.isLast();
        this.sorted = page.getSort().isSorted();
        this.content = page.getContent();
    }

    // Getter、Setter方法
}

在Controller中返回自定义分页类:

@GetMapping("/system/business/pagination")
public ResponseEntity<CustomPage<Business>> getPagination(
        @RequestParam(defaultValue = "1") Integer page,
        @RequestParam(defaultValue = "5") Integer size,
        Pageable pageable) {
    // 处理page=0的情况
    if (page == 0) {
        return ResponseEntity.ok(null);
    }
    Page<Business> resultPage = businessService.findAll(pageable);
    return ResponseEntity.ok(new CustomPage<>(resultPage));
}

方案二:自定义Jackson序列化器

针对Page对象定制序列化逻辑,自动将number字段加1:

public class PageSerializer extends JsonSerializer<Page<?>> {
    @Override
    public void serialize(Page<?> page, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeNumberField("totalPages", page.getTotalPages());
        gen.writeNumberField("totalElements", page.getTotalElements());
        gen.writeNumberField("size", page.getSize());
        gen.writeNumberField("number", page.getNumber() + 1); // 转换为1-based
        gen.writeNumberField("numberOfElements", page.getNumberOfElements());
        gen.writeBooleanField("empty", page.isEmpty());
        gen.writeBooleanField("first", page.isFirst());
        gen.writeBooleanField("last", page.isLast());
        gen.writeBooleanField("sorted", page.getSort().isSorted());
        gen.writeFieldName("content");
        serializers.defaultSerializeValue(page.getContent(), gen);
        gen.writeEndObject();
    }
}

在配置类中注册序列化器:

@Configuration
public class JacksonConfig {
    @Bean
    public Module pageSerializerModule() {
        SimpleModule module = new SimpleModule();
        module.addSerializer(Page.class, new PageSerializer());
        return module;
    }
}

2. 实现page=0返回null的需求

必须通过@RequestParam单独获取原始请求的page参数(因为Pageable对象中的number是转换后的值,无法区分原始请求是0还是1),判断后返回null:

@GetMapping("/system/business/pagination")
public ResponseEntity<?> getPagination(
        @RequestParam(defaultValue = "1") Integer page,
        Pageable pageable) {
    if (page == 0) {
        return ResponseEntity.ok(null);
    }
    Page<Business> resultPage = businessService.findAll(pageable);
    return ResponseEntity.ok(new CustomPage<>(resultPage));
}

3. 额外优化:拦截非法页码

如果需要禁止page<=0的非法请求,可返回400错误:

if (page <= 0) {
    return ResponseEntity.badRequest().body("页码必须大于0");
}

验证效果

  • 请求page=0:返回null
  • 请求page=1:响应中number为1,返回第一页数据
  • 请求page=2:响应中number为2,返回第二页数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 12:30:58