JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java 程式分享區  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to postflat modego to previous topicgo to next topic
話題被移動
該話題已被移動 - browser , 2004-08-08 11:36
如果您尚不清楚該話題被移動的原因,請參考論壇規則以及本版公告或者聯系本版版主。
本主題所含的標籤
無標籤
作者 實作資料庫記錄分頁瀏覽程式
精靈





發文: 86
積分: 7
於 2004-06-09 02:19 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
我常 release 一些 API , 但實在不知道到底有多少人去用它,可是這些 API 對我而言,都是非常實用的啊,效能問題我也都很嚴謹的測試過,這是第一次丟到網路上來,大家看看,究竟在沒有人解說的狀況下,這樣的 API 有辦法運用嗎 ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
package util;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
 
import javax.servlet.http.HttpServletRequest;
 
/**
 * 此程式用於處理分頁瀏覽功能
 * @version 1.0
 * @date 2004.04.26
 * @author jing.lin
 *
  如何使用:(請 copy 以下的程式至你的 jsp 檔中)
  // new 一個 pagelist 物件
  PageList pagelist = new PageList( request, 10 );
  // 請事先開好 DB Connection 並當作參數傳給 pagelist
  pagelist.setConnection( dbc );
  // 設定要取得第幾頁的資料
  pagelist.setCurrentPageNo();
  // 執行資料筆數的計算,請傳入計算總筆數的 SQL Statement
  String Values[] = { };
  pagelist.setPageInfo( TotalRecords_SQL_Statement, Values );
  // 執行資料取出作業
  String sOrder[] = { };
  pagelist.setPageData(
    getId_SQL_Statement,
    sOrder,
    "DESC",
    getData_SQL_Statement,
    Values );

  pagelist.getTotalRecords();
  pagelist.getTotalPages();
  pagelist.getPageRecords();
  pagelist.getCurrentPageNo();
  pagelist.getCurrentPageRecords();

  for( int j = 0;j < pagelist.getCurrentPageRecords();j++ ) {
    pagelist.get( j, "xxx" );
  }

  * 標準的上下頁 jsp code
  <table width="100%" border="0" align="center" cellpadding="0" cellspacing="0" 
    bgcolor="#FFFFFF">
    <tr>
      <td class="bk-12">
        <% if ( pagelist.getTotalRecords() > 0 ) { %>
          <% if ( pagelist.getTotalPages() > 1 ) { %>
            <% if ( pagelist.getCurrentPageNo() > 0 ) { %>
        【<a href="<%= request.getRequestURI() %>"><font color=blue>第一頁</font></a>】
        【<a href="<%= request.getRequestURI() %>?pno=<%= pagelist.getCurrentPageNo() - 1 %>">
          <font color=blue>上一頁</font></a>】
            <% } else {  %>
        【第一頁】
        【上一頁】
            <% } %>
            <% if ( pagelist.getCurrentPageNo() < ( pagelist.getTotalPages() - 1) ) { %>
        【<a href="<%= request.getRequestURI() %>?pno=<%= pagelist.getCurrentPageNo() + 1 %>">
          <font color=blue>下一頁</font></a>】
        【<a href="<%= request.getRequestURI() %>?pno=<%= pagelist.getTotalPages() - 1 %>">
          <font color=blue>最末頁</font></a>】
            <% } else {  %>
        【下一頁】
        【最末頁】
            <% } %>
          目前共有 <%= pagelist.getTotalPages() %> 頁,<%= pagelist.getTotalRecords() %> 筆,
          您現在在<SELECT NAME="pageselect" class="bk-12" 
            onChange="window.location.href=(this.options[this.selectedIndex].value)">
            <% for( int j = 0;j < pagelist.getTotalPages();j++ ) { %>
          <OPTION value="<%= request.getRequestURI() %>?pno=<%= j %>"
            <% if ( j == pagelist.getCurrentPageNo() ) out.print(" selected" ); %>>
              <%= j+1 %></option>
            <% } %>
        </SELECT> 頁。
          <% } else  { %>
        目前共有 <%= pagelist.getTotalRecords() %> 筆。
        <% } %>
      <% } else  { %>
        目前沒有記錄可供瀏覽。
      <% } %>
      </td>
    </tr>
  </table>
 */
public class PageList {
  // 總筆數
  public int _total_records = 0;
  // 總頁數
  public int _total_pages = 0;
  // 每頁的筆數
  public int _page_records = 20;
  // 目前處理的頁數
  public int _current_page = 0;
  // 目前處理的頁數有幾筆資料
  public int _current_page_record = 0;
 
