分頁技術:將所有數據分段展示給用戶的技術。
分頁的意義:增加系統的複雜度,另外可以將大量的數據限制在某一個特定的範圍。
選擇分頁的標準:
首先,判斷的標準是速度,顯而易見,數據庫服務器,Web應用服務器和客戶端之間是網絡,如果網絡傳遞的數據量越少,則客戶端獲得響應的速度越快。一般來說,數據庫服務器和Web應用服務器的處理能力一般比客戶端要強很多.從這兩點來看,在客戶端分頁的方案是最不可取的。
其次,在Web服務器端分頁和在數據庫端分頁,如果選擇在Web服務器端分頁的話,大部分的被過濾掉的數據還是被傳輸到了Web應用服務器端,與其這樣還不如直接在數據庫端進行分頁。
因此比較好的分頁做法應該是每次翻頁的時候只從數據庫裏檢索頁面大小的塊區的數據。
雖然每次翻頁都需要查詢數據庫,但查詢出的記錄數很少,網絡傳輸數據量不大,如果使用連接池更可以略過最耗時的建立數據庫連接過程。而在數據庫端有各種成熟的優化技術用於提高查詢速度,比在應用服務器層做緩存有效得多。
Web服務器端分頁和在數據庫端分頁:
數據庫端分頁:通過JDBC的方式訪問數據庫,根據數據庫類型採取不同的SQL分頁語句。
對於MySql數據庫:採用limit m,n語句進行分頁,需要指定m和n的2個值
Limit後的兩個參數中,參數m是起始下標[頁碼],它從0開始;參數n是返回的記錄數。
SQL語句形式:
語句1: select * from 表名 limit m,n; --返回表中m-n行的數據 語句2: select * from 表名 limit m offset n; --從n行開始到返回表中m行的數據 假設 numberpage 表示每頁要顯示的條數,pagenumber表示頁碼: 語句3:select * from 表名 limit (pagenumber-1)*numberpage,numberpage; 語句4:select * from 表名 limit numberpage offset(pagenumber-1)*numberpage;
對於Oracle數據庫:採用rownum的方式進行分頁,rownum表示一條記錄的行號,注意Oracle獲取每一行後才賦予.因此,指定rownum區間來取得分頁數據在一層查詢語句中是無法做到的,要分頁還要進行一次查詢。
SQL形式:
select * from ( select page.*,rownum rn from (select * from 表名) page where rownum <= (?-1)*?+?) where rn > (?-1)*?; --其中page是將表中的數據查詢出來取名爲page
另外,不論使用哪種數據庫,都的想知道數據中有幾條數據,自然需要一個獲取總行的SQL:
SQL形式:
select count(*) from 表名;
首先:實現分頁的具體實現需要結合JDBC和Java代碼實現:
分頁的時,返回的參數包括查詢的結果集(List),總的頁數(pageCount)、當前第幾頁(pageNo)等等信息,所以我們封裝一個查詢結果Page類,當然還需要分頁的一個實體類,這裏我以Entity爲例,具體代碼:
Page.java: //第一種實現方式: import java.util.List; import entity.Entity; public class Page { private int pageNo;//當前頁數 private int hangCount;//每頁顯示的行數 private int sumCount;//總條數 private int sumPage;//總頁數 private List<Entity> entitys;//需要生成setXX()和getXX()方法 public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { //給當前頁賦值 if (pageNo<=1) { this.pageNo=1; }else if (pageNo>=this.sumPage) { this.pageNo=this.sumPage; }else { this.pageNo = pageNo; } } public int getHangCount() { return hangCount; } public void setHangCount(int hangCount) { this.hangCount = hangCount; } public int getSumCount() { return sumCount; } public void setSumCount(int sumCount) { this.sumCount = sumCount; if(this.sumCount%this.hangCount==0){ this.sumPage = this.sumCount/this.hangCount; } else{ this.sumPage = this.sumCount/this.hangCount+1; } } public int getSumPage() { return sumPage; } public void setSumPage(int sumPage) { this.sumPage = sumPage; } //List<Entity> entitys 生成的setXX()和getXX()方法 } //第二種實現方式: import java.util.List; import entity.Entity; public class Page { private int pageNo;//當前頁數 private int hangCount;//每頁顯示的行數 private int sumCount;//總條數 private int sumPage;//總頁數 private List<Entity> entitys;//需要生成setXX()和getXX()方法 public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } public int getHangCount() { return hangCount; } public void setHangCount(int hangCount) { this.hangCount = hangCount; } public int getSumCount() { return sumCount; } public void setSumCount(int sumCount) { this.sumCount = sumCount; setSumPage((getSumCount()%hangCount)==0?(getSumCount()/hangCount):(getTotalNum() /hangCount+1)); } public int getSumPage() { return sumPage; } public void setSumPage(int sumPage) { this.sumPage = sumPage; } // 獲取首頁 public int getFirstPage() { return 1; } // 獲取末頁 public int getLastPage() { return sumPage; } // 獲取上一頁 public int getPrePage() { if (pageNo > 1) return pageNo - 1; return 1; } // 獲取下一頁 public int getBackPage() { if (pageNo<sumPage) return pageNo + 1; return sumPage; } // 判斷'首頁'及‘上一頁’是否可用 public String isPreable() { if (pageNo == 1) return "disabled"; return ""; } // 判斷'尾頁'及‘下一頁’是否可用 public String isBackable() { if (pageNo == totalPage) return "disabled"; return ""; } //List<Entity> entitys 生成的setXX()和getXX()方法 }
其次:編寫數據數據連接類,以BaseDao爲例,具體代碼:
數據庫驅動類名:oracle.jdbc.driver.OracleDriver
數據庫連接URL:jdbc:oracle:thin:@localhost:1521:連接名
數據庫用戶名和密碼:userName,passWord
//BaseDao.java 第一種方式: import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class BaseDao{ //使用ThreadLocal是爲了保證事務的一致,使得同一個線程的所有數據庫操作使用同一個Connection private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>(); public static Connection getConnection() { Connection conn = null; conn = threadLocal.get(); if (conn == null) { try { Class.forName("數據庫驅動類名"); conn = DriverManager.getConnection( "數據庫連接URL", "用戶名","密碼"); threadLocal.set(conn); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } return conn; } // 封裝設置Connection自動提交 public static void setAutoCommit(Connection conn, Boolean flag) { try { conn.setAutoCommit(flag); } catch (SQLException e) { e.printStackTrace(); } } // 設置事務提交 public static void commit(Connection conn) { try { conn.commit(); } catch (SQLException e) { e.printStackTrace(); } } // 封裝設置Connection回滾 public static void rollBack(Connection conn) { try { conn.rollback(); } catch (SQLException e) { e.printStackTrace(); } } // 封裝關閉Connection、PreparedStatement、ResultSet的函數 public static void closeConnection() { Connection conn = threadLocal.get(); try { if (conn != null) { conn.close(); conn = null; threadLocal.remove(); } } catch (SQLException e) { e.printStackTrace(); } } //關閉PreparedStatement public static void closePreparedStatement(PreparedStatement pstmt) { try { if (pstmt != null) { pstmt.close(); pstmt = null; } } catch (SQLException e) { e.printStackTrace(); } } //關閉ResultSet public static void closeResultSet(ResultSet rs) { try { if (rs != null) { rs.close(); rs = null; } } catch (SQLException e) { e.printStackTrace(); } } //公共的增刪改方法 public int allUpdateAndAddAndDel(List<Object> list,String sql){ try { conn=getConnection(); ps=conn.prepareStatement(sql); if(list.size()>0){ for (int i = 0; i < list.size(); i++) { ps.setObject((i+1), list.get(i)); } } return ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); return -1; } finally{ closeAll(); } } //查詢公共方法 public ResultSet select(String sql,List<Object> list) { try { conn=getConnection(); ps=conn.prepareStatement(sql); if (list.size()>0) { for (int i = 0; i < list.size(); i++) { ps.setObject((i+1), list.get(i)); } } rs=ps.executeQuery(); return rs; } catch (Exception e) { e.printStackTrace(); return null; } } } 第二種方式: import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.List; public class BaseDao { private String name="用戶名"; private String pwd="密碼"; private String drivername="數據庫驅動名"; private String url="數據庫連接URL"; public Connection conn = null; public PreparedStatement ps = null; public ResultSet rs = null; /** * 關閉所有接口對象的方法 */ public void closeAll(){ try { if(rs!=null)rs.close(); if(ps!=null)ps.close(); if(conn!=null)conn.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 獲取連接對象的方法 */ public Connection getConnection(){ try { Class.forName(drivername); conn = DriverManager.getConnection(url, name, pwd); return conn; } catch (Exception e) { e.printStackTrace(); return null; } } // 封裝設置Connection自動提交 public static void setAutoCommit(Connection conn, Boolean flag) { try { conn.setAutoCommit(flag); } catch (SQLException e) { e.printStackTrace(); } } // 設置事務提交 public static void commit(Connection conn) { try { conn.commit(); } catch (SQLException e) { e.printStackTrace(); } } // 封裝設置Connection回滾 public static void rollBack(Connection conn) { try { conn.rollback(); } catch (SQLException e) { e.printStackTrace(); } } // 封裝關閉Connection、PreparedStatement、ResultSet的函數 public static void closeConnection() { Connection conn = threadLocal.get(); try { if (conn != null) { conn.close(); conn = null; threadLocal.remove(); } } catch (SQLException e) { e.printStackTrace(); } } //公共的增刪改方法 public int allUpdateAndAddAndDel(List<Object> list,String sql){ try { conn=getConnection(); ps=conn.prepareStatement(sql); if(list.size()>0){ for (int i = 0; i < list.size(); i++) { ps.setObject((i+1), list.get(i)); } } return ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); return -1; } finally{ closeAll(); } } //查詢公共方法 public ResultSet select(String sql,List<Object> list) { try { conn=getConnection(); ps=conn.prepareStatement(sql); if (list.size()>0) { for (int i = 0; i < list.size(); i++) { ps.setObject((i+1), list.get(i)); } } rs=ps.executeQuery(); return rs; } catch (Exception e) { e.printStackTrace(); return null; } } }
利用Jsp/Servlet實現:
以實體類User爲例,需要UserInfo.java:
//UserInfo.java import java.util.Date; public class UserInfo { private int id; private String username; private String password; private String truename; private String sex; private Date birthday; private String home; private String colleage; private String comingYear; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getTruename() { return truename; } public void setTruename(String truename) { this.truename = truename; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getHome() { return home; } public void setHome(String home) { this.home = home; } public String getColleage() { return colleage; } public void setColleage(String colleage) { this.colleage = colleage; } public String getCy() { return comingYear; } public void setCy(String cy) { this. comingYear= cy; } }
在dao層實現:
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import entity.UserInfo; import entity.BaseDao; public class UserInfoDao { public List<UserInfo> getUserList(UserInfo userInfo, int pageNo, int hangCount ) throws Exception { PreparedStatement pstmt = null; ResultSet rs = null; List<UserInfo> userList = null; try { String sql = "select * from(select rownum num,u.* from(select * from user_info where sex = ? and home like '" + userInfo.getHome() + "%" + "' and colleage like '" + userInfo.getColleage() + "%" + "' and comingyear like '" + userInfo.getCy() + "%" + "' order by id) u where rownum<=?) where num>=?"; userList = new ArrayList<UserInfo>(); Connection conn = BaseDao.getConnection(); pstmt = conn.prepareStatement(sql); pstmt.setString(1, userInfo.getSex()); pstmt.setInt(2, pageNo * hangCount); pstmt.setInt(3, (pageNo - 1) * hangCount + 1); rs = pstmt.executeQuery(); while (rs.next()) { UserInfo user = new UserInfo(); user.setId(rs.getInt("id")); user.setTruename(rs.getString("truename")); user.setSex(rs.getString("sex")); user.setHome(rs.getString("home")); userList.add(user); } } catch (SQLException e) { e.printStackTrace(); throw new Exception(e); } finally { BaseDao.closeResultSet(rs); BaseDao.closePreparedStatement(pstmt); } return userList; } public int getTotalNum(UserInfo userInfo) throws Exception { PreparedStatement pstmt = null; ResultSet rs = null; int count = 0; try { String sql = "select count(*) from user_info where sex=? and home like '" + userInfo.getHome() + "%" + "' and colleage like '" + userInfo.getColleage() + "%" + "' and comingyear like '" + userInfo.getCy()+ "%" + "'"; Connection conn = BaseDao.getConnection(); pstmt = conn.prepareStatement(sql); pstmt.setString(1, userInfo.getSex()); rs = pstmt.executeQuery(); if (rs.next()) { count = rs.getInt(1); } } catch (SQLException e) { e.printStackTrace(); throw new Exception(e); } finally { BaseDao.closeResultSet(rs); BaseDao.closePreparedStatement(pstmt); } return count; } }
在service層:
import java.sql.Connection; import util.BaseDao; import util.Page; public class UserInfoManage { private UserInfoDao userInfoDao = null; public UserInfoManage () { userInfoDao = new UserInfoDao(); } public Page userBasicSearch(UserInfo u, int pageNo, int hangCount) throws Exception { Connection connection = null; Page pagination = new Page(); try { connection = BaseDao.getConnection(); DBUtility.setAutoCommit(connection, false); pagination.setList(userInfoDao.getUserList(u, pageNo, hangCount)); pagination.setPageNo(pageNo); pagination.setHangCount(hangCount); pagination.setSumCount(userInfoDao.getTotalNum(u)); BaseDao.commit(connection); } catch (Exception e) { DBUtility.rollBack(connection); e.printStackTrace(); throw new Exception(); } finally { BaseDao.closeConnection(); } return pagination; } }
在Servlet:
import java.io.*; import java.util.*; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import entity.UserInfo; import service.UserInfoManage; import util.Page; public class UserBasicSearchServlet extends HttpServlet { private static final long serialVersionUID = 1L; private int hangCount = 0; @Override public void init(ServletConfig config) throws ServletException { hangCount = Integer.parseInt(config.getInitParameter("hangCount")); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1.取得頁面參數並構造參數對象 int pageNo = Integer.parseInt(req.getParameter("pageNo")); String sex = req.getParameter("gender"); String home = req.getParameter("newlocation"); String colleage = req.getParameter("colleage"); String comingyear = req.getParameter("ComingYear"); UserInfo u = new UserInfo(); u.setSex(sex); u.setHome(home); u.setColleage(colleage); u.setCy(comingyear); // 2.調用業務邏輯取得結果集 UserInfoManage userInfoManage = new UserInfoManage(); PageModel<UserInfo> pagination = userInfoManage.userBasicSearch(u, pageNo, pageSize); List<UserInfo> userList = pagination.getList(); // 3.封裝返回結果 StringBuffer resultXML = new StringBuffer(); try { resultXML.append("<?xml version='1.0' encoding='gb18030'?>/n"); resultXML.append("<root>/n"); for (Iterator<UserInfo> iterator = userList.iterator(); iterator .hasNext();) { UserInfo userInfo = iterator.next(); resultXML.append("<data>/n"); resultXML.append("/t<id>" + userInfo.getId() + "</id>/n"); resultXML.append("/t<truename>" + userInfo.getTruename() + "</ truename >/n"); resultXML.append("/t<sex>" + userInfo.getSex() + "</sex>/n"); resultXML.append("/t<home>" + userInfo.getHome() + "</home>/n"); resultXML.append("</data>/n"); } resultXML.append("<pagination>/n"); resultXML.append("/t<total>" + pagination.getTotalPage() + "</total>/n"); resultXML.append("/t<start>" + pagination.getFirstPage() + "</start>/n"); resultXML.append("/t<end>" + pagination.getLastPage() + "</end>/n"); resultXML.append("/t<pageno>" + pagination.getPageNo() + "</pageno>/n"); resultXML.append("</pagination>/n"); resultXML.append("</root>/n"); } catch (Exception e) { e.printStackTrace(); } writeResponse(req, resp, resultXML.toString()); } public void writeResponse(HttpServletRequest request, HttpServletResponse response, String result) throws IOException { response.setContentType("text/xml"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Content-Type", "text/xml; charset=gb18030"); PrintWriter pw = response.getWriter(); pw.write(result); pw.close(); } }
利用SSH實現:
在dao層編寫getSumCount()和List<Student> getStuByPage(Integer pageNo, Integer pageCount)2個方法:
有2種方法: 第一種:使用普通的分頁方法 //實現獲取總行數的方法 import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Query; private BaseUtil baseUtil;//需要生成setXX()和getXX()方法 public Integer getSumCount() { //獲取session Session session = baseUtil.getHibernateTemplate().getSessionFactory().openSession(); //執行查詢,調用查詢結果唯一的uniqueResult()方法; Object object =session.createQuery("select count(別名.id) from 類名 別名 ").uniqueResult(); //根據數據類型確定返回值,類型不對時需要強制轉換 return Integer.valueOf(object.toString()); } //實現分頁的方法 public List<Entity> getEntityByPage(Integer pageNo, Integer pageCount) { Session session = baseUtil.getHibernateTemplate().getSessionFactory().openSession(); Query query = session.createQuery("from 類名 別名 "); query.setMaxResults(pageCount); return query.setFirstResult((pageNo-1)*pageCount).list(); } 第二種:使用Spring框架提供的方法 import org.hibernate.HibernateException; import org.springframework.orm.hibernate3.HibernateCallback; import org.hibernate.Query; //實現獲取總行數的方法 public Integer getSumCount() { Object obj = baseUtil.getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session){ Query query = session.createQuery("select count(別名.id) from 類名 別名 "); Object object = query.uniqueResult(); return object; } }); return Integer.valueOf(obj.toString()); } //實現分頁的方法 getEntityByPage(final Integer pageNo, final Integer pageCount):方法內的變量必須是final public List<Entity> getEntityByPage(final Integer pageNo, final Integer pageCount) { List<Entity> entitys = baseUtil.getHibernateTemplate().executeFind(new HibernateCallback() { public Object doInHibernate(Session session){ Query query = session.createQuery("from 類名 別名"); query.setMaxResults(pageCount); query.setFirstResult((pageNo-1)*pageCount); return query.list(); } }); return entitys ; }
在service層中:
//EntityService.java private Page page;//需要生成setXX()和getXX()方法 private Integer pageNo=1; private Integer pageCount=1; public Page getEntityByPage(Integer pageNo, Integer pageCount) { if(page==null){ page=new Page(); } page.setHangCount(pageCount); page.setSumCount(stuDao.getSumCount()); page.setPageNo(pageNo); page.setEntitys(stuDao.getEntityByPage(page.getPageNo(), page.getHangCount())); return page; }
在action層中:
//EntityAction.java import service.EntityService; import util.Page; import com.opensymphony.xwork2.ActionSupport; public class EntityAction extends ActionSupport { private EntityService EntityService;//需要生成setXX()方法 private Page page;//當前頁,需要生成setXX()和getXX()方法 private Integer pageNo=1;//當前頁數,需要生成setXX()和getXX()方法 private Integer pageCount=2;//每頁顯示行數,需要生成setXX()和getXX()方法 @SuppressWarnings("unchecked") @Override public String execute() throws Exception { page=entityService.getEntityByPage(pageNo, pageCount); return SUCCESS; }
最後在jsp頁面:
<div class=pager> <ul> <li class=current><a href="form表單action名?pageNo=1">首頁</a></li> <li><a href="form表單action名?pageNo=${page.pageNo-1}">上一頁</a></li> <li><a href="form表單action名?pageNo=${page.pageNo+1}">下一頁</a></li> <li><a href="form表單action名?pageNo=${page.sumPage}">末頁</a></li> </ul> </DIV>
綜上所述,分頁功能可以基本實現。
文責聲明:本人借鑑得有別的作者的代碼,本人初探JavaWeb,技術有限,還望各位多多指正批評。如果文中有涉及之外的事情,還望見諒!