1. 程式人生 > >JavaWeb 分頁查詢的實現

JavaWeb 分頁查詢的實現

1、建立一個數據表

USE test;

CREATE TABLE mybooks(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
author VARCHAR(100) NOT NULL,
price DOUBLE(12,2) NOT NULL
);

2、插入資料

INSERT INTO mybooks(name, author, price)
VALUES(‘歐葉妮·格朗臺’, ‘巴爾扎克’, 36.9),
(‘名利場’, ‘薩克雷’, 41.9),
(‘老人與海’, ‘海明威’, 36.5),
(‘簡·愛’, ‘夏洛蒂·勃朗特’, 42.9),
(‘好兵帥克’, ‘雅·哈謝克’, 11.3),
(‘父與子’, ‘屠格涅夫’, 25.2),
(‘基督山伯爵’, ‘大仲馬’, 39.9),
(‘飛鳥集’, ‘泰戈爾’, 32.9),
(‘三國演義’, ‘羅貫中’, 41.3),
(‘紅樓夢’, ‘曹雪芹’, 31.5),
(‘水滸傳’, ‘施耐庵’, 39.0),
(‘聊齋志異’, ‘蒲松齡’, 29.5),
(‘道德經’, ‘老子’, 59.0),
(‘平凡的世界’, ‘路遙’, 59.0),
(‘西遊記’, ‘吳承恩’, 41.3),
(‘包法利夫人’, ‘莫泊桑’, 32.3),
(‘小王子’, ‘聖埃克絮佩裡’, 36.3),
(‘圍城’, ‘錢鍾書’, 29.3),
(‘巴黎聖母院’, ‘雨果’, 26.3),
(‘伯羅奔尼撒戰爭史’, ‘修昔底德’, 29.6),
(‘坎特伯雷故事集’, ‘傑弗雷·喬叟’, 32.5),
(‘烏托邦’, ‘托馬斯·莫爾’, 19.6),
(‘魯濱遜漂流記’, ‘丹尼爾·笛福’, 15.3),
(‘國富論’, ‘亞當·斯密’, 29.5),
(‘傲慢與偏見’, ‘簡·奧斯汀’, 35.5),
(‘東方快車謀殺案’, ‘阿加莎·克里斯蒂’, 41.5),
(‘霧都孤兒’, ‘查爾斯·狄更斯’, 36.5),
(‘環遊世界八十天’, ‘儒勒·凡爾納’, 32.5),
(‘三個火槍手’, ‘大仲馬’, 32.5),
(‘戰爭與和平’, ‘托爾斯泰’, 40.5),
(‘書名1’, ‘作者1’, 19.5),
(‘書名2’, ‘作者2’, 11.5),
(‘書名3’, ‘作者3’, 21.5),
(‘書名4’, ‘作者4’, 26.5),
(‘書名5’, ‘作者5’, 23.5),
(‘書名6’, ‘作者6’, 41.2),
(‘書名7’, ‘作者7’, 31.7),
(‘書名8’, ‘作者8’, 22.6),
(‘書名9’, ‘作者9’, 18.7),
(‘書名10’, ‘作者10’, 27.8),
(‘書名11’, ‘作者11’, 25.6),
(‘書名12’, ‘作者12’, 14.5),
(‘書名13’, ‘作者13’, 33.5),
(‘書名14’, ‘作者14’, 28.5),
(‘書名15’, ‘作者15’, 45.5),
(‘書名16’, ‘作者16’, 41.5),
(‘書名17’, ‘作者17’, 43.6),
(‘書名18’, ‘作者18’, 39.6),
(‘書名19’, ‘作者19’, 26.3),
(‘書名20’, ‘作者20’, 49.5),
(‘書名21’, ‘作者21’, 28.5),
(‘書名22’, ‘作者22’, 59.5),
(‘書名23’, ‘作者23’, 50.5),
(‘書名24’, ‘作者24’, 19.3),
(‘書名25’, ‘作者25’, 34.5),
(‘書名16’, ‘作者26’, 20.1),
(‘書名27’, ‘作者27’, 30.5),
(‘書名28’, ‘作者28’, 12.6),
(‘書名29’, ‘作者29’, 29.2),
(‘書名30’, ‘作者30’, 18.5)

