将一个List分页返回的操作方式

在 Java 后端对内存 List 数据进行分页返回给前端,有几种常见的实现方式。以下是详细的解决方案:
方案一:使用 MyBatis-Plus 的 Page 对象(推荐)
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;@RestController
@RequestMapping("/api/data")
public class DataController {/*** 对内存中的 List 进行分页*/@GetMapping("/page")public Result<IPage<YourEntity>> getPageData(@RequestParam(defaultValue = "1") Integer current,@RequestParam(defaultValue = "10") Integer size) {// 1. 获取原始数据列表(这里用模拟数据)List<YourEntity> dataList = getDataFromMemory();// 2. 创建分页对象IPage<YourEntity> page = new Page<>(current, size);// 3. 设置总记录数page.setTotal(dataList.size());// 4. 计算分页数据int startIndex = (int) ((current - 1) * size);int endIndex = Math.min(startIndex + size, dataList.size());if (startIndex > dataList.size()) {page.setRecords(new ArrayList<>());} else {List<YourEntity> pageRecords = dataList.subList(startIndex, endIndex);page.setRecords(pageRecords);}return Result.success(page);}// 模拟从内存获取数据private List<YourEntity> getDataFromMemory() {List<YourEntity> list = new ArrayList<>();for (int i = 1; i <= 100; i++) {YourEntity entity = new YourEntity();entity.setId((long) i);entity.setName("Item " + i);entity.setCreateTime(new Date());list.add(entity);}return list;}
}
方案二:自定义通用分页工具类
/*** 分页工具类*/
@Component
public class PageUtils {/*** 对 List 进行分页*/public static <T> IPage<T> paginateList(List<T> dataList, long current, long size) {IPage<T> page = new Page<>(current, size);page.setTotal(dataList.size());int startIndex = (int) ((current - 1) * size);int endIndex = Math.min(startIndex + (int) size, dataList.size());if (startIndex >= dataList.size()) {page.setRecords(new ArrayList<>());} else {List<T> pageList = dataList.subList(startIndex, endIndex);page.setRecords(new ArrayList<>(pageList)); // 避免原List修改影响}return page;}/*** 带排序的分页*/public static <T> IPage<T> paginateList(List<T> dataList, long current, long size, Comparator<T> comparator) {// 先排序再分页List<T> sortedList = new ArrayList<>(dataList);sortedList.sort(comparator);return paginateList(sortedList, current, size);}
}// 控制器中使用
@RestController
@RequestMapping("/api/data")
public class DataController {@GetMapping("/page")public Result<IPage<YourEntity>> getPageData(@RequestParam(defaultValue = "1") Integer current,@RequestParam(defaultValue = "10") Integer size,@RequestParam(required = false) String sortField) {List<YourEntity> dataList = getDataFromMemory();// 可选:添加添加排序逻辑if ("name".equals(sortField)) {return Result.success(PageUtils.paginateList(dataList, current, size, Comparator.comparing(YourEntity::getName)));}return Result.success(PageUtils.paginateList(dataList, current, size));}
}
方案三:封装统一响应对象
/*** 统一的响应结果包装类*/
@Data
public class Result<T> implements Serializable {private Boolean success;private Integer code;private String message;private T data;public static <T> Result<T> success(T data) {Result<T> result = new Result<>();result.setSuccess(true);result.setCode(200);result.setMessage("操作成功");result.setData(data);return result;}
}/*** 自定义分页响应对象(如果不依赖 MyBatis-Plus)*/
@Data
public class CustomPage<T> {private Long current;      // 当前页private Long size;         // 每页大小private Long total;        // 总记录数private Long pages;        // 总页数private List<T> records;   // 数据列表public CustomPage(Long current, Long size, Long total, List<T> records) {this.current = current;this.size = size;this.total = total;this.pages = (total + size - 1) / size; // 计算总页数this.records = records;}/*** 从 List 创建分页对象*/public static <T> CustomPage<T> of(List<T> dataList, long current, long size) {long total = dataList.size();long startIndex = (current - 1) * size;long endIndex = Math.min(startIndex + size, total);List<T> pageRecords;if (startIndex >= total) {pageRecords = new ArrayList<>();} else {pageRecords = new ArrayList<>(dataList.subList((int) startIndex, (int) endIndex));}return new CustomPage<>(current, size, total, pageRecords);}
}
方案四:结合 Stream API 的高级用法
@Service
public class DataService {/*** 使用 Stream API 进行复杂分页*/public IPage<YourEntity> getComplexPageData(long current, long size, Map<String, Object> filters) {List<YourEntity> allData = getDataFromMemory();// 流式处理:过滤 -> 排序 -> 分页List<YourEntity> filteredData = allData.stream().filter(item -> filterCondition(item, filters)) // 自定义过滤条件.sorted(Comparator.comparing(YourEntity::getCreateTime).reversed()).collect(Collectors.toList());return PageUtils.paginateList(filteredData, current, size);}/*** 多条件动态查询*/public IPage<YourEntity> dynamicQueryPage(List<YourEntity> dataList, long current, long size,DynamicQuery query) {Stream<YourEntity> stream = dataList.stream();// 动态添加过滤条件if (StringUtils.hasText(query.getKeyword())) {stream = stream.filter(item -> item.getName().contains(query.getKeyword()));}if (query.getStartDate() != null) {stream = stream.filter(item -> !item.getCreateTime().before(query.getStartDate()));}List<YourEntity> filteredList = stream.collect(Collectors.toList());return PageUtils.paginateList(filteredList, current, size);}private boolean filterCondition(YourEntity item, Map<String, Object> filters) {// 实现你的过滤逻辑return true;}
}
前端调用示例
// Vue/React 调用示例
const getPageData = async (page = 1, page pageSize = 10) => {try {const response = await axios.get('/api/data/page', {params: {current: page,size: pageSize}});const pageInfo = response.data.data;console.log('当前页:', pageInfo.current);console.log('每页大小:', pageInfo.size);console.log('总记录数:', pageInfo.total);console.log('总页数:', pageInfo.pages);console.log('数据列表:', pageInfo.records);} catch (error) {console.error('请求失败:', error);}
};
关键要点总结
1、性能考虑:对于大数据集,建议缓存分页计算结果
2、线程安全:如果源 List 可能被并发修改,需要加锁或使用副本
3、空值处理:处理好边界情况(如超出范围的页码)
4、灵活性:可根据需要添加排序、过滤等功能
推荐使用方案一或方案二,它们结构清晰且易于维护,同时保持了与 MyBatis-Plus 的良好兼容性。
