1. 程式人生 > >JSP分頁技術實現

JSP分頁技術實現

                     目前比較廣泛使用的分頁方式是將查詢結果快取在HttpSession或有狀態bean中,翻頁的時候從快取中取出一頁資料顯示。這種方法有兩個主要的缺點:一是使用者可能看到的是過期資料;二是如果資料量非常大時第一次查詢遍歷結果集會耗費很長時間,並且快取的資料也會佔用大量記憶體,效率明顯下降。  其它常見的方法還有每次翻頁都查詢一次資料庫,從ResultSet中只取出一頁資料(使用rs.last();rs.getRow()獲得總計錄條數,使用rs.absolute()定位到本頁起始記錄)。這種方式在某些資料庫(如oracle)的JDBC實現中差不多也是需要遍歷所有記錄,實驗證明在記錄數很大時速度非常慢。  至於快取結果集ResultSet的方法則完全是一種錯誤的做法。因為ResultSet在Statement或Connection關閉時也會被關閉,如果要使ResultSet有效勢必長時間佔用資料庫連線。  因此比較好的分頁做法應該是每次翻頁的時候只從資料庫裡檢索頁面大小的塊區的資料。這樣雖然每次翻頁都需要查詢資料庫,但查詢出的記錄數很少,網路傳輸資料量不大,如果使用連線池更可以略過最耗時的建立資料庫連線過程。而在資料庫端有各種成熟的優化技術用於提高查詢速度,比在應用伺服器層做快取有效多了。  在oracle資料庫中查詢結果的行號使用偽列ROWNUM表示(從1開始)。例如select * from employee where rownum<10 返回前10條記錄。但因為rownum是在查詢之後排序之前賦值的,所以查詢employee按birthday排序的第100到120條記錄應該這麼寫:
  mySQL可以使用LIMIT子句:    select name, birthday from employee order by birthday LIMIT 99,20  DB2有rownumber()函式用於獲取當前行數。  SQL Server沒研究過,可以參考這篇文章:http://www.csdn.net/develop/article/18/18627.shtm  在Web程式中分頁會被頻繁使用,但分頁的實現細節卻是程式設計過程中比較麻煩的事情。大多分頁顯示的查詢操作都同時需要處理複雜的多重查詢條件,sql語句需要動態拼接組成,再加上分頁需要的記錄定位、總記錄條數查詢以及查詢結果的遍歷、封裝和顯示,程式會變得很複雜並且難以理解。因此需要一些工具類簡化分頁程式碼,使程式設計師專注於業務邏輯部分。下面是我設計的兩個工具類:  PagedStatement
  封裝了資料庫連線、總記錄數查詢、分頁查詢、結果資料封裝和關閉資料庫連線等操作,並使用了PreparedStatement支援動態設定引數。  RowSetPage  參考PetStore的page by page iterator模式, 設計RowSetPage用於封裝查詢結果(使用OracleCachedRowSet快取查詢出的一頁資料,關於使用CachedRowSet封裝資料庫查詢結果請參考
JSP頁面查詢顯示常用模式)以及當前頁碼、總記錄條數、當前記錄數等資訊, 並且可以生成簡單的HTML分頁程式碼。  PagedStatement 查詢的結果封裝成RowsetPage。  下面是簡單的使用示例
  1.     //DAO查詢資料部分程式碼:
  2.     …
  3.     public RowSetPage getEmployee( gender, int pageNo) throws {
  4.          sql="select emp_id, emp_code,  user_name, real_name from employee where gender =?";
  5.        //使用Oracle資料庫的分頁查詢實現,每頁顯示5條
  6.         PagedStatement pst =new PagedStatementOracleImpl(sql,  pageNo, 5);
  7.         pst.setString(1, gender);
  8.         return pst.executeQuery();
  9.     }
  10.     //Servlet處理查詢請求部分程式碼:
  11.     …
  12.     int pageNo;
  13.     try{
  14.         //可以通過引數pageno獲得使用者選擇的頁碼
  15.         pageNo = .parseInt(request.getParameter("pageno") );
  16.         //預設為第一頁
  17.         pageNo=1;
  18.     }
  19.      gender = request.getParameter("gender" );
  20.     request.setAttribute("empPage", myBean.getEmployee(gender, pageNo) );
  21.     …
  22.     //JSP顯示部分程式碼
  23. <%@ page import = "page.RowSetPage"%>
  24.     …
  25.     <script language="javascript">
  26.         function doQuery(){
  27.             form1.actionType.value="doQuery";
  28.             form1.submit();
  29.     }
  30.     </script>
  31.     …
  32.     <form name=form1 method=get>
  33.       <input type=hidden name=actionType>
  34.       性別:
  35.       <input type=text name=gender size=1 value="<%=request.getParameter("gender")%>">
  36.       <input type=button value=" 查詢 " onclick="doQuery()">
  37. <%
  38.     RowSetPage empPage = (RowSetPage)request.getAttribute("empPage");
  39.     if (empPage == null ) empPage = RowSetPage.EMPTY_PAGE;
  40. %>
  41.     …
  42.     <table  cellspacing="0" width="90%">
  43.         <tr> <td>ID</td> <td>程式碼</td> <td>使用者名稱</td> <td>姓名</td>  </tr>
  44. <%
  45.     javax.sql. empRS = (javax.sql.) empPage.getRowSet();
  46.     if (empRS!=nullwhile (empRS.next() ) {
  47. %>
  48.         <tr>  
  49.             <td><%= empRS.getString("EMP_ID")%></td> 
  50.             <td><%= empRS.getString("EMP_CODE")%></td>  
  51.             <td><%= empRS.getString("USER_NAME")%></td> 
  52.             <td><%= empRS.getString("REAL_NAME")%></td>  
  53.         </tr>
  54. <%
  55.     }// end while
  56. %>
  57.         <tr>
  58. <%
  59.     //顯示總頁數和當前頁數(pageno)以及分頁程式碼。
  60.     //此處doQuery為頁面上提交查詢動作的javascript函式名, pageno為標識當前頁碼的引數名
  61. %>
  62.             <td colspan=4><%= empPage .getHTML("doQuery", "pageno")%></td>
  63.         </tr>
  64.     </table>
  65.     </form>
  效果如圖:pagediv.jpg  因為分頁顯示一般都會伴有查詢條件和查詢動作,頁面應已經有校驗查詢條件和提交查詢的javascript方法(如上面的doQuery),所以RowSetPage.getHTML()生成的分頁程式碼在使用者選擇新頁碼時直接回調前面的處理提交查詢的javascript方法。注意在顯示查詢結果的時候上次的查詢條件也需要保持,如<input type=text name=gender size=1 value="<%=request.getParameter("gender")%>">。同時由於頁碼的引數名可以指定,因此也支援在同一頁面中有多個分頁區。  另一種分頁程式碼實現是生成每一頁的URL,將查詢引數和頁碼作為QueryString附在URL後面。這種方法的缺陷是在查詢條件比較複雜時難以處理,並且需要指定處理查詢動作的servlet,可能不適合某些定製的查詢操作。  如果對RowSetPage.getHTML()生成的預設分頁程式碼不滿意可以編寫自己的分頁處理程式碼,RowSetPage提供了很多getter方法用於獲取相關資訊(如當前頁碼、總頁數、 總記錄數和當前記錄數等)。  在實際應用中可以將分頁查詢和顯示做成jsp taglib, 進一步簡化JSP程式碼,遮蔽Java Code。附:分頁工具類的原始碼, 有註釋,應該很容易理解。1.Page.java2.RowSetPage.java(RowSetPage繼承Page)3.PagedStatement.java4.PagedStatementOracleImpl.java(PagedStatementOracleImpl繼承PagedStatement)您可以任意使用這些原始碼,但必須保留author [email protected]字樣
  1. ///////////////////////////////////
  2. //
  3. //  Page.java
  4. //  author: [email protected]
  5. //
  6. ///////////////////////////////////
  7. package page;
  8. import java.util.List;
  9. import java.util.;
  10. import java.util.;
  11. import java.util.;
  12. /**
  13.  * Title: 分頁物件<br>
  14.  * Description:  用於包含資料及分頁資訊的物件<br>
  15.  *               Page類實現了用於顯示分頁資訊的基本方法,但未指定所含資料的型別,
  16.  *               可根據需要實現以特定方式組織資料的子類,<br>
  17.  *               如RowSetPage以RowSet封裝資料,ListPage以List封裝資料<br>
  18.  * Copyright:    Copyright (c) 2002 <br>
  19.  * @author [email protected] <br>
  20.  * @version 1.0
  21.  */
  22. public  class Page implements java.io. {
  23.     public static final Page EMPTY_PAGE = new Page();
  24.     public static final int  DEFAULT_PAGE_SIZE = 20;
  25.     public static final  int MAX_PAGE_SIZE = 9999;
  26.     private int myPageSize = DEFAULT_PAGE_SIZE;
  27.     private int start;
  28.     private int avaCount,totalSize;
  29.     private  data;
  30.     private int currentPageno;
  31.     private int totalPageCount;
  32.     /**
  33.      * 預設構造方法,只構造空頁
  34.      */
  35.     protected Page(){
  36.         this.init(0,0,0,DEFAULT_PAGE_SIZE,new ());
  37.     }
  38.     /**
  39.      * 分頁資料初始方法,由子類呼叫
  40.      * @param start 本頁資料在資料庫中的起始位置
  41.      * @param avaCount 本頁包含的資料條數
  42.      * @param totalSize 資料庫中總記錄條數
  43.      * @param pageSize 本頁容量
  44.      * @param data 本頁包含的資料
  45.      */
  46.     protected void init(int start, int avaCount, int totalSize, int pageSize,  data){
  47.         this.avaCount =avaCount;
  48.         this.myPageSize = pageSize;
  49.         this.start = start;
  50.         this.totalSize = totalSize;
  51.         this.data=data;
  52.         //System.out.println("avaCount:"+avaCount);
  53.         //System.out.println("totalSize:"+totalSize);
  54.         if (avaCount>totalSize) {
  55.             //throw new RuntimeException("記錄條數大於總條數?!");
  56.         }
  57.         this.currentPageno = (start -1)/pageSize +1;
  58.         this.totalPageCount = (totalSize + pageSize -1) / pageSize;
  59.         if (totalSize==0 && avaCount==0){
  60.             this.currentPageno = 1;
  61.             this.totalPageCount = 1;
  62.         }
  63.         //System.out.println("Start Index to Page No: " + start + "-" + currentPageno);
  64.     }
  65.     public   getData(){
  66.         return this.data;
  67.     }
  68.     /**
  69.      * 取本頁資料容量(本頁能包含的記錄數)
  70.      * @return 本頁能包含的記錄數
  71.      */
  72.     public int getPageSize(){
  73.         return this.myPageSize;
  74.     }
  75.     /**
  76.      * 是否有下一頁
  77.      * @return 是否有下一頁
  78.      */
  79.     public boolean hasNextPage() {
  80.       /*
  81.         if (avaCount==0 && totalSize==0){
  82.             return false;
  83.         }
  84.         return (start + avaCount -1) < totalSize;
  85.        */
  86.       return (this.getCurrentPageNo()<this.getTotalPageCount());
  87.     }
  88.     /**
  89.      * 是否有上一頁
  90.      * @return  是否有上一頁
  91.      */
  92.     public boolean hasPreviousPage() {
  93.       /*
  94.         return start > 1;
  95.        */
  96.       return (this.getCurrentPageNo()>1);
  97.     }
  98.     /**
  99.      * 獲取當前頁第一條資料在資料庫中的位置
  100.      * @return
  101.      */
  102.     public int getStart(){
  103.         return start;
  104.     }
  105.     /**
  106.      * 獲取當前頁最後一條資料在資料庫中的位置
  107.      * @return
  108.      */
  109.     public int getEnd(){
  110.         int end = this.getStart() + this.getSize() -1;
  111.         if (end<0) {
  112.             end = 0;
  113.         }
  114.         return end;
  115.     }
  116.     /**
  117.      * 獲取上一頁第一條資料在資料庫中的位置
  118.      * @return 記錄對應的rownum
  119.      */
  120.     public int getStartOfPreviousPage() {
  121.         return Math.max(start-myPageSize, 1);
  122.     }
  123.     /**
  124.      * 獲取下一頁第一條資料在資料庫中的位置
  125.      * @return 記錄對應的rownum
  126.      */
  127.     public int getStartOfNextPage() {
  128.         return start + avaCount;
  129.     }
  130.     /**
  131.      * 獲取任一頁第一條資料在資料庫中的位置,每頁條數使用預設值
  132.      * @param pageNo 頁號
  133.      * @return 記錄對應的rownum
  134.      */
  135.     public static int getStartOfAnyPage(int pageNo){
  136.         return getStartOfAnyPage(pageNo, DEFAULT_PAGE_SIZE);
  137.     }
  138.     /**
  139.      * 獲取任一頁第一條資料在資料庫中的位置
  140.      * @param pageNo 頁號
  141.      * @param pageSize 每頁包含的記錄數
  142.      * @return 記錄對應的rownum
  143.      */
  144.     public static int getStartOfAnyPage(int pageNo, int pageSize){
  145.         int startIndex = (pageNo-1) * pageSize + 1;
  146.         if ( startIndex < 1) startIndex = 1;
  147.         //System.out.println("Page No to Start Index: " + pageNo + "-" + startIndex);
  148.         return startIndex;
  149.     }
  150.     /**
  151.      * 取本頁包含的記錄數
  152.      * @return 本頁包含的記錄數
  153.      */
  154.     public int getSize() {
  155.         return avaCount;
  156.     }
  157.     /**
  158.      * 取資料庫中包含的總記錄數
  159.      * @return 資料庫中包含的總記錄數
  160.      */
  161.     public int getTotalSize() {
  162.         return this.totalSize;
  163.     }
  164.     /**
  165.      * 取當前頁碼
  166.      * @return 當前頁碼
  167.      */
  168.     public int getCurrentPageNo(){
  169.         return  this.currentPageno;
  170.     }
  171.     /**
  172.      * 取總頁碼
  173.      * @return 總頁碼
  174.      */
  175.     public int getTotalPageCount(){
  176.         return this.totalPageCount;
  177.     }
  178.     /**
  179.      *
  180.      * @param queryJSFunctionName 實現分頁的JS指令碼名字,頁碼變動時會自動回撥該方法
  181.      * @param pageNoParamName 頁碼引數名稱
  182.      * @return
  183.      */
  184.     public  getHTML( queryJSFunctionName,  pageNoParamName){
  185.         if (getTotalPageCount()<1){
  186.             return "<input type='hidden' name='"+pageNoParamName+"' value='1' >";
  187.         }
  188.         if (queryJSFunctionName == null || queryJSFunctionName.trim().length()<1) {
  189.             queryJSFunctionName = "gotoPage";
  190.         }
  191.         if (pageNoParamName == null || pageNoParamName.trim().length()<1){
  192.             pageNoParamName = "pageno";
  193.         }
  194.          gotoPage = "_"+queryJSFunctionName;
  195.         html.append("<script language=/"Javascript1.2/">/n")
  196.              .append("function ").append(gotoPage).append("(pageNo){  /n")
  197.              .append(  "   var curPage=1;  /n")
  198.              .append(  "   try{ curPage = document.all[/"")
  199.              .append(pageNoParamName).append("/"].value;  /n")
  200.              .append(  "        document.all[/"").append(pageNoParamName)
  201.              .append("/"].value = pageNo;  /n")
  202.              .append(  "        ").append(queryJSFunctionName).append("(pageNo); /n")
  203.              .append(  "        return true;  /n")
  204.              .append(  "   }catch(e){ /n")
  205. //             .append(  "      try{ /n")
  206. //             .append(  "           document.forms[0].submit();  /n")
  207. //             .append(  "      }catch(e){   /n")
  208.              .append(  "          alert('尚未定義查詢方法:function ")
  209.              .append(queryJSFunctionName).append("()'); /n")
  210.              .append(  "          document.all[/"").append(pageNoParamName)
  211.              .append("/"].value = curPage;  /n")
  212.              .append(  "          return false;  /n")
  213. //             .append(  "      }  /n")
  214.              .append(  "   }  /n")
  215.              .append(  "}")
  216.              .append(  "</script>  /n")
  217.              .append(  "");
  218.         html.append( "<table  border=0 cellspacing=0 cellpadding=0 align=center width=80%>  /n")
  219.              .append( "  <tr>  /n")
  220.              .append( "    <td align=left><br>  /n");
  221.         html.append(  "       共" ).append( getTotalPageCount() ).append( "頁")
  222.              .append(  "       [") .append(getStart()).append("..").append(getEnd())
  223.              .append("/").append(this.getTotalSize()).append("]  /n")
  224.              .append( "    </td>  /n")
  225.              .append( "    <td align=right>  /n");
  226.         if (hasPreviousPage()){
  227.              html.append( "[<a href='javascript:").append(gotoPage)
  228.              .append("(") .append(getCurrentPageNo()-1) 
  229.              .append( ")'>上一頁</a>]   /n");
  230.         }
  231.         html.append(  "       第")
  232.              .append(   "        <select name='")
  233.              .append(pageNoParamName).append("' onChange='javascript:")
  234.              .append(gotoPage).append("(this.value)'>/n");
  235.          selected = "selected";
  236.         for(int i=1;i<=getTotalPageCount();i++){
  237.             if( i == getCurrentPageNo() )
  238.                  selected = "selected";
  239.             else selected = "";
  240.             html.append( "      <option value='").append(i).append("' ")
  241.               .append(selected).append(">").append(i).append("</option>  /n");
  242.         }
  243.         if (getCurrentPageNo()>getTotalPageCount()){
  244.             html.append( "      <option value='").append(getCurrentPageNo())
  245.             .append("' selected>").append(getCurrentPageNo())
  246.             .append("</option>  /n");
  247.         }
  248.         html.append( "    </select>頁  /n");
  249.         if (hasNextPage()){
  250.              html.append( "    [<a href='javascript:").append(gotoPage)
  251.                .append("(").append((getCurrentPageNo()+1)) 
  252.                .append( ")'>下一頁</a>]   /n");
  253.         }
  254.         html.append( "</td></tr></table>  /n");
  255.         return html.toString();
  256.     }
  257. }
  258. ///////////////////////////////////
  259. //
  260. //  RowSetPage.java
  261. //  author: [email protected]
  262. //
  263. ///////////////////////////////////
  264. package page;
  265. import javax.sql.;
  266. /**
  267.  * <p>Title: RowSetPage</p>
  268.  * <p>Description: 使用RowSet封裝資料的分頁物件</p>
  269.  * <p>Copyright: Copyright (c) 2003</p>
  270.  * @author [email protected]
  271.  * @version 1.0
  272.  */
  273. public class RowSetPage extends Page {
  274.     private javax.sql. rs;
  275.     /**
  276.      *空頁
  277.      */
  278.     public static final RowSetPage EMPTY_PAGE = new RowSetPage();
  279.     /**
  280.      *預設構造方法,建立空頁
  281.      */
  282.     public RowSetPage(){
  283.       this(null, 0,0);
  284.     }
  285.     /**
  286.      *構造分頁物件
  287.      *@param crs 包含一頁資料的OracleCachedRowSet
  288.      *@param start 該頁資料在資料庫中的起始位置
  289.      *@param totalSize 資料庫中包含的記錄總數
  290.      */
  291.     public RowSetPage( crs, int start, int totalSize) {
  292.         this(crs,start,totalSize,Page.DEFAULT_PAGE_SIZE);
  293.     }
  294.     /**
  295.      *構造分頁物件
  296.      *@param crs 包含一頁資料的OracleCachedRowSet
  297.      *@param start 該頁資料在資料庫中的起始位置
  298.      *@param totalSize 資料庫中包含的記錄總數
  299.      *@pageSize 本頁能容納的記錄數
  300.      */
  301.     public RowSetPage( crs, int start, int totalSize, int pageSize) {
  302.         try{
  303.             int avaCount=0;
  304.             if (crs!=null) {
  305.                 crs.beforeFirst();
  306.                 if (crs.next()){
  307.                     crs.last();
  308.                     avaCount = crs.getRow();
  309.                 }
  310.                 crs.beforeFirst();
  311.             }
  312.             rs = crs;
  313.             super.init(start,avaCount,totalSize,pageSize,rs);
  314.         }catch(java.sql. sqle){
  315.             throw new (sqle.toString());
  316.         }
  317.     }
  318.     /**
  319.      *取分頁物件中的記錄資料
  320.      */
  321.     public javax.sql. getRowSet(){
  322.         return rs;
  323.     }
  324. }
  325. ///////////////////////////////////
  326. //
  327. //  PagedStatement.java
  328. //  author: [email protected]
  329. //
  330. ///////////////////////////////////
  331. package page;
  332. import foo.DBUtil;
  333. import java.math.;
  334. import java.util.List;
  335. import java.util.;
  336. import java.util.;
  337. import java.sql.;
  338. import java.sql.;
  339. import java.sql.;
  340. import java.sql.;
  341. import javax.sql.;
  342. /**
  343.  * <p>Title: 分頁查詢</p>
  344.  * <p>Description: 根據查詢語句和頁碼查詢出當頁資料</p>
  345.  * <p>Copyright: Copyright (c) 2002</p>
  346.  * @author [email protected]
  347.  * @version 1.0
  348.  */
  349. public abstract class PagedStatement {
  350.     public final static int MAX_PAGE_SIZE = Page.MAX_PAGE_SIZE;
  351.     protected  countSQL, querySQL;
  352.     protected int pageNo,pageSize,startIndex,totalCount;
  353.     protected javax.sql. rowSet;
  354.     protected RowSetPage rowSetPage;
  355.     private List boundParams;
  356.     /**
  357.      * 構造一查詢出所有資料的PageStatement
  358.      * @param sql  query sql
  359.      */
  360.     public PagedStatement( sql){
  361.         this(sql,1,MAX_PAGE_SIZE);
  362.     }
  363.     /**
  364.      * 構造一查詢出當頁資料的PageStatement
  365.      * @param sql  query sql
  366.      * @param pageNo  頁碼
  367.      */
  368.     public PagedStatement( sql, int pageNo){
  369.         this(sql, pageNo, Page.DEFAULT_PAGE_SIZE);
  370.     }
  371.     /**
  372.      * 構造一查詢出當頁資料的PageStatement,並指定每頁顯示記錄條數
  373.      * @param sql query sql
  374.      * @param pageNo 頁碼
  375.      * @param pageSize 每頁容量
  376.      */
  377.     public PagedStatement( sql, int pageNo, int pageSize){
  378.         this.pageNo = pageNo;
  379.         this.pageSize = pageSize;
  380.         this.startIndex = Page.getStartOfAnyPage(pageNo, pageSize);
  381.         this.boundParams = .synchronizedList(new java.util.());
  382.         this.countSQL = "select count(*) from ( " + sql +") ";
  383.         this.querySQL = intiQuerySQL(sql, this.startIndex, pageSize);
  384.     }
  385.     /**
  386.      *生成查詢一頁資料的sql語句
  387.      *@param sql 原查詢語句
  388.      *@startIndex 開始記錄位置
  389.      *@size 需要獲取的記錄數
  390.      */
  391.     protected abstract   intiQuerySQL( sql, int startIndex, int size);
  392.     /**
  393.      *使用給出的物件設定指定引數的值
  394.      *@param index 第一個引數為1,第二個為2,。。。
  395.      *@param obj 包含引數值的物件
  396.      */
  397.     public void setObject(int index,  obj) throws {
  398.         BoundParam bp = new BoundParam(index, obj);
  399.         boundParams.remove(bp);
  400.         boundParams.add( bp);
  401.     }
  402.     /**
  403.      *使用給出的物件設定指定引數的值
  404.      *@param index 第一個引數為1,第二個為2,。。。
  405.      *@param obj 包含引數值的物件
  406.      *@param targetSqlType 引數的資料庫型別
  407.      */
  408.     public void setObject(int index,  obj, int targetSqlType) throws {
  409.         BoundParam bp = new BoundParam(index, obj, targetSqlType);
  410.         boundParams.remove(bp);
  411.         boundParams.add(bp );
  412.     }
  413.     /**
  414.      *使用給出的物件設定指定引數的值
  415.      *@param index 第一個引數為1,第二個為2,。。。
  416.      *@param obj 包含引數值的物件
  417.      *@param targetSqlType 引數的資料庫型別(常量定義在java.sql.Types中)
  418.      *@param scale 精度,小數點後的位數
  419.      * (只對targetSqlType是Types.NUMBER或Types.DECIMAL有效,其它型別則忽略)
  420.      */
  421.     public void setObject(int index,  obj, int targetSqlType, int scale) throws {
  422.         BoundParam bp = new BoundParam(index, obj, targetSqlType, scale) ;
  423.         boundParams.remove(bp);
  424.         boundParams.add(bp);
  425.     }
  426.     /**
  427.      *使用給出的字串設定指定引數的值
  428.      *@param index 第一個引數為1,第二個為2,。。。
  429.      *@param str 包含引數值的字串
  430.      */
  431.     public void setString(int index,  str)throws {
  432.         BoundParam bp = new BoundParam(index, str)  ;
  433.         boundParams.remove(bp);
  434.         boundParams.add(bp);
  435.     }
  436.     /**
  437.      *使用給出的字串設定指定引數的值
  438.      *@param index 第一個引數為1,第二個為2,。。。
  439.      *@param timestamp 包含引數值的時間戳
  440.      */
  441.     public void setTimestamp(int index,  timestamp)throws {
  442.         BoundParam bp = new BoundParam(index, timestamp)  ;
  443.         boundParams.remove(bp);
  444.         boundParams.add( bp );
  445.     }
  446.     /**
  447.      *使用給出的整數設定指定引數的值
  448.      *@param index 第一個引數為1,第二個為2,。。。
  449.      *@param value 包含引數值的整數
  450.      */
  451.     public void setInt(int index, int value)throws {
  452.         BoundParam bp =  new BoundParam(index, new (value))  ;
  453.         boundParams.remove(bp);
  454.         boundParams.add( bp );
  455.     }
  456.     /**
  457.      *使用給出的長整數設定指定引數的值
  458.      *@param index 第一個引數為1,第二個為2,。。。
  459.      *@param value 包含引數值的長整數
  460.      */
  461.     public void setLong(int index, long value)throws {
  462.         BoundParam bp =  new BoundParam(index, new Long(value))  ;
  463.         boundParams.remove(bp);
  464.         boundParams.add( bp );
  465.     }
  466.     /**
  467.      *使用給出的雙精度浮點數設定指定引數的值
  468.      *@param index 第一個引數為1,第二個為2,。。。
  469.      *@param value 包含引數值的雙精度浮點數
  470.      */
  471.     public void setDouble(int index, double value)throws {
  472.         BoundParam bp =  new BoundParam(index, new (value))   ;
  473.         boundParams.remove(bp);
  474.         boundParams.add( bp);
  475.     }
  476.     /**
  477.      *使用給出的BigDecimal設定指定引數的值
  478.      *@param index 第一個引數為1,第二個為2,。。。
  479.      *@param bd 包含引數值的BigDecimal
  480.      */
  481.     public void setBigDecimal(int index,  bd)throws {
  482.         BoundParam bp =   new BoundParam(index, bd )   ;
  483.         boundParams.remove(bp);
  484.         boundParams.add( bp);
  485.     }
  486.         if (pst==null || this.boundParams==null || this.boundParams.size()==0 ) return ;
  487.         BoundParam param;
  488.         for ( itr = this.boundParams.iterator();itr.hasNext();){
  489.             param = (BoundParam) itr.next();
  490.             if  (param==nullcontinue;
  491.             if (param.sqlType == java.sql.Types.OTHER){
  492.                 pst.setObject(param.index, param.value);
  493.             }else{
  494.                 pst.setObject(param.index, param.value, param.sqlType, param.scale);
  495.             }
  496.         }
  497.     }
  498.     /**
  499.      * 執行查詢取得一頁資料,執行結束後關閉資料庫連線
  500.      * @return RowSetPage
  501.      * @throws SQLException
  502.      */
  503.     public  RowSetPage executeQuery() throws {
  504.         .out.println("executeQueryUsingPreparedStatement");
  505.          conn = DBUtil.getConnection();
  506.         try{
  507.             pst = conn.prepareStatement(this.countSQL);
  508.             setParams(pst);
  509.             rs =pst.executeQuery();
  510.             if (rs.next()){
  511.                 totalCount = rs.getInt(1);
  512.             } else {
  513.                 totalCount = 0;
  514.             }
  515.             rs.close();
  516.             pst.close();
  517.             if (totalCount < 1 ) return RowSetPage.EMPTY_PAGE;
  518.             pst = conn.prepareStatement(this.querySQL);
  519.             .out.println(querySQL);
  520.             pst.setFetchSize(this.pageSize);
  521.             setParams(pst);
  522.             rs =pst.executeQuery();
  523.             //rs.setFetchSize(pageSize);
  524.             this.rowSet = populate(rs);
  525.             rs.close();
  526.             rs = null;
  527.             pst.close();
  528.             pst = null;
  529.             this.rowSetPage = new RowSetPage(this.rowSet,startIndex,totalCount,pageSize);
  530.             return this.rowSetPage;
  531.             //System.out.println("executeQuery SQLException");
  532.             sqle.printStackTrace();
  533.             throw sqle;
  534.             e.printStackTrace();
  535.         }finally{
  536.             //System.out.println("executeQuery finally");
  537.             DBUtil.close(rs, pst, conn);
  538.         }
  539.     }
  540.     /**
  541.      *將ResultSet資料填充進CachedRowSet
  542.      */
  543.     /**
  544.      *取封裝成RowSet查詢結果
  545.      *@return RowSet
  546.      */
  547.     public javax.sql. getRowSet(){
  548.         return this.rowSet;
  549.     }
  550.     /**
  551.      *取封裝成RowSetPage的查詢結果
  552.      *@return RowSetPage
  553.      */
  554.     public RowSetPage getRowSetPage() {
  555.         return this.rowSetPage;
  556.     }
  557.     /**
  558.      *關閉資料庫連線
  559.      */
  560.     public void close(){
  561.         //因為資料庫連線在查詢結束或發生異常時即關閉,此處不做任何事情
  562.         //留待擴充。
  563.     }
  564.     private class BoundParam {
  565.         int index;
  566.         int sqlType;
  567.         int scale;
  568.         public BoundParam(int index,  value) {
  569.             this(index, value, java.sql.Types.OTHER);
  570.         }
  571.         public BoundParam(int index,  value, int sqlType) {
  572.             this(index, value, sqlType, 0);
  573.         }
  574.         public BoundParam(int index,  value, int sqlType, int scale) {