3、建立動態WEB工程

⑴ 建立一個Book的JavaBean

對應mybooks資料表的各個欄位,提供get和set方法,無參和有參的構造方法,以及重寫toString方法

⑵ 建立c3p0資料庫連線工具類

用於獲取Connection連線物件和關閉Connection連線物件

⑶ 建立一個帶泛型的BaseDAO類

① 查詢多行記錄的方法
② 查詢第一行第一列的方法

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import com.mybooks.utils.JDBCUtils;

public class BaseDAO<T> {
    private QueryRunner qr = new QueryRunner();
    private Class<T> type;

    public BaseDAO() {
        // 獲取父類的泛型
        Type genericSuperClass = this.getClass().getGenericSuperclass();
        // 向下轉型,以便呼叫方法
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperClass;
        // 取第一個泛型
        Type actualTypeArguments = parameterizedType.getActualTypeArguments()[0];
        // 向下轉型為Class型別
        type = (Class<T>) actualTypeArguments;
    }

    /**
     * 獲取多行記錄
     * 
     * @param sql
     *            SQL語句
     * @param args
     *            填充佔位符元素
     * @return 儲存到List集合中的多行記錄
     */
    public List<T> getBeanList(String sql, Object... args) {
        Connection connection = null;
        List<T> list = null;

        try {
            connection = JDBCUtils.getConnection();
            list = qr.query(connection, sql, new BeanListHandler<T>(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (null != connection) {
                JDBCUtils.closeConnection(connection);
            }
        }

        return list;
    }

    /**
     * 查詢第一行第一列的結果
     * 
     * @param sql
     *            SQL語句
     * @param args
     *            填充佔位符的元素
     * @return 第一行第一列的結果
     */
    public Object getValue(String sql, Object... args) {
        Connection connection = null;
        Object obj = null;

        try {
            connection = JDBCUtils.getConnection();
            obj = qr.query(connection, sql, new ScalarHandler<>(), args);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeConnection(connection);
        }

        return obj;
    }

}

⑷ 建立一個帶泛型的Page類 【★實現分頁的關鍵類】

屬性:

   ① 當前頁碼【Integer】
   ② 每頁要顯示的數量【Integer】
   ③ 資料庫中有多少條記錄【Integer】
   ④ 一共有多少頁【Integer】
      該屬性的值是通過資料庫中總的記錄數 / 每頁顯示的數量,計算得到的
      ⒈ 如果兩數能夠整除,則返回整除的結果
      ⒉ 如果不能整除,則返回除數再 加 1的結果
   ⑤ 查詢出的結果,儲存到List集合中【List<T>】

方法【提供get和set方法】:

   ① 設定和獲取當前頁碼
   ② 設定和獲取資料庫中的記錄數
   ③ 獲取一共有多少頁碼
      set方法,則是通過計算得出
   ④ 設定和獲取List集合

防止出錯的處理:
【在獲取當前頁碼時】

⒈ 如果當前頁碼設定的小於1,則返回1
⒉ 如果當前頁碼設定的大於總的頁碼數:
   ㈠ 如果總的頁碼數等於0【沒有查詢出結果】,則返回1
   ㈡ 如果總的頁碼數不等於0,則返回總的頁碼數
⒊ 其他情況,就正常返回

程式碼:

import java.util.List;

public class Page<T> {
    private Integer pageNo; // 當前頁碼
    public static final Integer SHOW_ITEMS = 5; // 每頁顯示多少資訊
    private Integer countNo; // 資料庫中一共有多少符合條件的記錄
    private Integer totalPageNo; // 一共有多少頁碼
    private List<T> list; // 把查詢出來的記錄儲存到List集合中

    public Integer getPageNo() {
        // 如果當前頁碼小於1,則返回1
        if (pageNo < 1) {
            return 1;
        }

        // 如果當前頁碼大於總的頁碼,則返回總的頁碼
        if (pageNo > getTotalPageNo()) {
            // 如果總的頁碼等於0【當價格查詢時,沒有符合條件的情況】,則返回1
            if (0 == getTotalPageNo()) {
                return 1;
            }

            // 總的頁碼不等於0,返回總的頁碼
            return getTotalPageNo();
        }

        // 其他情況就正常返回
        return pageNo;
    }

    public void setPageNo(Integer pageNo) {
        this.pageNo = pageNo;
    }

    public Integer getCountNo() {
        return countNo;
    }

    public void setCountNo(Integer countNo) {
        this.countNo = countNo;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public Integer getTotalPageNo() {
        // 如果總的記錄數能夠被每頁顯示的數量整除,就返回整除的結果
        if (0 == getCountNo() % SHOW_ITEMS) {
            return getCountNo() / SHOW_ITEMS;
        }

        // 如果不能被整除,就在除以的結果上 + 1
        return getCountNo() / SHOW_ITEMS + 1;
    }

}

⑸ 建立一個QueryBooksDAO介面

① 查詢資料庫中有多少條記錄的方法【可以傳入Object型別的可變引數 以此來查詢符合價格範圍內的記錄數】
② 傳入一個帶有當前頁的屬性的Page物件,返回一個帶有所有屬性的Page物件

public interface QueryBooksDAO {

    /**
     * 用於查詢符合條件的所有的Book物件的數量
     * 
     * @param args
     *            可以傳入最低價格和最高價格
     * @return 一共有多少符合規則的記錄
     */
    Object getValue(Object... args);

    /**
     * 查詢指定頁碼的Book資訊
     * 
     * @param page
     *            一個只有當前頁碼屬性的Page物件
     * @return 返回一個List屬性為【當前頁碼的所有的Book物件】的Page物件
     */
    Page<Book> queryLimitedBooks(Page<Book> page);

}

⑹ 建立一個QueryBooksDAOImpl類

其繼承自BaseDAO,並實現了QueryBooksDAO的所有的抽象方法

public class QueryBookDAOImpl extends BaseDAO<Book> implements QueryBooksDAO {

    @Override
    public Object getValue(Object... args) {
        String sql = "SELECT COUNT(id) FROM test.mybooks WHERE price BETWEEN ? AND ?";
        return getValue(sql, args);
    }

    @Override
    public Page<Book> queryLimitedBooks(Page<Book> page) {
        String sql = "SELECT id, name, author, price FROM test.mybooks LIMIT ?, ?";

      // 這裡將最低價格賦值為0,最高價格為Double的最大值。這樣就能查詢出所有的Book物件
        long countNo = (long) getValue(0, Double.MAX_VALUE);

        // 設定資料庫中一共有多少條記錄
        page.setCountNo((int) countNo);

        // 獲取當前頁碼
        int pageNo = page.getPageNo();

        // LIMIT的第一個引數
        int a = (pageNo - 1) * Page.SHOW_ITEMS;

        // 查詢出當前頁碼中的所有的Book物件
        List<Book> books = getBeanList(sql, a, Page.SHOW_ITEMS);
        // 賦值給page物件的List屬性
        page.setList(books);

        return page;
    }

}

⑺ 建立一個QueryBooksServer的介面

根據指定頁碼查詢相應的記錄的方法

public interface QueryBooksServer {

    /**
     * 傳入當前頁碼,返回List屬性為當前頁碼所有的Book物件的一個Page物件
     * 
     * @param pageNoStr
     *            當前頁碼
     * @return List屬性為所有符合條件的Book物件的Page物件
     */
    Page<Book> queryLimitedBooks(String pageNoStr);

}

⑻ 建立一個QueryBooksServerImpl類

其實現了QueryBooksServer的所有的抽象方法

public class QueryBooksServerImpl implements QueryBooksServer {
    private QueryBooksDAO dao = new QueryBookDAOImpl();

    @Override
    public Page<Book> queryLimitedBooks(String pageNoStr) {
        int pageNo = 1;

        try {
            pageNo = Integer.parseInt(pageNoStr);
        } catch (NumberFormatException e) {
        }

        // 建立一個Page物件
        Page<Book> page = new Page<Book>();
        // 只給當前頁碼屬性賦值
        page.setPageNo(pageNo);

        // 返回一個包含了所有的屬性值的Page物件
        return dao.queryLimitedBooks(page);
    }

}

⑼ 建立一個BaseServlet

其就是一個普通的繼承自HttpServlet的Servlet,doPost呼叫doGet。在doGet中,獲取方法名的請求引數,通過反射來呼叫繼承自BaseServlet的子Servlet的相應方法

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    String methodName = request.getParameter("method");

    Class<? extends BaseServlet> clazz = this.getClass();
    try {
        Method method = clazz.getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
        method.setAccessible(true);
        method.invoke(this, request, response);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }

}

⑽ 建立QueryBooksServlet 子Servlet

其繼承自BaseServlet,裡面只有具體的業務方法

查詢指定頁碼的Book物件的方法,通過呼叫業務邏輯層【server】的相關方法,得到Page物件,再將其放到request域中,再轉發到要顯示的JSP頁面

public class QueryBooksServlet extends BaseServlet {
    private static final long serialVersionUID = 1L;
    private QueryBooksServer server = new QueryBooksServerImpl();

    private void queryLimitedBooks(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String pageNo = request.getParameter("pageNo");
        Page<Book> page = server.queryLimitedBooks(pageNo);

        // 將Page物件放到request域中
        request.setAttribute("page", page);
        // 轉發到顯示頁面
        request.getRequestDispatcher("???.jsp").forward(request, response);
    }

}

4、JSP頁面的編寫

⑴ 首先編寫index.jsp

裡面呼叫JSP的動作標籤,轉發到QueryBooksServlet中,並攜帶方法的請求引數

<jsp:forward page="/queryBooks?method=queryLimitedBooks"></jsp:forward>

⑵ 編寫顯示查詢結果的JSP頁面

可以寫一個base標籤,其href到當前WEB應用的根路徑。可以使用獲取的方式,保證無論換到哪裡,都是通用的:

<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/" />

需要呼叫JSTL的

  ① <c:if>來判斷request域中的Page物件的list屬性是否為empty
  ② 如果list集合中有Book物件,就用
    <c:forEach>來遍歷所有的Book物件,通過EL表示式,獲取Book物件的相應的屬性值

頁碼導航欄的編寫【普通的頁碼導航欄】

① 需要有首頁,前一頁,當前頁 - 1,當前頁,當前頁 + 1,下一頁,末頁。這些都是a標籤
② 需要提示使用者一共有多少條記錄,一共有幾頁。並提供輸入框,用於輸入要跳轉的頁碼。並提供一個跳轉的按鈕

分析:
⒈ 首頁的href可以直接寫方法的請求引數
⒉ 前一頁 和 當前頁 - 1,需要判斷當前頁碼是否為1:如果當前頁碼為1,則需要將這兩個a標籤變為文字顯示;否則就顯示a標籤
⒊ 同理:下一頁 和 當前頁 + 1,的顯示和隱藏替換和上面類似
⒋ 末頁的href的pageNo請求引數就是一共有多少頁碼
⒌ 一共有多少條記錄,和一共有多少頁。都可以通過page物件來獲取
⒍ 提供一個輸入框,新增一個id,方便獲取其value值
⒎ 提供一個按鈕,新增一個id,方便新增點選事件
⒏ 按鈕的點選事件:首先獲取輸入跳轉頁碼的輸入框value屬性值,然後呼叫window.location.href = 要跳轉的頁面,來實現要跳轉的頁面

Tips:

window.location.href,還可以寫為:
Window.location,還可以寫為:
location

程式碼:
【頁碼導航條】

    <div class="nav">

        <%-- 當前頁碼大於1 --%>
        <c:if test="${requestScope.page.pageNo > 1}">
            <a href="queryBooks?method=queryLimitedBooks">首頁</a>
            <a href="queryBooks?method=queryLimitedBooks&pageNo=${requestScope.page.pageNo - 1}">前一頁</a>
        </c:if>
        <%-- 當前頁碼等於1 --%>
        <c:if test="${requestScope.page.pageNo == 1}">
            首頁
            前一頁
        </c:if>

        <a style="color:red; text-decoration:none;" href="queryBooks?method=queryLimitedBooks&pageNo=${requestScope.page.pageNo}">【${requestScope.page.pageNo}】</a>

        <%-- 當前頁碼小於總頁碼 --%>
        <c:if test="${requestScope.page.pageNo < requestScope.page.totalPageNo}">
            <a href="queryBooks?method=queryLimitedBooks&pageNo=${requestScope.page.pageNo + 1}">下一頁</a>
            <a href="queryBooks?method=queryLimitedBooks&pageNo=${requestScope.page.totalPageNo}">末頁</a>
        </c:if>
        <%-- 當前頁碼等於總頁碼 --%>
        <c:if test="${requestScope.page.pageNo == requestScope.page.totalPageNo}">
            下一頁
            末頁
        </c:if>

    </div>
    <div class="choose">
        一共有 ${requestScope.page.countNo} 條記錄&nbsp;&copy;&nbsp;
        一共有 ${requestScope.page.totalPageNo} 頁&nbsp;
        跳轉到第 <input type="text" value="${requestScope.page.pageNo}" id="goPageNo" /> 頁&nbsp;
        <input type="button" id="goBtn" value="跳轉" />
    </div>

【JS程式碼】

<script type="text/javascript">
    window.onload = function(){
        var goBtn = document.getElementById("goBtn");
        goBtn.onclick = function(){
            var goPageNo = document.getElementById("goPageNo").value;

            location = "queryBooks?method=queryLimitedBooks&pageNo=" + goPageNo;
        };
    };
</script>

5、帶有價格查詢範圍的查詢【新增方法】

⑴ 給QueryBooksDAO介面新增規範

/**
 * 根據指定的頁碼,價格範圍。來查詢指定的圖書資訊
 * 
 * @param page
 *            一個只有當前頁碼屬性的Page物件
 * @param min
 *            最低價格
 * @param max
 *            最高價格
 * @return 一個Page物件,其List屬性值為【符合價格範圍的,當前頁碼的所有的Book物件】
 */
Page<Book> queryLimitedBooksByMinpriceAndMaxprice(Page<Book> page, Double min, Double max);

⑵ QueryBookDAOImpl實現新新增的方法

@Override
public Page<Book> queryLimitedBooksByMinpriceAndMaxprice(Page<Book> page, Double min, Double max) {
    String sql = "SELECT id, name, author, price FROM test.mybooks WHERE price BETWEEN ? AND ? LIMIT ?, ?";

    // 獲取資料庫中的記錄數
    long countNo = (long) getValue(min, max);

    // 給一共有多少記錄屬性賦值
    page.setCountNo((int) countNo);

    // 得到LIMIT的第一個引數
    int a = (page.getPageNo() - 1) * Page.SHOW_ITEMS;

    List<Book> books = getBeanList(sql, min, max, a, Page.SHOW_ITEMS);

    // 將查詢出結果賦予Page物件
    page.setList(books);

    return page;
}

⑶ 給QueryBooksServer介面新增規範

/**
 * 傳入當前頁碼,最低價格和最高價格。返回List屬性值為價格範圍內的當前頁碼的所有Book物件的一個Page物件
 * 
 * @param pageNoStr
 *            當前頁碼
 * @param minPrice
 *            最低價格
 * @param maxPrice
 *            最高價格
 * @return List屬性值為價格範圍內的當前頁碼的Book物件的Page物件
 */
Page<Book> queryPageBooksByMinpriceAndMaxprice(String pageNoStr, String minPrice, String maxPrice);

⑷ QueryBooksServerImpl實現新新增的方法

@Override
public Page<Book> queryPageBooksByMinpriceAndMaxprice(String pageNoStr, String minPrice, String maxPrice) {
    // 預設頁碼
    int pageNo = 1;

    try {
        pageNo = Integer.parseInt(pageNoStr);
    } catch (NumberFormatException e) {
    }

    // 預設最低價格
    Double min = 0.0;
    try {
        min = Double.parseDouble(minPrice);
    } catch (NullPointerException e1) {
    } catch (NumberFormatException e2) {
    }

    // 預設最高價格
    Double max = Double.MAX_VALUE;
    try {
        max = Double.parseDouble(maxPrice);
    } catch (NullPointerException e1) {
    } catch (NumberFormatException e2) {
    }

    // 如果最低價格大於最高價格,交換
    if (min > max) {
        min += max;
        max = min - max;
        min = min - max;
    }

    Page<Book> page = new Page<Book>();
    // 賦予當前頁碼值
    page.setPageNo(pageNo);

    return dao.queryLimitedBooksByMinpriceAndMaxprice(page, min, max);
}

⑸ 給QueryBooksServlet新增新的方法

private void queryPageBooksByMinpriceAndMaxprice(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    String pageNoStr = request.getParameter("pageNo");
    String minPrice = request.getParameter("min");
    String maxPrice = request.getParameter("max");

    Page<Book> page = server.queryPageBooksByMinpriceAndMaxprice(pageNoStr, minPrice, maxPrice);
    request.setAttribute("page", page);
    request.getRequestDispatcher("???.jsp").forward(request, response);
}

6、編寫帶有價格查詢的JSP頁面【進階的頁碼導航欄】

實現的效果

最終實現的頁碼導航欄的效果是:指定一次顯示5個頁碼,儘量讓當前頁碼在中間位置

分析

⑴ 導航條的實現


可以使用
  <c:forEach begin="起始頁碼" end="結束頁碼" var="當前頁碼">
    <a href="">${當前頁碼}</a>
  </c:forEach>

來動態地實現頁碼導航欄的建立

動態地給begin和end賦值,有四中情況:
① 情況一:當總的頁碼值不夠指定每頁顯示的頁碼數(5個)的時候。這時begin就是1,end就是總的頁碼值

② 情況二:當總的頁碼值超過了指定每頁顯示的頁碼數,但是當前頁碼值小於等於指定頁碼數的中間位置【3 = (5 + 1) / 2】時。這時begin就是1,end就是5(指定每頁顯示的頁碼數)

③ 情況三:當總的頁碼值吵過了指定的頁碼數,並且已經超過了指定頁碼數的中間位置,但是此時當前頁碼小於總的頁碼數 - 2。這時begin就是當前頁碼 - 2,end就是當前頁碼 + 2。這是保證當前頁碼在中間位置的關鍵

④ 情況四:當前頁碼值已經超過了總的頁碼值 - 2的位置。這時begin就是總的頁碼值 + 1 - 5,end就是總的頁碼。這樣才能保證頁碼範圍不會超過總的頁碼,並且顯示的頁碼數也是5個,即指定每頁顯示的頁碼數量

要實現這四種情況,就要用

   <c:choose>
     <c:when test="當前頁碼所屬的範圍">
       <c:set var="起始頁碼" value="起始頁碼值"></c:set>
       <c:set var="結束頁碼" value="結束頁碼值"></c:set>
     </c:when>
   </c:choose>

來實現

⑵ 最低價格和最高價格的提交

可以建立一個form表單,新增兩個文字框,和一個提交按鈕。這樣就可以提交到Servlet中。而且因為查詢的整個過程,一直是用請求的轉發,所以可以保證request域中的資料可以被重複多次獲取使用

Tips:可以通過 ${param.標籤的name屬性值} 來獲取

⑶ URI地址的改寫

因為添加了價格範圍的查詢,所以需要再新增兩個請求引數,分別提交最低價格和最高價格。因為在業務邏輯層【Server】中添加了預設值,即0和Double的最大值。所以可以傳遞空串。但是要注意空指標的問題,因為Double的parseDouble方法,不能轉換null值。所以需要在Server層轉換的時候,把NullPointerException catch一下。

JSP頁面的編寫

【頁碼導航條】

    <div class="nav">
        <%-- 指定顯示的頁碼數量是5 --%>
        <c:set var="defaultShowPageNo" value="<%=Page.SHOW_ITEMS%>"></c:set>

        <c:choose>
            <%-- 【情況一】總的頁碼數量小於指定顯示的頁碼數量 --%>
            <c:when test="${requestScope.page.totalPageNo < defaultShowPageNo}">
                <c:set var="beginPageNo" value="1"></c:set>
                <c:set var="endPageNo" value="${requestScope.page.totalPageNo}"></c:set>
            </c:when>

            <%-- 【情況二】當前頁碼小於等於指定顯示的頁碼數量的中間位置 --%>
            <c:when test="${requestScope.page.pageNo <= ((defaultShowPageNo + 1) / 2)}">
                <c:set var="beginPageNo" value="1"></c:set>
                <c:set var="endPageNo" value="${defaultShowPageNo}"></c:set>
            </c:when>

            <%-- 【情況三】當前頁碼小於等於總的頁碼數 - 2(就是到最後的中間位置時) --%>
            <c:when test="${requestScope.page.pageNo <= (requestScope.page.totalPageNo - 2)}">
                <c:set var="beginPageNo" value="${requestScope.page.pageNo - 2}"></c:set>
                <c:set var="endPageNo" value="${requestScope.page.pageNo + 2}"></c:set>
            </c:when>

            <%-- 【情況四】當前頁碼大於總的頁碼數 - 2 --%>
            <c:when test="${requestScope.page.pageNo > (requestScope.page.totalPageNo - 2)}">
                <c:set var="beginPageNo" value="${requestScope.page.totalPageNo + 1 - defaultShowPageNo}"></c:set>
                <c:set var="endPageNo" value="${requestScope.page.totalPageNo}"></c:set>
            </c:when>
        </c:choose>


        <c:if test="${requestScope.page.pageNo > 1}">
            <a href="queryBooks?method=queryPageBooksByMinpriceAndMaxprice&min=${param.min}&max=${param.max}">首頁</a>
            <a href="queryBooks?method=queryPageBooksByMinpriceAndMaxprice&pageNo=${requestScope.page.pageNo - 1}&min=${param.min}&max=${param.max}">前一頁</a>
        </c:if>
        <c:if test="${requestScope.page.pageNo == 1}">
            首頁
            前一頁
        </c:if>

        <%-- 從page域中取出開始和結束下標值 --%>
        <c:forEach begin="${beginPageNo}" end="${endPageNo}" var="index">
            <c:if test="${index == requestScope.page.pageNo}">
                <a style="color:red; text-decoration:none;" href="queryBooks?method=queryPageBooksByMinpriceAndMaxprice&pageNo=${index}&min=${param.min}&max=${param.max}">【${index}】</a>
            </c:if>

            <c:if test="${index != requestScope.page.pageNo}">
                <a href="queryBooks?method=queryPageBooksByMinpriceAndMaxprice&pageNo=${index}&min=${param.min}&max=${param.max}">${index}</a>
            </c:if>
        </c:forEach>

        <c:if test="${requestScope.page.pageNo < requestScope.page.totalPageNo}">
            <a href="queryBooks?method=queryPageBooksByMinpriceAndMaxprice&pageNo=${requestScope.page.pageNo + 1}&min=${param.min}&max=${param.max}">下一頁</a>
            <a href="queryBooks?method=queryPageBooksByMinpriceAndMaxprice&pageNo=${requestScope.page.totalPageNo}&min=${param.min}&max=${param.max}">末頁</a>
        </c:if>
        <c:if test="${requestScope.page.pageNo == requestScope.page.totalPageNo}">
            下一頁
            末頁
        </c:if>

    </div>
    <div class="choose">
        一共有 ${requestScope.page.countNo} 條記錄&nbsp;&copy;&nbsp;
        一共有 ${requestScope.page.totalPageNo} 頁&nbsp;
        跳轉到第 <input type="text" value="${requestScope.page.pageNo}" id="goPageNo" /> 頁&nbsp;
        <input type="button" id="goBtn" value="跳轉" />
    </div>

【價格提交的form表單】

        <form action="queryBooks?method=queryPageBooksByMinpriceAndMaxprice" method="post">
            價格查詢:
            <input class="priceTxt" type="text" name="min" value="${param.min}" />元 -
            <input class="priceTxt" type="text" name="max" value="${param.max}" />元
            <input id="queryBtn" type="submit" value="查詢" />
        </form>

【JS程式碼】

<script type="text/javascript">
    window.onload = function(){
        var goBtn = document.getElementById("goBtn");
        goBtn.onclick = function(){
            var goPageNo = document.getElementById("goPageNo").value;

            location = "queryBooks?method=queryPageBooksByMinpriceAndMaxprice&pageNo=" + goPageNo + "&min=${param.min}&max=${param.max}";
        };
    };
</script>

7、最終實現的效果

普通的頁碼導航欄

普通的頁碼導航欄

進階的頁碼導航欄

進階的頁碼導航欄