Spring Boot 3.1开启one-indexed-parameters后分页异常求助
Spring Boot 3.1分页异常修复方案
问题原因分析
spring.data.web.pageable.one-indexed-parameters=true仅负责将请求传入的1-based页码转换为Spring内部使用的0-based页码,但Spring默认返回的Page对象(如PageImpl)中的number字段仍然是0-based的,所以响应里的页码会比请求值小1。- 当请求
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
相关产品推荐
相关产品推荐