  // 資料庫連結物件
  public Connection dbc;
  // servlet object
  public HttpServletRequest _request;
  // 存放回傳的資料,資料筆數記錄在 _current_page_record
  public HashMap[] _records;
 
  private static boolean B_DEBUG = false;
 
  /**
   * 建構元
   * @param HttpServletRequest request
   */
  public PageList() {
    _records = new HashMap[_page_records];
  }
 
  /**
   * 建構元:在 jsp 中使用
   * @param HttpServletRequest request
   */
  public PageList( HttpServletRequest request ) {
    _request = request;
    _records = new HashMap[_page_records];
  }
 
  /**
   * 建構元
   * @param HttpServletRequest request
   */
  public PageList( HttpServletRequest request, int nPageRecords ) {
    _request = request;
    _page_records = nPageRecords;
    _records = new HashMap[_page_records];
  }
 
  /**
   * 設定資料庫連結物件
   * @param  Connection p_conn
   */
  public void setConnection( Connection p_conn ) {
    dbc = p_conn;
  }
 
  /**
   * 取得總筆數
   * @return int
   */
  public int getTotalRecords() {
    return _total_records;
  }
 
  /**
   * 取得總頁數
   * @return int
   */
  public int getTotalPages() {
    return _total_pages;
  }
 
  /**
   * 取得每頁有幾筆
   * @return int
   */
  public int getPageRecords() {
    return _page_records;
  }
 
  /**
   * 取得目前要處理的頁數
   * @return int
   */
  public int getCurrentPageNo() {
    return _current_page;
  }
 
  /**
   * 取得目前頁數的資料筆數
   * @return int
   */
  public int getCurrentPageRecords() {
    return _current_page_record;
  }
 
  /**
   * 設定目前要處理的頁數
   * @param int pageno
   */
  public void setCurrentPageNo( int pageno ) {
    _current_page = pageno;
  }
 
  /**
   * 設定目前要處理的頁數
   * 在 Web 使用時,必須採用固定的參數 pno
   */
  public void setCurrentPageNo() {
    try {
      _current_page = Integer.parseInt( ReqParam.getParameter( _request, "pno" ) );
      if ( _current_page < 0 ) _current_page = 0;
    }
    catch( NumberFormatException e ) {
      _current_page = 0;
    }
  }
 
  /**
   * 取得記錄內的資料
   * @param int n_row
   * @param String s_name
   * @return String
   */
  public String get( int n_row, String s_name ) {
    if ( n_row < 0 || n_row >= _current_page_record ) return null;
    return (String)_records[n_row].get( s_name );
  }
 
  /**
   * 計算目前的記錄數
   * @param int n_row
   * @return int
   */
  public int getCurrentRecords( int n_row ) {
    return (n_row+1) + (_current_page * _page_records );
  }
 
  /**
   * 設定各項參數值
   * @param String sSQL 用來計算總筆數的 SQL Statement
      ex. select count(*) from xxxtable
   * @param String[] sValues 計算總筆數時,若有 where 條件式,
      請將該條件對應的 Values ,按順序用 String Array 傳過來。
   * @throw SQLException
   */
  public void setPageInfo( String sSQL, String[] sValues ) throws SQLException {
    // 取得總文章數
    PreparedStatement pstmt = dbc.prepareStatement( sSQL );
    setWhereValues( pstmt, sValues );
    ResultSet rs = pstmt.executeQuery();
    if ( rs.next() ) {
      _total_records = rs.getInt(1);
      _total_pages = _total_records / _page_records;
      if ( ( _total_records % _page_records ) != 0 ) _total_pages += 1;
    }
    rs.close();
    pstmt.close();
    if ( _current_page >= _total_pages ) _current_page = _total_pages - 1;
  }
 
