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

Spring PageImpl含冗余内容,能否自定义CustomPageImpl及最佳实践?

解决方案与最佳实践

针对Spring默认Page类型返回JSON存在冗余字段的问题,既可以自定义Page实现类(比如CustomPageImpl),也可以通过DTO按需传输数据,以下是具体实现方案和最佳实践:

一、自定义Page实现类(CustomPageImpl)

可以通过实现Spring的Page<T>接口,只保留业务需要的核心字段,过滤冗余内容。

实现代码示例

public class CustomPageImpl<T> implements Page<T> {
    private final List<T> content;
    private final long totalElements;
    private final int totalPages;
    private final int size;
    private final int number;
    private final int numberOfElements;

    // 构造方法,传入核心分页参数
    public CustomPageImpl(List<T> content, long totalElements, int totalPages, int size, int number) {
        this.content = content;
        this.totalElements = totalElements;
        this.totalPages = totalPages;
        this.size = size;
        this.number = number;
        this.numberOfElements = content.size();
    }

    // 实现Page接口的必要方法,按需返回逻辑,冗余字段返回默认值
    @Override
    public int getNumber() { return number; }
    @Override
    public int getSize() { return size; }
    @Override
    public int getNumberOfElements() { return numberOfElements; }
    @Override
    public List<T> getContent() { return content; }
    @Override
    public boolean hasContent() { return !content.isEmpty(); }
    @Override
    public Sort getSort() { return Sort.unsorted(); } // 不需要排序字段时返回空Sort
    @Override
    public boolean isFirst() { return number == 0; }
    @Override
    public boolean isLast() { return number == totalPages - 1; }
    @Override
    public boolean hasNext() { return number < totalPages - 1; }
    @Override
    public boolean hasPrevious() { return number > 0; }
    @Override
    public Pageable nextPageable() { return hasNext() ? PageRequest.of(number + 1, size) : Pageable.unpaged(); }
    @Override
    public Pageable previousPageable() { return hasPrevious() ? PageRequest.of(number - 1, size) : Pageable.unpaged(); }
    @Override
    public Iterator<T> iterator() { return content.iterator(); }
    @Override
    public int getTotalPages() { return totalPages; }
    @Override
    public long getTotalElements() { return totalElements; }
    @Override
    public boolean isEmpty() { return content.isEmpty(); }
}

使用方式

在Service层查询得到默认Page对象后,转换为自定义的CustomPageImpl:

Page<User> defaultPage = userRepository.findAll(pageable);
CustomPageImpl<User> customPage = new CustomPageImpl<>(
    defaultPage.getContent(),
    defaultPage.getTotalElements(),
    defaultPage.getTotalPages(),
    defaultPage.getSize(),
    defaultPage.getNumber()
);
return customPage;

二、使用DTO传输(推荐最佳实践)

这种方式更符合分层架构设计,彻底分离业务数据与传输数据,灵活度更高。

实现步骤

  1. 创建分页DTO类,仅保留需要的字段:
public class PageDTO<T> {
    private List<T> content;
    private long totalElements;
    private int totalPages;
    private int pageSize;
    private int pageNumber;
    private int numberOfElements;

    // 构造方法
    public PageDTO(List<T> content, long totalElements, int totalPages, int pageSize, int pageNumber) {
        this.content = content;
        this.totalElements = totalElements;
        this.totalPages = totalPages;
        this.pageSize = pageSize;
        this.pageNumber = pageNumber;
        this.numberOfElements = content.size();
    }

    // 按需生成getter/setter方法
}
  1. 转换逻辑(Service/Controller层):
Page<User> defaultPage = userRepository.findAll(pageable);
// 若需要对content中的对象也做DTO转换,可结合MapStruct等工具简化
List<UserDTO> userDTOs = userMapper.toUserDTOList(defaultPage.getContent());
PageDTO<UserDTO> pageDTO = new PageDTO<>(
    userDTOs,
    defaultPage.getTotalElements(),
    defaultPage.getTotalPages(),
    defaultPage.getSize(),
    defaultPage.getNumber()
);
return pageDTO;

三、方案对比与选择

  • 自定义PageImpl:适合需要与Spring Data生态深度绑定的场景,但需要实现接口所有方法,代码冗余,灵活度有限。
  • DTO传输:优先推荐,完全按需定义字段,降低业务层与传输层耦合,后续扩展、维护更方便,配合MapStruct等工具可大幅减少转换代码。

另外,也可以通过Jackson的@JsonIgnoreProperties注解直接忽略默认Page类中的冗余字段,但这种硬编码方式不够灵活,仅适合临时快速屏蔽字段,不推荐作为长期方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 01:20:18