jsp分页技术实现.docx
- 文档编号:8725107
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:22
- 大小:38.19KB
jsp分页技术实现.docx
《jsp分页技术实现.docx》由会员分享,可在线阅读,更多相关《jsp分页技术实现.docx(22页珍藏版)》请在冰豆网上搜索。
jsp分页技术实现
title:
JSP分页技术实现
summary:
使用工具类实现通用分页处理
author:
evan_zhao
目前比较广泛使用的分页方式是将查询结果缓存在HttpSession或有状态bean中,翻页的时候从缓存中取出一页数据显示。
这种方法有两个主要的缺点:
一是用户可能看到的是过期数据;二是如果数据量非常大时第一次查询遍历结果集会耗费很长时间,并且缓存的数据也会占用大量内存,效率明显下降。
其它常见的方法还有每次翻页都查询一次数据库,从ResultSet中只取出一页数据(使用();()获得总计录条数,使用()定位到本页起始记录)。
这种方式在某些数据库(如oracle)的JDBC实现中差不多也是需要遍历所有记录,实验证明在记录数很大时速度非常慢。
至于缓存结果集ResultSet的方法则完全是一种错误的做法。
因为ResultSet在Statement或Connection关闭时也会被关闭,如果要使ResultSet有效势必长时间占用数据库连接。
因此比较好的分页做法应该是每次翻页的时候只从数据库里检索页面大小的块区的数据。
这样虽然每次翻页都需要查询数据库,但查询出的记录数很少,网络传输数据量不大,如果使用连接池更可以略过最耗时的建立数据库连接过程。
而在数据库端有各种成熟的优化技术用于提高查询速度,比在应用服务器层做缓存有效多了。
在oracle数据库中查询结果的行号使用伪列ROWNUM表示(从1开始)。
例如select * from employee where rownum<10 返回前10条记录。
但因为rownum是在查询之后排序之前赋值的,所以查询employee按birthday排序的第100到120条记录应该这么写:
select * from (
select my_table.*, rownum as my_rownum from (
select name, birthday from employee order by birthday
) my_table where rownum <120
) where my_rownum>=100
mySQL可以使用LIMIT子句:
select name, birthday from employee order by birthday LIMIT 99,20
DB2有rownumber()函数用于获取当前行数。
SQL Server没研究过,可以参考这篇文章:
在Web程序中分页会被频繁使用,但分页的实现细节却是编程过程中比较麻烦的事情。
大多分页显示的查询操作都同时需要处理复杂的多重查询条件,sql语句需要动态拼接组成,再加上分页需要的记录定位、总记录条数查询以及查询结果的遍历、封装和显示,程序会变得很复杂并且难以理解。
因此需要一些工具类简化分页代码,使程序员专注于业务逻辑部分。
下面是我设计的两个工具类:
PagedStatement 封装了数据库连接、总记录数查询、分页查询、结果数据封装和关闭数据库连接等操作,并使用了PreparedStatement支持动态设置参数。
RowSetPage 参考PetStore的page by page iterator模式, 设计RowSetPage用于封装查询结果(使用OracleCachedRowSet缓存查询出的一页数据,关于使用CachedRowSet封装数据库查询结果请参考JSP页面查询显示常用模式)以及当前页码、总记录条数、当前记录数等信息, 并且可以生成简单的HTML分页代码。
PagedStatement 查询的结果封装成RowsetPage。
下面是简单的使用示例:
1.
2. RowSet empRS = .RowSet) ();
3. if (empRS!
=null) while () ) {
4.%>
5.
6.
7.
8.
9.
10.
11.<%
12. }etHTML("doQuery", "pageno")%>
13.
14.
15.
效果如图:
因为分页显示一般都会伴有查询条件和查询动作,页面应已经有校验查询条件和提交查询的javascript方法(如上面的doQuery),所以()生成的分页代码在用户选择新页码时直接回调前面的处理提交查询的javascript方法。
注意在显示查询结果的时候上次的查询条件也需要保持,如">。
同时由于页码的参数名可以指定,因此也支持在同一页面中有多个分页区。
另一种分页代码实现是生成每一页的URL,将查询参数和页码作为QueryString附在URL后面。
这种方法的缺陷是在查询条件比较复杂时难以处理,并且需要指定处理查询动作的servlet,可能不适合某些定制的查询操作。
如果对()生成的默认分页代码不满意可以编写自己的分页处理代码,RowSetPage提供了很多getter方法用于获取相关信息(如当前页码、总页数、 总记录数和当前记录数等)。
在实际应用中可以将分页查询和显示做成jsp taglib, 进一步简化JSP代码,屏蔽Java Code。
附:
分页工具类的源代码, 有注释,应该很容易理解。
继承Page)
继承PagedStatement)
您可以任意使用这些源代码,但必须保留author字样
1.
2.List;
3.import .ArrayList;
4.import .Collection;
5.import .Collections;
6.
7.
8./**
9. * Title:
分页对象
10. * Description:
用于包含数据及分页信息的对象
11. * Page类实现了用于显示分页信息的基本方法,但未指定所含数据的类型,
12. * 可根据需要实现以特定方式组织数据的子类,
13. * 如RowSetPage以RowSet封装数据,ListPage以List封装数据
14. * Copyright:
Copyright (c) 2002
15. * @author
16. * @version
17. */
18.public class Page implements .Serializable {
19. public static final Page EMPTY_PAGE = new Page();
20. public static final int DEFAULT_PAGE_SIZE = 20;
21. public static final int MAX_PAGE_SIZE = 9999;
22.
23. private int myPageSize = DEFAULT_PAGE_SIZE;
24.
25. private int start;
26. private int avaCount,totalSize;
27. private Object data;
28.
29. private int currentPageno;
30. private int totalPageCount;
31.
32. /**
33. * 默认构造方法,只构造空页
34. */
35. protected Page(){
36. (0,0,0,DEFAULT_PAGE_SIZE,new Object());
37. }
38.
39. /**
40. * 分页数据初始方法,由子类调用
41. * @param start 本页数据在数据库中的起始位置
42. * @param avaCount 本页包含的数据条数
43. * @param totalSize 数据库中总记录条数
44. * @param pageSize 本页容量
45. * @param data 本页包含的数据
46. */
47. protected void init(int start, int avaCount, int totalSize, int pageSize, Object data){
48.
49. =avaCount;
50. = pageSize;
51.
52. = start;
53. = totalSize;
54.
55. =data;
56.
57. ength()<1) {
58. queryJSFunctionName = "gotoPage";
59. }
60. if (pageNoParamName == null || ().length()<1){
61. pageNoParamName = "pageno";
62. }
63.
64. String gotoPage = "_"+queryJSFunctionName;
65.
66. StringBuffer html = new StringBuffer("\n");
67. (" \n")
89. .append( "");
90. ( "
\n"); 93. ( " 共" ).append( getTotalPageCount() ).append( "页") 94. .append( " [") .append(getStart()).append("..").append(getEnd()) 95. .append("/").append()).append("] \n") 96. .append( " | \n") \n"); 98. if (hasPreviousPage()){ 99. ( "[ ").append(gotoPage) 100. .append("(") .append(getCurrentPageNo()-1) 101. .append( ")'>上一页 102. } 103. ( " 第") 104. .append( " 页 \n"); 121. if (hasNextPage()){ 122. ( " [ ").append(gotoPage) 123. .append("(").append((getCurrentPageNo()+1)) 124. .append( ")'>下一页 125. } 126. ( " |
127.
128. return ();
129.
130. }
131.}
132.
133.
134.
135.
136.RowSet;
137.
138.
139./**
140. *
Title:
RowSetPage
141. *
Description:
使用RowSet封装数据的分页对象
142. *
Copyright:
Copyright (c) 2003
143. * @author
144. * @version
145. */
146.
147.public class RowSetPage extends Page {
148. private .RowSet rs;
149.
150. /**
151. *空页
152. */
153. public static final RowSetPage EMPTY_PAGE = new RowSetPage();
154.
155. /**
156. *默认构造方法,创建空页
157. */
158. public RowSetPage(){
159. this(null, 0,0);
160. }
161.
162. /**
163. *构造分页对象
164. *@param crs 包含一页数据的OracleCachedRowSet
165. *@param start 该页数据在数据库中的起始位置
166. *@param totalSize 数据库中包含的记录总数
167. */
168. public RowSetPage(RowSet crs, int start, int totalSize) {
169. this(crs,start,totalSize,;
170. }
171.
172. /**
173. *构造分页对象
174. *@param crs 包含一页数据的OracleCachedRowSet
175. *@param start 该页数据在数据库中的起始位置
176. *@param totalSize 数据库中包含的记录总数
177. *@pageSize 本页能容纳的记录数
178. */
179. public RowSetPage(RowSet crs, int start, int totalSize, int pageSize) {
180. try{
181. int avaCount=0;
182. if (crs!
=null) {
183. ();
184. if ()){
185. ();
186. avaCount = ();
187. }
188. ();
189. }
190. rs = crs;
191. (start,avaCount,totalSize,pageSize,rs);
192. }catch.SQLException sqle){
193. throw new RuntimeException());
194. }
195. }
196.
197. /**
198. *取分页对象中的记录数据
199. */
200. public .RowSet getRowSet(){
201. return rs;
202. }
203.
204.
205.}
206.
207.
208.
209.
210.BigDecimal;
211.import .List;
212.import .Iterator;
213.import .Collections;
214.
215.import .Connection;
216.import .SQLException;
217.import .ResultSet;
218.import .Statement;
219.import .Prepar
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- jsp 分页 技术 实现