  /**
   * 取得該頁的資料
   * 當 DB Server 的 JDBC Driver 不支援 ResultSet.TYPE_SCROLL_INSENSITIVE,請使用此函數。
   * @param String sIDSQL 用以取得 Primary Key 的 SQL Statement
      ex. select id from xxxtable
   * @param String sOrder[] 排序用的欄位,即 SQL Statement 裡的 order by 欄位
      請以 String Array 來傳遞。
   * @param String sAscOrDesc 請傳進 ASC , DESC,用來決定要採用何種排序
   * @param String sSQL 取得資料的 SQL Statement
      ex. select fa, fb, fc from xxxtable
   * @param String[] sValues 若有 where 條件式,
      請將該條件對應的 Values ,按順序用 String Array 傳過來。
   * @param boolean bTrue 無用的參數,僅是用來區分二個 setPageData 函數用
   *
   * @return boolean
   * @throw SQLException
   */
  public void setPageData( String sIDSQL, String sOrder[], String sAscOrDesc,
    String sSQL, String[] sValues ) throws SQLException {
    if ( _total_records == 0 ) return;
    long startTimeMillis  = System.currentTimeMillis();
    // 先取出 ID
    PreparedStatement pstmt = dbc.prepareStatement( sIDSQL 
      + parseOrderBy( sOrder, sAscOrDesc ) );
    PreparedStatement pstmt2 = dbc.prepareStatement( sSQL );
    setWhereValues( pstmt, sValues );
    setWhereValues( pstmt2, sValues );
    pstmt.setMaxRows( parseMaxRows() );
    ResultSet rs = pstmt.executeQuery();
    int curRows = 0;
    int nRecCnt = setStartRecordNo();
    while( rs.next() ) {
      if ( isPageData( curRows ) ) {
        setIdValues( pstmt2, sValues, rs );
        ResultSet rs2 = pstmt2.executeQuery();
        nRecCnt = setRecordData( rs2, nRecCnt, overHalfPages() );
        rs2.close();
      }
      curRows++;
    }
    pstmt2.close();
    rs.close();
    pstmt.close();
    countExecTime( startTimeMillis );
  }
 
  private int setStartRecordNo() {
    if ( overHalfPages() ) {
      if ( parseMaxRows() < _page_records ) return (parseMaxRows()-1);
      else return (_page_records-1);
    }
    else return 0;
  }
 
  private void setIdValues( PreparedStatement pstmt, String sValues[], ResultSet rs )
    throws SQLException {
    ResultSetMetaData rmd = rs.getMetaData();
    int nStart = 0;
    if ( sValues != null && sValues.length > 0 ) nStart = sValues.length;
    for( int j = 1;j <= rmd.getColumnCount();j++ ) {
      pstmt.setString( nStart + j, rs.getString(j) );
    }
  }
 
  private void setWhereValues( PreparedStatement pstmt, String sValues[] )
    throws SQLException {
    if ( sValues != null && sValues.length > 0 ) {
      for( int j = 0;j < sValues.length;j++ ) {
        pstmt.setString( j+1, sValues[j] );
      }
    }
  }
 
  private int setRecordData( ResultSet rs, int nRecCnt, boolean bOverHalf )
    throws SQLException {
    if ( nRecCnt < 0 || nRecCnt >= _page_records ) return nRecCnt;
    if ( rs.next() ) {
      ResultSetMetaData rmd = rs.getMetaData();
      _records[nRecCnt] = new HashMap( rmd.getColumnCount() );
      for( int j = 1;j <= rmd.getColumnCount();j++ ) {
        // Log.println( "setRecordData()", rmd.getColumnTypeName(j) );
        if ( rmd.getColumnTypeName(j).equals("CLOB") )
          _records[nRecCnt].put( rmd.getColumnName(j).toUpperCase(), 
            LobPros.readClob( rs, rmd.getColumnName(j) ) );
        else
          _records[nRecCnt].put( rmd.getColumnName(j).toUpperCase(), rs.getString(j) );
      }
      _current_page_record++;
      if ( bOverHalf ) return (nRecCnt - 1);
      else return (nRecCnt + 1);
    }
    return nRecCnt;
  }
 
  private void countExecTime( long lStartTime ) {
    long endTimeMillis  = System.currentTimeMillis();
    double runTime = (endTimeMillis - lStartTime) / 1000.0;
    if ( B_DEBUG ) System.out.println( "result spend times => (" + runTime + ")" );
  }
 
  private boolean overHalfPages() {
    if ( _current_page > ( _total_pages / 2 ) ) return true;
    return false;
  }
 
  /**
   * 沒有使用 ResultSet.TYPE_SCROLL_INSENSITIVE 時,才會呼叫到此 Method
   * 用以檢查目前的記錄數是否為該頁的記錄
   * @param int nCurCnt 目前的記錄數
   * @return boolean
   */
  private boolean isPageData( int nCurCnt ) {
    if ( overHalfPages() ) {
      if ( ( _total_records - nCurCnt ) <= ( ( _current_page + 1 ) * _page_records ) )
        return true;
    }
    else {
      if ( nCurCnt >= ( _current_page * _page_records ) ) return true;
    }
    return false;
  }
 
  /**
   * 當要處理的頁次 > 總頁次 / 2 時,改為反向排序,減少取回的資料筆數
   * 根據 sOrder[] 內的欄位,製作出 order by a desc, b desc ... 的字串
   * @param String sOrder[] 排序用的欄位,即 SQL Statement 裡的 order by 欄位
      請以 String Array 來傳遞。
   * @param String sAscOrDesc 請傳進 ASC , DESC,用來決定要採用何種排序
   *
   * @return String orderby_string
   */
  private String parseOrderBy( String sOrder[], String sAscOrDesc ) {
    if ( sOrder == null || sOrder.length <= 0 ) return "";
    String s_order = sAscOrDesc.toUpperCase();
    if ( overHalfPages() ) {
      if ( s_order.equals( "DESC" ) ) s_order = "";
      else s_order = "DESC";
    }
    StringBuffer sbtmp = new StringBuffer( 128 );
    sbtmp.append( " ORDER BY " );
    for( int j = 0;j < sOrder.length;j++ ) {
      if ( j > 0 ) sbtmp.append( "," );
      sbtmp.append( sOrder[j] ).append( " " ).append( s_order );
    }
    return sbtmp.toString();
  }
 
  /**
   * 計算出本次查詢要取回多少筆記錄
   * @return int MaxRows
   */
  private int parseMaxRows() {
    if ( overHalfPages() ) {
      return ( _total_records - ( _current_page * _page_records ) );
    }
    else {
      return ( ( _current_page + 1 ) * _page_records );
    }
  }
 
  /**
   * 取得該頁的資料
   * @param String sIDSQL 用以取得 Primary Key 的 SQL Statement
      ex. select id from xxxtable
   * @param String sOrder[] 排序用的欄位,即 SQL Statement 裡的 order by 欄位
      請以 String Array 來傳遞。
   * @param String sAscOrDesc 請傳進 ASC , DESC,用來決定要採用何種排序
   * @param String sSQL 取得資料的 SQL Statement
      ex. select fa, fb, fc from xxxtable
   * @param String[] sValues 若有 where 條件式,
      請將該條件對應的 Values ,按順序用 String Array 傳過來。
   *
   * @return boolean
   * @throw SQLException
   */
  public void setPageData( String sIDSQL, String sOrder[], String sAscOrDesc,
    String sSQL, String[] sValues, boolean bTrue ) throws SQLException {
    if ( _total_records == 0 ) return;
    long startTimeMillis  = System.currentTimeMillis();
    // 先取出 ID
    PreparedStatement pstmt = dbc.prepareStatement(
      sIDSQL + parseOrderBy( sOrder, sAscOrDesc ),
      ResultSet.TYPE_SCROLL_INSENSITIVE,
      ResultSet.CONCUR_READ_ONLY );
    PreparedStatement pstmt2 = dbc.prepareStatement( sSQL );
    setWhereValues( pstmt, sValues );
    setWhereValues( pstmt2, sValues );
    pstmt.setMaxRows( parseMaxRows() );
    ResultSet rs = pstmt.executeQuery();
    rs.last();
    if ( rs.getRow() <= 0 ) return;
    int nRelative = 1;
    if ( overHalfPages() ) nRelative = -1;
    else rs.absolute( _current_page * _page_records + 1 );
    int nRecCnt = 0;
    while( true ) {
      setIdValues( pstmt2, sValues, rs );
      ResultSet rs2 = pstmt2.executeQuery();
      nRecCnt = setRecordData( rs2, nRecCnt, false );
      rs2.close();
      if ( nRecCnt >= _page_records ) break;
      if ( rs.relative( nRelative ) != true ) break;
    }
    pstmt2.close();
    rs.close();
    pstmt.close();
    countExecTime( startTimeMillis );
  }
} 


精靈 edited on 2004-06-09 08:07
reply to postreply to post
話題樹型展開
人氣 標題 作者 字數 發文時間
7446 實作資料庫記錄分頁瀏覽程式 精靈 14281 2004-06-09 02:19
5415 Re:實作資料庫記錄分頁瀏覽程式 tclin 626 2004-08-08 11:17
5351 Re:實作資料庫記錄分頁瀏覽程式 精靈 353 2004-08-08 14:06
4761 Re:實作資料庫記錄分頁瀏覽程式 catfish 1102 2004-10-22 16:45
» JWorld@TW »  Java 程式分享區

reply to postflat modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8