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

Spring Boot分页Bug:空数据表时错误显示多页(应为1页)

Spring Boot分页异常问题:无数据时错误显示多页

问题现象

  • 当数据表存在9条有效数据、每页显示5条时,分页正常(共2页);
  • 当数据表无有效记录时,错误显示多页,实际应仅显示1页。

相关代码

ProductDAO.java

package com.springboot3.sb3hxh.DAO;

import com.springboot3.sb3hxh.Entity.*;

import java.util.*;

public interface ProductDAO {

    List<ProductEntity> indexPagination(int page, int size);
    int totalProducts();

}

ProductService.java

package com.springboot3.sb3hxh.Service;

import com.springboot3.sb3hxh.DAO.*;
import com.springboot3.sb3hxh.Entity.*;
import jakarta.persistence.*;
import jakarta.transaction.*;
import org.springframework.stereotype.*;

import java.time.*;
import java.util.*;

@Service
public class ProductService implements ProductDAO {

    @PersistenceContext
    private EntityManager entityManager;

    public ProductService(EntityManager theEntityManager) {
        this.entityManager = theEntityManager;
    }

    @Override
    public List<ProductEntity> indexPagination(int page, int size) {
        TypedQuery<ProductEntity> query = entityManager.createQuery("SELECT p FROM ProductEntity p " +
                "WHERE p.deleted_at IS NULL " +
                "ORDER BY p.id ASC", ProductEntity.class);
        query.setFirstResult(page * size);
        query.setMaxResults(size);
        return query.getResultList();
    }


    @Override
    public int totalProducts() {
        TypedQuery<Long> query = entityManager.createQuery("SELECT COUNT(p) FROM ProductEntity p", Long.class);
        return query.getSingleResult().intValue();
    }

}

ProductController.java

package com.springboot3.sb3hxh.Controller;

import com.springboot3.sb3hxh.Entity.*;
import com.springboot3.sb3hxh.Service.*;
import jakarta.validation.*;
import org.springframework.stereotype.*;
import org.springframework.ui.*;
import org.springframework.validation.*;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@Controller
@RequestMapping("/products")
public class ProductController {

    private ProductService productService;

    public ProductController(ProductService theProductService){
        productService = theProductService;
    }

    @GetMapping("/list")
    public String listProducts(Model model, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "5") int size){
        List<ProductEntity> productEntity = productService.indexPagination(page -1, size);
        int totalItems = productService.totalProducts();
        int totalPages = (int) Math.ceil((double) totalItems / size);
        model.addAttribute("currentPage", page);
        model.addAttribute("totalPages", totalPages);
        model.addAttribute("products", productEntity);
        return "/product/list-products";
    }

} 

list-products.html

<div class="pagination justify-content-center">
    <ul class="pagination">
        <li class="page-item" th:each="i: ${#numbers.sequence(1, totalPages)}" th:class="${currentPage == i} ? 'active' : ''">
            <a class="page-link" th:href="@{'/products/list?page=' + ${i}}">[[${i}]]</a>
        </li>
    </ul>
</div>

问题原因

  1. 统计与查询条件不一致:分页查询过滤了deleted_at IS NULL的有效数据,但totalProducts()方法统计的是所有ProductEntity(包括已删除数据)。若存在已删除数据,无有效记录时totalItems仍不为0,导致计算出错误的总页数。
  2. 无数据时总页数计算错误:当totalItems为0时,Math.ceil(0/size)结果为0,Thymeleaf的#numbers.sequence(1, 0)会生成反向序列,导致显示异常页码。

解决方案

1. 修正统计方法的过滤条件

修改ProductService中的totalProducts()方法,与分页查询保持一致的过滤条件:

@Override
public int totalProducts() {
    TypedQuery<Long> query = entityManager.createQuery("SELECT COUNT(p) FROM ProductEntity p WHERE p.deleted_at IS NULL", Long.class);
    return query.getSingleResult().intValue();
}

2. 处理无数据时的总页数逻辑

在ProductController中修改总页数计算逻辑,确保无数据时总页数为1:

int totalPages = totalItems == 0 ? 1 : (int) Math.ceil((double) totalItems / size);

3. 优化当前页合法性校验

添加当前页超出总页数时的重定向处理,避免显示空数据:

@GetMapping("/list")
public String listProducts(Model model, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "5") int size){
    int totalItems = productService.totalProducts();
    int totalPages = totalItems == 0 ? 1 : (int) Math.ceil((double) totalItems / size);
    
    // 处理当前页超出总页数的情况
    if (page > totalPages) {
        page = totalPages;
        return "redirect:/products/list?page=" + page + "&size=" + size;
    }
    
    List<ProductEntity> productEntity = productService.indexPagination(page -1, size);
    model.addAttribute("currentPage", page);
    model.addAttribute("totalPages", totalPages);
    model.addAttribute("products", productEntity);
    return "/product/list-products";
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 04:45:58