首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JavaBean + Servlet + JSP 實現分頁功能完整教程

     編輯:Java 相關知識

分頁是 Web 應用最基礎的功能之一。本文採用經典三層架構 (Model/DAO/Service) + Servlet 控制器 + JSP 視圖,構建一個完整、可復用的分頁組件,涵蓋 PageBean 封裝、邊界處理、前端交互 (首頁/末頁/上下頁/下拉跳轉/輸入框跳轉) 及 JSTL 改造。

整體架構


┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
│  JSP    │◀───▶│ Servlet │◀───▶│ Service │◀───▶│  DAO    │
│  視圖層  │     │ 控制層  │     │ 業務層  │     │ 數據層  │
└─────────┘     └─────────┘     └─────────┘     └─────────┘
       ▲                                               │
       │                    ┌──────────────┐           │
       └───────────────────▶│  PageBean    │◀──────────┘
                            │  分頁數據封裝  │
                            └──────────────┘

領域模型


// Blog.java 實體類
public class Blog {
    private int id;
    private int categoryId;
    private String title;
    private String content;
    private Date createdTime;
    // getter/setter/toString 省略
}

分頁核心:PageBean 封裝所有分頁元數據


public class BlogPage {
    private List pageRecords;   // 當前頁記錄
    private int pageNo;               // 當前頁碼 (1-based)
    private int pageNoStart;          // 當前頁起始索引 (0-based, 用於 LIMIT)
    private int pageSize = 5;         // 每頁條數
    private int totalRecord;          // 總記錄數
    private int totalPage;            // 總頁數

    /** 單一構造器:由 Service 傳入 pageNo、totalRecord 自動推算其餘 */
    public BlogPage(int pageNo, int totalRecord) {
        this.totalRecord = totalRecord;
        this.totalPage = (totalRecord % pageSize == 0) 
            ? totalRecord / pageSize 
            : totalRecord / pageSize + 1;

        // 邊界修正
        if (pageNo <= 1) this.pageNo = 1;
        else if (pageNo >= totalPage) this.pageNo = totalPage;
        else this.pageNo = pageNo;

        this.pageNoStart = (this.pageNo - 1) * pageSize;
    }
    // getter/setter 省略
}

DAO 層:MySQL LIMIT 分頁查詢


public class BlogDao {
    // 分頁查詢:LIMIT offset, size
    public List getPageRecord(int offset, int pageSize) {
        String sql = "SELECT * FROM blog LIMIT ?, ?";
        try (Connection conn = JDBCUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, offset);
            ps.setInt(2, pageSize);
            ResultSet rs = ps.executeQuery();
            List list = new ArrayList<>();
            while (rs.next()) {
                Blog b = new Blog();
                b.setId(rs.getInt("id"));
                b.setCategoryId(rs.getInt("category_id"));
                b.setTitle(rs.getString("title"));
                b.setContent(rs.getString("content"));
                b.setCreatedTime(rs.getDate("created_time"));
                list.add(b);
            }
            return list;
        } catch (SQLException e) { throw new RuntimeException(e); }
    }

    // 總記錄數
    public int getTotal() {
        String sql = "SELECT COUNT(*) FROM blog";
        try (Connection conn = JDBCUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql);
             ResultSet rs = ps.executeQuery()) {
            return rs.next() ? rs.getInt(1) : 0;
        } catch (SQLException e) { throw new RuntimeException(e); }
    }
}

Service 層:組裝 PageBean


public class BlogService {
    private BlogDao dao = new BlogDao();

    public BlogPage findPageRecord(int pageNo) {
        int total = dao.getTotal();
        BlogPage page = new BlogPage(pageNo, total);
        List records = dao.getPageRecord(page.getPageNoStart(), page.getPageSize());
        page.setPageRecords(records);
        return page;
    }
}

Servlet 控制器:處理請求參數、轉發


@WebServlet("/BlogSplitServlet")
public class BlogSplitServlet extends HttpServlet {
    private BlogService service = new BlogService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        
        // 1. 獲取頁碼參數,預設第 1 頁
        String pageNoStr = req.getParameter("pageno");
        int pageNo = 1;
        if (pageNoStr != null) {
            try { pageNo = Integer.parseInt(pageNoStr); } 
            catch (NumberFormatException ignored) {}
        }

        // 2. 業務處理
        BlogPage page = service.findPageRecord(pageNo);

        // 3. 尾頁補白:保證表格行數一致 (可選,視 UI 需求)
        List list = page.getPageRecords();
        if (list.size() < page.getPageSize()) {
            for (int i = list.size(); i < page.getPageSize(); i++) list.add(null);
        }

        // 4. 轉發到 JSP
        req.setAttribute("blogPage", page);
        req.getRequestDispatcher("/blogPage.jsp").forward(req, resp);
    }

    @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException { doGet(req, resp); }
}

JSP 視圖:原始版 (Scriptlet) 與 JSTL 版對比

版本 A:Scriptlet 版 (教學/舊專案)


<%@ page import="java.util.*,model.Blog,model.BlogPage" %>
<%
    BlogPage page = (BlogPage) request.getAttribute("blogPage");
    List list = page.getPageRecords();
%>

    <% for (Blog b : list) { 
           if (b != null) { %>
    
    <% } else { %>
    
    <% } } %>
ID標題內容創建時間
<%=b.getId()%><%=b.getTitle()%> <%=b.getContent()%><%=b.getCreatedTime()%>

版本 B:JSTL 版 (推薦,關閉 Scriptlet)


<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>

        
            
                
                
ID標題內容創建時間
${b.id}${b.title}${b.content}${b.createdTime}

前端交互邏輯說明

控件觸發事件跳轉邏輯
下拉選單onchange直接跳轉到選中頁碼
輸入框onblur失焦時跳轉輸入頁碼 (需前端校驗數字範圍)
首頁/尾頁click固定 pageno=1 / pageno=totalPage
上一頁/下一頁click邊界保護:最小 1、最大 totalPage

關鍵優化與擴展點

  1. 計數查詢優化:大數據量時 `COUNT(*)` 慢,可用觸發器維護計數表、或估算值 (EXPLAIN)。
  2. 游標分頁:`WHERE id > lastId ORDER BY id LIMIT size` 避免深分頁 OFFSET 掃描慢。
  3. PageBean 泛型化:`PageBean` 復用於所有實體。
  4. 前端組件化:提取分頁片段為 `pagination.jspf` 或 Vue/React 組件。
  5. RESTful 風格:`/blogs?page=2&size=10` 替代 `pageno` 參數。
  6. 緩存總數:Redis 緩存 `totalRecord`,定時/事件驅動刷新。

常見坑點檢查清單

  • ✅ `pageNo` 參數校驗:非數字、負數、超過總頁數 → 修正為邊界值。
  • ✅ `LIMIT` 參數順序:MySQL `LIMIT offset, size`,PostgreSQL `LIMIT size OFFSET offset`。
  • ✅ 尾頁補白邏輯放在 Servlet (控制層) 而非 JSP,保持視圖純粹。
  • ✅ JSTL 表達式語言 (EL) 需啟用:`<%@ page isELIgnored="false" %>` 或 web.xml 配置。
  • ✅ 編碼統一:`request.setCharacterEncoding("UTF-8")`、頁面 `pageEncoding="UTF-8"`、資料庫連接 `characterEncoding=utf8`。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved