JavaWeb 分页查询的实现

0、感谢大家的支持!

非常感谢大家的支持,我没有想到这篇笔记式的文章会这么受欢迎
这是 GitHub的仓库链接

1、创建一个数据表

USE test;

CREATE TABLE mybooks (
  id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  name VARCHAR(100) NOT NULL COMMENT '书名',
  author VARCHAR(100) NOT NULL COMMENT '作者',
  price DOUBLE(12,2) NOT NULL COMMENT '价格',
  PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

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方法

⑵ 创建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 ???.???.???.???.JDBCUtils;

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

    @SuppressWarnings("unchecked")
	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");
    if (null == methodName || 0 == methodName.length()) {
        response.sendRedirect("index.jsp");
        return;
    }
	
	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 (ReflectiveOperationException 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 goPageNoEle = document.getElementById("goPageNo");
			var goPageNo = goPageNoEle.value;
			goPageNo = parseInt(goPageNo);
            if (isNaN(goPageNo)) {
                alert('页码不是数值!');
                goPageNoEle.value = 1;
                return;
            }
			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 goPageNoEle = document.getElementById("goPageNo");
			var goPageNo = goPageNoEle.value;
			goPageNo = parseInt(goPageNo);
            if (isNaN(goPageNo)) {
                alert('页码不是数值!');
                goPageNoEle.value = 1;
                return;
            }

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

7、最终实现的效果

普通的页码导航栏

普通的页码导航栏

进阶的页码导航栏

进阶的页码导航栏

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值