JSP分页显示实例(基于Bootstrap)
首先介绍一款简单利落的分页显示利器:bootstrap-paginator
效果截图:
GitHub官方下载地址:https://github.com/lyonlai/bootstrap-paginator
备用下载地址:https://files.cnblogs.com/files/Dreamer-1/bootstrap-paginator-master.rar
下面就来详细介绍一下基于这款分页利器的JSP分页显示实现过程(注:相较于原网页我隐去了很多不必要的内容,本例只专注于分页显示的实现)
一:
为什么需要分页显示?
这篇博文的博主说得很透彻:http://blog.csdn.net/xiaoyousifang/article/details/5659667
二:
JSP页面部分,这里直接在JSP页面中用JDBC连接SqlServer2005数据库查询数据(实际实现里不建议把复杂的业务逻辑封装在JSP页面中,JSP页面应当只是负责显示;对客户端的响应、业务逻辑调用、结果转发都应该由Servlet来完成)
代码如下:
<%@ page import="PaginationExample.*" %> <%@ page import="java.util.*"%> <%@ page import="java.sql.*"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%! private static final int pageSize = 20; //设定每页显示的记录条数(当前为每页显示20条记录) %> <% request.setCharacterEncoding("UTF-8"); //设定客户端提交给servlet的内容按UTF-8编码 response.setCharacterEncoding("UTF-8"); //设定servlet传回给客户端的内容按UTF-8编码 response.setContentType("text/html;charset=UTF-8"); //告知浏览器用UTF-8格式解析内容 String pageNoStr = request.getParameter("pageNoStr"); //接收客户端传递的要显示页数 int pageNo = 1; //要显示的页数 int totalPages = 1; //总页数 //检查、设置pageNo if (pageNoStr != null && !pageNoStr.equals("")) { try { pageNo = Integer.parseInt(pageNoStr); if (pageNo < 1) { //pageNo小于1时默认显示第一页 pageNo = 1; } } catch (NumberFormatException e) { //获取到的pageNo(当前页面数)不合法时,默认显示第一页 pageNo = 1; } } else { //其他未获取到pageNo的情况都默认显示第一页 pageNo = 1; } /* ========================================连接数据库(获取总页数与当前页内要显示的观测记录)====================================== */ /* 获取数据库中将记录按指定条数(pageSize)分页后的总页数 */ Connection totalConn = null; Statement totalStmt = null; ResultSet totalRs = null; try { totalConn = DBUtil.getConnection(); //生成sql语句 String sqlGetTotalPages = "select count(*) from alldata"; //获取总记录条数 totalStmt = totalConn.createStatement(); totalRs = totalStmt.executeQuery(sqlGetTotalPages); totalRs.next(); int countResult = totalRs.getInt(1); //取得总页数 totalPages = countResult % pageSize == 0 ? countResult / pageSize : (int)(countResult / pageSize) + 1; } catch (SQLException e) { System.out.println("历史记录查询出错,操作未完成!"); e.printStackTrace(); } finally { DBUtil.close(totalRs); DBUtil.close(totalStmt); DBUtil.close(totalConn); } /* 如果页数大于总页数,则默认显示最后一页 */ if (pageNo > totalPages) { pageNo = totalPages; } /* 获取数据库中当前页内要显示的观测记录,使用一个List来盛装记录 */ List<Record> records = new ArrayList<Record>(); Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; int startIndex = (pageNo - 1) * pageSize + 1; int endIndex = pageNo * pageSize; try { conn = DBUtil.getConnection(); String sql = "select * from (select row_number() over(order by data_taizhan_num, data_date asc) as 'num', * from alldata) as temp where num between " + startIndex + " and " + endIndex; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while (rs.next()) { //取出每条记录的数据,并将其封装成Record对象 Record r = new Record(); r.setTaizhan_num(rs.getString(2)); r.setDate(rs.getTimestamp(3)); r.setTem(rs.getString(4)); r.setHum(rs.getString(5)); r.setPa(rs.getString(6)); r.setRain(rs.getString(7)); r.setWin_dir(rs.getString(8)); r.setWin_sp(rs.getString(9)); records.add(r); //将封装好的Record对象放入列表容器中 } } catch (SQLException e) { System.out.println("查询出错,操作未完成!"); e.printStackTrace(); } finally { DBUtil.close(rs); DBUtil.close(pstmt); DBUtil.close(conn); } System.out.println(totalPages); System.out.println(pageNo); /* ========================================数据库连接结束====================================== */ %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang="zh-CN"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <%-- 在IE运行最新的渲染模式 --%> <meta name="viewport" content="width=device-width, initial-scale=1"> <%-- 初始化移动浏览显示 --%> <meta name="Author" content="Dreamer-1."> <link rel="stylesheet" href="css/bootstrap.css"> <link rel="stylesheet" href="css/recordSearchResult.css"> <script type="text/javascript" src="js/jquery-1.12.3.min.js"></script> <script type="text/javascript" src="js/bootstrap.min.js"></script> <script type="text/javascript" src="js/bootstrap-paginator.min.js"></script> <title>- 搜索记录 -</title> </head> <body> <div class="container"> <div class="wrapper"> <!-- 使用表单展示数据记录 --> <form class="form-area"> <table class="table table-striped table-hover" > <% if (records == null || records.size() == 0) { out.println("<tr><td><h4><strong>没有符合要求的记录呢,不如换个搜索条件试试吧~</strong></h4></td></tr>"); } else { %> <tr> <td><h4><strong>观测台站</strong></h4></td> <% Record r = records.get(0); if (r.getTem() != null) { out.println("<td><h4><strong>温度(℃)</strong></h4></td>"); } if (r.getHum() != null) { out.println("<td><h4><strong>湿度(%)</strong></h4></td>"); } if (r.getPa() != null) { out.println("<td><h4><strong>压强(hPa)</strong></h4></td>"); } if (r.getRain() != null) { out.println("<td><h4><strong>雨量(mm)</strong></h4></td>"); } if (r.getWin_dir() != null) { out.println("<td><h4><strong>风向(°)</strong></h4></td>"); } if (r.getWin_sp() != null) { out.println("<td><h4><strong>风速(m/s)</strong></h4></td>"); } %> <td><h4><strong>观测时间</strong></h4></td> </tr> <% } %> <% if (records != null && records.size() != 0) { for (Record r : records) { %> <tr> <td><%= r.getTaizhan_num() %></td> <% if (r.getTem() != null) { out.println("<td>" + r.getTem() + "</td>"); } if (r.getHum() != null) { out.println("<td>"+ r.getHum() +"</td>"); } if (r.getPa() != null) { out.println("<td>" + r.getPa() + "</td>"); } if (r.getRain() != null) { out.println("<td>" + r.getRain() + "</td>"); } if (r.getWin_dir() != null) { out.println("<td>" + r.getWin_dir() + "</td>"); } if (r.getWin_sp() != null) { out.println("<td>" + r.getWin_sp() + "</td>"); } %> <td><%= r.getDate() %></td> </tr> <% } %> </table> <!-- 分页显示div --> <div align="center"> <ul class="pagination" id="paginator"></ul> </div> </form> <% } %> </div> </div> <script type='text/javascript'> var options = { bootstrapMajorVersion: 3, //bootstrap版本 size: 'normal', itemTexts: function (type, page, current) { switch (type) { case "first": return "首页"; case "prev": return "<i class='fa fa-caret-left'></i> 上一页"; case "next": return "下一页 <i class='fa fa-caret-right'></i>"; case "last": return "末页"; case "page": return page; } }, tooltipTitles: function (type, page, current) { switch (type) { case "first": return "首页"; case "prev": return "上一页"; case "next": return "下一页"; case "last": return "末页"; case "page": return "第" + page + "页"; } }, pageUrl: function(type, page, current){ return "showInfoSearchResult.jsp?pageNoStr="+page; //跳转到选定页面 }, numberOfPages: 6, //显示“第几页”的选项数目 currentPage: <%= pageNo %>, //当前页数 totalPages: <%= totalPages %> //总页数 } $('#paginator').bootstrapPaginator(options); </script> </body> </html>
三:
关于本例中用到的Record、DBUtil类:
Record类是一个用于封装数据的,对外仅提供get/set方法的普通Java类,其属性与数据库表中包含的字段一一对应,代码如下:
package PaginationExample; import java.sql.*; /** * 封装气象数据信息 * @author zhong * */ public class Record { private String taizhan_num; //台站名 private String tem; //温度 private String hum; //湿度 private String pa; //压强 private String rain; //雨量 private String win_dir; //风向 private String win_sp; //风速 private Timestamp date; //观测日期(原始格式) /** * 获取产生该观测记录的台站名称; * @return 台站名称 */ public String getTaizhan_num() { return taizhan_num; } /** * 设置产生该观测记录的台站名称; * @param taizhan_num 待设置台站名称 */ public void setTaizhan_num(String taizhan_num) { this.taizhan_num = taizhan_num; } /** * 获取温度; * @return 温度值 */ public String getTem() { return tem; } /** * 设置温度; * @param tem 待设置温度值 */ public void setTem(String tem) { this.tem = tem; } /** * 获取湿度; * @return 湿度值 */ public String getHum() { return hum; } /** * 设置湿度; * @param hum 待设置湿度值 */ public void setHum(String hum) { this.hum = hum; } /** * 获取压强; * @return 压强值 */ public String getPa() { return pa; } /** * 设置压强; * @param pa 待设置压强值 */ public void setPa(String pa) { this.pa = pa; } /** * 获取雨量; * @return 雨量值 */ public String getRain() { return rain; } /** * 设置雨量; * @param rain 待设置雨量值 */ public void setRain(String rain) { this.rain = rain; } /** * 获取风向; * @return 风向值 */ public String getWin_dir() { return win_dir; } /** * 设置风向; * @param win_dir 待设置风向值 */ public void setWin_dir(String win_dir) { this.win_dir = win_dir; } /** * 获取风速; * @return 风速值 */ public String getWin_sp() { return win_sp; } /** * 设置风向; * @param win_sp 待设置风向值 */ public void setWin_sp(String win_sp) { this.win_sp = win_sp; } /** * 获取观测日期; * @return 观测日期 */ public Timestamp getDate() { return date; } /** * 设置观测日期; * @param date 观测日期值 */ public void setDate(Timestamp date) { this.date = date; } }
对应的alldata表部分数据截图:
DBUtil类是一个数据库工具类,统一对外提供与数据库相关的Connection、Statement等,代码如下:
package PaginationExample; import java.sql.*; import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.PoolProperties; /** * 数据库工具类(采用了tomcat jdbc pool) * @author zhong * */ public class DBUtil { private static DataSource ds; static { //配置tomcat jdbc pool (连接池) PoolProperties p = new PoolProperties(); p.setUrl("jdbc:sqlserver://localhost:1433; DatabaseName=weather"); //设置连接的url p.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //载入数据库驱动 p.setUsername("sa"); //用于远程连接的用户名 p.setPassword("2003NianDeDiYiChangXue"); //密码 p.setJmxEnabled(true); p.setTestWhileIdle(false); p.setTestOnBorrow(true); p.setValidationQuery("SELECT 1"); p.setTestOnReturn(false); p.setValidationInterval(30000); p.setTimeBetweenEvictionRunsMillis(30000); p.setMaxActive(100); p.setInitialSize(10); p.setMaxWait(10000); p.setRemoveAbandonedTimeout(60); p.setMinEvictableIdleTimeMillis(30000); p.setMinIdle(10); p.setLogAbandoned(true); p.setRemoveAbandoned(true); p.setJdbcInterceptors( "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+ "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"); ds = new DataSource(); ds.setPoolProperties(p); } private DBUtil() {} /** * 获取一个数据库连接(Connection); * @return Database Connection */ public static Connection getConnection() { Connection conn = null; try { conn = ds.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return conn; } /** * 关闭传入的Connection; * @param conn 待关闭的Connection */ public static void close(Connection conn) { try { if (conn != null) { conn.close(); conn = null; } } catch (SQLException e) { e.printStackTrace(); } } /** * 关闭传入的Statement; * @param stmt 待关闭的Statement */ public static void close(Statement stmt) { try { if (stmt != null) { stmt.close(); stmt = null; } } catch (SQLException e) { e.printStackTrace(); } } /** * 关闭传入的ResultSet; * @param rs 待关闭的ResultSet */ public static void close(ResultSet rs) { try { if (rs != null) { rs.close(); rs = null; } } catch (SQLException e) { e.printStackTrace(); } } }
四:
补充说明:
①:SQLServer(2008及以下版本)实现分页时需借助ROW_NUMBER()函数,以生成一个单独记录了行号的列,方便后面分页时取出对应行号区间段的记录。例:
select * from alldata 执行效果:
select row_number() over(order by data_taizhan_num, data_date asc) as 'num', * from alldata 执行效果:
看到了吧,最前面多了一列存储了行号的字段名为num的列;
(如果表内主键id是自动递增的数字的话,也可以直接用id来分段取出记录,但前提是id必须连续且自动递增)
关于更多ROW_NUMBER()函数实现分页的信息请参考:http://www.cnblogs.com/ajun/archive/2012/12/12/2814780.html
②:MySQL分页实现起来简单很多,直接使用limit关键字即可。例:
select * from table1 order by id asc limit 3, 2 意即将表table1中的数据按id值排序(升序)后,从第三行开始,取后面的两行记录(即第四、五行记录)
③:关于bootstrap-paginator的具体使用方法可以参考官方的文档(位于解压后的document文件夹内),官方文档写得很棒,简单易懂。
在使用时要注意对于bootstrap V3版本来说,要使用<ul>标签来显示bootstrap-paginator,并在配置项里注明所用bootstrap的版本(参考我jsp示例页面的写法)。
(bootstrap V2版本直接使用示例文档中的<div>标签即可)
④:分页常用公式:设要显示的页数为 n ,每页显示 m 条数据,则(数据库中)待取数据的开始位置(即jsp示例中的startIndex)为: (n-1)*m+1,终止位置(endIndex)为:n*m
⑤:源码下载:https://files.cnblogs.com/files/Dreamer-1/PaginationExample.rar