$$$$$$$$$$$$$$$在struts中分页的一种实现
我的项目中的分页功能 1, 思路
使用一个页面控制类,它记录页面信息,如上页,下页,当前页等。在查询的Action中,将这个控制类和查询条件一起传递给数据库访问bean,然后将这两个参数保存在用户session中。在分页控制Action中,利用接收到的分页参数调用数据库访问的bean.
2,实现
(1)分页控制类 /* @author nick
* Created on 2004-3-18
* file name:PageController.java * * */
package com.tower.util; /**
* @author nick * 2004-3-18
* 用来进行翻页控制 * */
public class PageController { int totalRowsAmount; //总行数
boolean rowsAmountSet; //是否设置过totalRowsAmount int pageSize=2; //每页行数 int currentPage=1; //当前页码 int nextPage; int previousPage;
int totalPages; //总页数
boolean hasNext; //是否有下一页 boolean hasPrevious; //是否有前一页 String description; int pageStartRow; int pageEndRow;
public PageController(int totalRows){ setTotalRowsAmount(totalRows); }
public PageController(){} /**
* @param i * 设定总行数 */
public void setTotalRowsAmount(int i) { if(!this.rowsAmountSet){ totalRowsAmount = i;
totalPages=totalRowsAmount/pageSize+1; setCurrentPage(1);
this.rowsAmountSet=true; } } /**
* @param i *
* 当前页 * */
public void setCurrentPage(int i) { currentPage = i;
nextPage=currentPage+1; previousPage=currentPage-1; //计算当前页开始行和结束行
if(currentPage*pageSize pageEndRow=totalRowsAmount; pageStartRow=pageSize*(totalPages-1)+1; } //是否存在前页和后页 if (nextPage>totalPages){ hasNext=false; }else{ hasNext=true; } if(previousPage==0){ hasPrevious=false; }else{ hasPrevious=true; }; System.out.println(this.description()); } /** * @return */ public int getCurrentPage() { return currentPage; } /** * @return */ public boolean isHasNext() { return hasNext; } /** * @return */ public boolean isHasPrevious() { return hasPrevious; } /** * @return */ public int getNextPage() { return nextPage; } /** * @return */ public int getPageSize() { return pageSize; } /** * @return */ public int getPreviousPage() { return previousPage; } /** * @return */ public int getTotalPages() { return totalPages; } /** * @return */ public int getTotalRowsAmount() { return totalRowsAmount; } /** * @param b */ public void setHasNext(boolean b) { hasNext = b; } /** * @param b */ public void setHasPrevious(boolean b) { hasPrevious = b; } /** * @param i */ public void setNextPage(int i) { nextPage = i; } /** * @param i */ public void setPageSize(int i) { pageSize = i; } /** * @param i */ public void setPreviousPage(int i) { previousPage = i; } /** * @param i */ public void setTotalPages(int i) { totalPages = i; } /** * @return */ public int getPageEndRow() { return pageEndRow; } /** * @return */ public int getPageStartRow() { return pageStartRow; } public String getDescription(){ String description=\"Total:\"+this.getTotalRowsAmount()+ \" items \"+this.getTotalPages() +\" pages\"; // this.currentPage+\" Previous \"+this.hasPrevious + // \" Next:\"+this.hasNext+ // \" start row:\"+this.pageStartRow+ // \" end row:\"+this.pageEndRow; return description; } public String description(){ String description=\"Total:\"+this.getTotalRowsAmount()+ \" items \"+this.getTotalPages() +\" pages,Current page:\"+ this.currentPage+\" Previous \"+this.hasPrevious + \" Next:\"+this.hasNext+ \" start row:\"+this.pageStartRow+ \" end row:\"+this.pageEndRow; return description; } public static void main(String args[]){ PageController pc=new PageController(3); System.out.println(pc.getDescription()); // pc.setCurrentPage(2); // System.out.println(pc.description()); // pc.setCurrentPage(3); // System.out.println(pc.description()); } } (2)查询Action的代码片断 public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { Base queryForm= (Base) form; if(!queryForm.getName().equals(\"\")){ PageController pc=new PageController(); EmployeeBase service=new EmployeeBase(); ArrayList result=(ArrayList)service.search(queryForm,pc); HttpSession session=request.getSession(); session.setAttribute(\"queryForm\ session.setAttribute(\"pageController\ request.setAttribute(\"queryResult\ request.setAttribute(\"pageController\return mapping.findForward(\"haveResult\"); }else{ return mapping.findForward(\"noResult\"); } } (3),翻页Action的代码片断 public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { //读取翻页参数 TurnPageForm turnPageForm=(TurnPageForm)form; //从PageController中取出查询信息,并使用bean提供的调用接口处理结果 HttpSession session=request.getSession(); PageController pc=(PageController)session.getAttribute(\"pageController\"); Base queryForm=(Base)session.getAttribute(\"queryForm\"); pc.setCurrentPage(turnPageForm.getViewPage()); EmployeeBase service=new EmployeeBase(); ArrayList result=(ArrayList)service.search(queryForm,pc); //根据参数将数据写入 request request.removeAttribute(\"queryResult\"); request.removeAttribute(\"pageController\"); request.setAttribute(\"queryResult\request.setAttribute(\"pageController\ //forward 到显示页面 return mapping.findForward(\"haveResult\"); } (4)数据库访问bean中的片断 public Collection search(Base base, PageController pc) throws SQLException { ArrayList emps = new ArrayList(); ResultSet rs = getSearchResult(base); rs.absolute(-1); pc.setTotalRowsAmount(rs.getRow()); setPageController(pc); if (rs.getRow() > 0) { rs.absolute(pc.getPageStartRow()); do { System.out.println(\"in loop\" + rs.getRow()); Base b = new Base(); b.setName(rs.getString(\"Name\")); b.setIdCard(rs.getString(\"IDCard\")); System.out.println(\"From db:\" + rs.getString(\"IDCard\")); emps.add(b); if (!rs.next()) { break; } } while (rs.getRow() < (pc.getPageEndRow() + 1)); } return emps; } (5)在jsp中,翻页部分的代码片断 这样一来,翻页的功能可以以你喜欢的方式表现给client 版权声明 本篇文章对您是否有帮助? 投票: 是 否 投票结果: 作者其它文章: Struts处理用户表单请求的核心源代码: Struts例子的设计分析(转)- - struts简单例子的分析 使用struts,ibaits和JSTL开发简便通用的文件上传系统 Struts标记库 作者全部文章 评论人:fangxia 参与分: 593 专家分: 15 发表时间: 2005-03-30 14:31 思路8错,,谢谢。。 这个文章共有 1 条评论,共 1 页 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// $$$$$$$$$$$$$$$$JSP页面查询显示常用模式 1.直接使用ResultSet 2.Value Object 3.hashmap key,value 4.RowSet ------------------------ 1.直接使用ResultSet 最大众化的方法, 原文中忽略了这一方法,偶给加上了 代码略 2. 使用Value Object。将每条记录均封装成JavaBean对象,把这些对象装入Collection传送给JSP显示 。这种方法的缺点是每一种查询都需要定义一个java class,并且将记录数据封装成java对象时也需要很 多额外的代码。 示例代码: //查询数据代码 Connection conn = DBUtil.getConnection(); PreparedStatement pst = null; ResultSet rs = null; try{ String sql=“select emp_code, real_name from t_employee where organ_id=?”; pst = conn.preparedStatement(sql); pst.setString(1, “101”); ResultSet rs = pst.executeQuery(); List list = new ArrayList(); Employee emp; while (rs.next()){ emp = new Employee(); emp.setReakName(rs.getString(“real_name”)); emp.setEmpCode(rs.getString(“emp_code”)); „ list.add(emp); } return list; }finally{ DBUtil.close(rs, pst ,conn); } //jsp显示部分代码 <% List empList = (List)request.getAttribute(“empList”); if (empList == null) empList = Collections.EMPTY_LIST; %> „ Employee emp; for (int i=0; i< empList.size(); i++){ emp = (Employee) empList.get(i); %> }// end for %> 3. 使用hashmap作为数据容器。 具体做法: 1. 生成一个List对象(List list = new ArrayList() )。 2. 生成一个Map对象(Map map = new HashMap() )。使用Map封装一行数据,key为各字段名,value 为对应的值。(map.put(“USER_NAME”), rs.getString(“USER_NAME”)) 3. 将第2 步生成的Map对象装入第1步的list对象中(list.add(map) )。 4. 重复2、3步直到ResultSet遍历完毕 在DBUtil. resultSetToList(ResultSet rs)方法中实现了上述过程(所有列名均使用大写),可参考使用。 HashMap map = null; while(rs.next(){ map = new HashMap(); map.put(\"Field1\map.put(\"Field2\***** map.put(\"fieldn\} 以上是写死的, 可以使用ResultSetMetadata进行干净彻底的一次性封装, 可以取到rs中所有字段名 String name = null; ResultSetMetaData rsmd = rs.getMetaData(); int num = rsmd.getColumnCount(); int i = 0; while(rs.next()){ for(i=1;i<=num;i++){ name = rsmd.getColumnName(i); map.put(\"name\}/*end for*/ }/*end while*/ 示例代码: //查询数据部分代码: „ Connection conn = DBUtil.getConnection(); PreparedStatement pst = null; ResultSet rs = null; try{ String sql=“select emp_code, real_name from t_employee where organ_id=?”; pst = conn.preparedStatement(sql); pst.setString(1, “101”); rs = pst.executeQuery(); List list = DBUtil. resultSetToList(ResultSet rs); return list; }finally{ DBUtil.close(rs, pst ,conn); } //JSP显示部分代码 <% List empList = (List)request.getAttribute(“empList”); if (empList == null) empList = Collections.EMPTY_LIST; %> „ Map colMap; for (int i=0; i< empList.size(); i++){ colMap = (Map) empList.get(i); %> }// end for %> 使用RowSet。 RowSet是JDBC2.0中提供的接口,Oracle对该接口有相应实现,其中很有用的是 oracle.jdbc.rowset.OracleCachedRowSet。 OracleCachedRowSet实现了ResultSet中的所有方法,但与 ResultSet不同的是,OracleCachedRowSet中的数据在Connection关闭后仍然有效。 oracle的rowset实现在http://otn.oracle.com/software/content.html的jdbc下载里有,名称是 ocrs12.zip 示例代码: //查询数据部分代码: import javax.sql.RowSet; import oracle.jdbc.rowset.OracleCachedRowSet; „ Connection conn = DBUtil.getConnection(); PreparedStatement pst = null; ResultSet rs = null; try{„„ String sql=“select emp_code, real_name from t_employee where organ_id=?”; pst = conn.preparedStatement(sql); pst.setString(1, “101”); rs = pst.executeQuery(); OracleCachedRowSet ors = newOracleCachedRowSet(); //将ResultSet中的数据封装到RowSet中 ors.populate(rs); return ors; }finally{ DBUtil.close(rs, pst, conn); } //JSP显示部分代码 <% javax.sql.RowSet empRS = (javax.sql.RowSet) request.getAttribute(“empRS”); %> „ if (empRS != null) while (empRS.next() ) { %> }// end while %> 适用场合: 1.ResultSet适合于短平快项目,纯JSP方案最适合 2.value object 使用于定制的查询操作,个人认为该方法比较SB,而许多人却乐此不疲, 如果使用struts,ibatis,hibernate等开发基本上属于此中模式, 使用value object其实还是一个比较重量级的方案,如果不使用 EJB或web sevice等分布式方案,确实没有使用value object的必要, 大家都倡导轻量级的解决方案,为何不更轻松些,使用方法1或3, 写一大堆value bean,无论是从开发工作量和维护上都是一个噩梦 3.HashMap充当数据容器 适用于多条查询语句或需要对查询结果进行处理的情况。 该方法比较不错,灵活机动,适用范围广, 纯JSP,EJB,WEB SERVICE均适用 4.RowSet 适合于单条查询语句,适用于快速开发。 RowSet本身就是一种数据容器,其功能与hashmap差不多, 方法3可以取代方法4 版权声明 本篇文章对您是否有帮助? 投票: 是 否 投票结果: 作者其它文章: jdbc驱动导致的中文问题 在项目中使用Struts-menu 企业管理软件的需求描述方法 web开发中的多条件查询处理技巧1则 valuelist简介 作者全部文章 评论人:robornet 参与分: 636 专家分: 55 来自: 阳光岛 发表时间: 2005-04-26 08:41 ??得不?,?何第二?方法?第三?方法的示例代?一?呢? 评论人:robornet 参与分: 636 专家分: 55 来自: 阳光岛 发表时间: 2005-04-26 08:42 总结得不错,为何第二种方法与第三种方法的示例代码一样呢? 评论人:giscat 参与分: 16832 专家分: 1787 发表时间: 2005-04-26 08:50 方法2,3不一样的把, 2要写valuebean 3使用hashmap充当数据容器, 把每条记录都放到一个hashmap中,然后把 hashmap放到list里 评论人:giscat 参与分: 16832 专家分: 1787 发表时间: 2005-04-26 09:03 改了一下 HashMap map = null; while(rs.next(){ map = new HashMap(); map.put(\"Field1\map.put(\"Field2\***** map.put(\"fieldn\} 以上是写死的, 可以使用ResultSetMetadata进行干净彻底的一次性封装, 可以取到rs中所有字段名 String name = null; ResultSetMetaData rsmd = rs.getMetaData(); int num = rsmd.getColumnCount(); int i = 0; while(rs.next()){ for(i=1;i<=num;i++){ name = rsmd.getColumnName(i); map.put(\"name\}/*end for*/ }/*end while*/ 这个文章共有 4 条评论,共 1 页 上一篇文章 返回〔JSP/Servlet/JSF〕 下一篇文章 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// $$$$$$$$$$$$$$$$JSP分页技术实现 title: JSP分页技术实现 summary:使用工具类实现通用分页处理 author: evan_zhao email: evan_zhao@hotmail.com 目前比较广泛使用的分页方式是将查询结果缓存在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条记录应该这么写: [pre] 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 [/pre] 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。 下面是简单的使用示例: //DAO查询数据部分代码: „ public RowSetPage getEmployee(String gender, int pageNo) throws Exception{ String sql=\"select emp_id, emp_code, user_name, real_name from employee where gender =?\"; //使用Oracle数据库的分页查询实现,每页显示5条 PagedStatement pst =new PagedStatementOracleImpl(sql, pageNo, 5); pst.setString(1, gender); return pst.executeQuery(); } //Servlet处理查询请求部分代码: „ int pageNo; try{ //可以通过参数pageno获得用户选择的页码 pageNo = Integer.parseInt(request.getParameter(\"pageno\") ); }catch(Exception ex){ //默认为第一页 pageNo=1; } String gender = request.getParameter(\"gender\" ); request.setAttribute(\"empPage\ „ //JSP显示部分代码 <%@ page import = \"page.RowSetPage\"%> „ „ 效果如图: 因为分页显示一般都会伴有查询条件和查询动作,页面应已经有校验查询条件和提交查询的javascript方法(如上面的doQuery),所以 RowSetPage.getHTML()生成的分页代码在用户选择新页码时直接回调前面的处理提交查询的javascript方法。注意在显示查询结果的时候上次的查询条件也需要保持,如\">。同时由于页码的参数名可以指定,因此也支持在同一页面中有多个分页区。 另一种分页代码实现是生成每一页的URL,将查询参数和页码作为QueryString附在URL后面。这种方法的缺陷是在查询条件比较复杂时难以处理,并且需要指定处理查询动作的servlet,可能不适合某些定制的查询操作。 如果对RowSetPage.getHTML()生成的默认分页代码不满意可以编写自己的分页处理代码,RowSetPage提供了很多getter方法用于获取相关信息(如当前页码、总页数、 总记录 数和当前记录数等)。 在实际应用中可以将分页查询和显示做成jsp taglib, 进一步简化JSP代码,屏蔽Java Code。 附:分页工具类的源代码, 有注释,应该很容易理解。 1.Page.java 2.RowSetPage.java(RowSetPage继承Page) 3.PagedStatement.java 4.PagedStatementOracleImpl.java(PagedStatementOracleImpl继承PagedStatement) 您可以任意使用这些源代码,但必须保留author evan_zhao@hotmail.com字样 /////////////////////////////////// // // Page.java // author: evan_zhao@hotmail.com // /////////////////////////////////// package page; import java.util.List; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; /** * Title: 分页对象 * Description: 用于包含数据及分页信息的对象 * Page类实现了用于显示分页信息的基本方法,但未指定所含数据的类型, * 可根据需要实现以特定方式组织数据的子类, * 如RowSetPage以RowSet 封装数据,ListPage以List封装数据 public class Page implements java.io.Serializable { public static final Page EMPTY_PAGE = new Page(); public static final int DEFAULT_PAGE_SIZE = 20; public static final int MAX_PAGE_SIZE = 9999; private int myPageSize = DEFAULT_PAGE_SIZE; private int start; private int avaCount,totalSize; private Object data; private int currentPageno; private int totalPageCount; /** * 默认构造方法,只构造空页 */ protected Page(){ this.init(0,0,0,DEFAULT_PAGE_SIZE,new Object()); } /** * 分页数据初始方法,由子类调用 * @param start 本页数据在数据库中的起始位置 * @param avaCount 本页包含的数据条数 * @param totalSize 数据库中总记录条数 * @param pageSize 本页容量 * @param data 本页包含的数据 */ protected void init(int start, int avaCount, int totalSize, int pageSize, Object data){ this.avaCount =avaCount; this.myPageSize = pageSize; this.start = start; this.totalSize = totalSize; this.data=data; //System.out.println(\"avaCount:\"+avaCount); //System.out.println(\"totalSize:\"+totalSize); if (avaCount>totalSize) { //throw new RuntimeException(\"记录条数大于总条数?!\"); } this.currentPageno = (start -1)/pageSize +1; this.totalPageCount = (totalSize + pageSize -1) / pageSize; if (totalSize==0 && avaCount==0){ this.currentPageno = 1; this.totalPageCount = 1; } //System.out.println(\"Start Index to Page No: \" + start + \"-\" + currentPageno); } public Object getData(){ return this.data; } /** * 取本页数据容量(本页能包含的记录数) * @return 本页能包含的记录数 */ public int getPageSize(){ return this.myPageSize; } /** * 是否有下一页 * @return 是否有下一页 */ public boolean hasNextPage() { /* if (avaCount==0 && totalSize==0){ return false; } return (start + avaCount -1) < totalSize; */ return (this.getCurrentPageNo() * 是否有上一页 * @return 是否有上一页 */ public boolean hasPreviousPage() { /* return start > 1; */ return (this.getCurrentPageNo()>1); } /** * 获取当前页第一条数据在数据库中的位置 * @return */ public int getStart(){ return start; } /** * 获取当前页最后一条数据在数据库中的位置 * @return */ public int getEnd(){ int end = this.getStart() + this.getSize() -1; if (end<0) { end = 0; } return end; } /** * 获取上一页第一条数据在数据库中的位置 * @return 记录对应的rownum */ public int getStartOfPreviousPage() { return Math.max(start-myPageSize, 1); } /** * 获取下一页第一条数据在数据库中的位置 * @return 记录对应的rownum */ public int getStartOfNextPage() { return start + avaCount; } /** * 获取任一页第一条数据在数据库中的位置,每页条数使用默认值 * @param pageNo 页号 * @return 记录对应的rownum */ public static int getStartOfAnyPage(int pageNo){ return getStartOfAnyPage(pageNo, DEFAULT_PAGE_SIZE); } /** * 获取任一页第一条数据在数据库中的位置 * @param pageNo 页号 * @param pageSize 每页包含的记录数 * @return 记录对应的rownum */ public static int getStartOfAnyPage(int pageNo, int pageSize){ int startIndex = (pageNo-1) * pageSize + 1; if ( startIndex < 1) startIndex = 1; //System.out.println(\"Page No to Start Index: \" + pageNo + \"-\" + startIndex); return startIndex; } /** * 取本页包含的记录数 * @return 本页包含的记录数 */ public int getSize() { return avaCount; } /** * 取数据库中包含的总记录数 * @return 数据库中包含的总记录数 */ public int getTotalSize() { return this.totalSize; } /** * 取当前页码 * @return 当前页码 */ public int getCurrentPageNo(){ return this.currentPageno; } /** * 取总页码 * @return 总页码 */ public int getTotalPageCount(){ return this.totalPageCount; } /** * * @param queryJSFunctionName 实现分页的JS脚本名字,页码变动时会自动回调该方法 * @param pageNoParamName 页码参数名称 * @return */ public String getHTML(String queryJSFunctionName, String pageNoParamName){ if (getTotalPageCount()<1){ return \"\"; } if (queryJSFunctionName == null || queryJSFunctionName.trim().length()<1) { queryJSFunctionName = \"gotoPage\"; } if (pageNoParamName == null || pageNoParamName.trim().length()<1){ pageNoParamName = \"pageno\"; } String gotoPage = \"_\"+queryJSFunctionName; StringBuffer html = new StringBuffer(\"\\n\"); html.append(\" \\n\") .append( \"\"); html.append( \" .append( \" .append( \" html.append( \" 共\" ).append( getTotalPageCount() ).append( \"页\") .append( \" [\") .append(getStart()).append(\"..\").append(getEnd()) .append(\"/\").append(this.getTotalSize()).append(\"] \\n\") .append( \" .append( \" html.append( \"[上一页] \\n\"); } html.append( \" 第\") .append( \" 页 \\n\"); if (hasNextPage()){ html.append( \" [下一页] \\n\"); } html.append( \" return html.toString(); } } /////////////////////////////////// // // RowSetPage.java // author: evan_zhao@hotmail.com // /////////////////////////////////// package page; import javax.sql.RowSet; /** * Title: RowSetPage * Description: 使用RowSet封装数据的分页对象 Copyright: Copyright (c) 2003 public class RowSetPage extends Page { private javax.sql.RowSet rs; /** *空页 */ public static final RowSetPage EMPTY_PAGE = new RowSetPage(); /** *默认构造方法,创建空页 */ public RowSetPage(){ this(null, 0,0); } /** *构造分页对象 *@param crs 包含一页数据的OracleCachedRowSet *@param start 该页数据在数据库中的起始位置 *@param totalSize 数据库中包含的记录总数 */ public RowSetPage(RowSet crs, int start, int totalSize) { this(crs,start,totalSize,Page.DEFAULT_PAGE_SIZE); } /** *构造分页对象 *@param crs 包含一页数据的OracleCachedRowSet *@param start 该页数据在数据库中的起始位置 *@param totalSize 数据库中包含的记录总数 *@pageSize 本页能容纳的记录数 */ public RowSetPage(RowSet crs, int start, int totalSize, int pageSize) { try{ int avaCount=0; if (crs!=null) { crs.beforeFirst(); if (crs.next()){ crs.last(); avaCount = crs.getRow(); } crs.beforeFirst(); } rs = crs; super.init(start,avaCount,totalSize,pageSize,rs); }catch(java.sql.SQLException sqle){ throw new RuntimeException(sqle.toString()); } } /** *取分页对象中的记录数据 */ public javax.sql.RowSet getRowSet(){ return rs; } } /////////////////////////////////// // // PagedStatement.java // author: evan_zhao@hotmail.com // /////////////////////////////////// package page; import foo.DBUtil; import java.math.BigDecimal; import java.util.List; import java.util.Iterator; import java.util.Collections; import java.sql.Connection; import java.sql.SQLException; import java.sql.ResultSet; import java.sql.Statement; import java.sql.PreparedStatement; import java.sql.Timestamp; import javax.sql.RowSet; /** * Title: 分页查询 * Description: 根据查询语句和页码查询出当页数据 Copyright: Copyright (c) 2002 public abstract class PagedStatement { public final static int MAX_PAGE_SIZE = Page.MAX_PAGE_SIZE; protected String countSQL, querySQL; protected int pageNo,pageSize,startIndex,totalCount; protected javax.sql.RowSet rowSet; protected RowSetPage rowSetPage; private List boundParams; /** * 构造一查询出所有数据的PageStatement * @param sql query sql */ public PagedStatement(String sql){ this(sql,1,MAX_PAGE_SIZE); } /** * 构造一查询出当页数据的PageStatement * @param sql query sql * @param pageNo 页码 */ public PagedStatement(String sql, int pageNo){ this(sql, pageNo, Page.DEFAULT_PAGE_SIZE); } /** * 构造一查询出当页数据的PageStatement,并指定每页显示记录条数 * @param sql query sql * @param pageNo 页码 * @param pageSize 每页容量 */ public PagedStatement(String sql, int pageNo, int pageSize){ this.pageNo = pageNo; this.pageSize = pageSize; this.startIndex = Page.getStartOfAnyPage(pageNo, pageSize); this.boundParams = Collections.synchronizedList(new java.util.LinkedList()); this.countSQL = \"select count(*) from ( \" + sql +\") \"; this.querySQL = intiQuerySQL(sql, this.startIndex, pageSize); } /** *生成查询一页数据的sql语句 *@param sql 原查询语句 *@startIndex 开始记录位置 *@size 需要获取的记录数 */ protected abstract String intiQuerySQL(String sql, int startIndex, int size); /** *使用给出的对象设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param obj 包含参数值的对象 */ public void setObject(int index, Object obj) throws SQLException{ BoundParam bp = new BoundParam(index, obj); boundParams.remove(bp); boundParams.add( bp); } /** *使用给出的对象设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param obj 包含参数值的对象 *@param targetSqlType 参数的数据库类型 */ public void setObject(int index, Object obj, int targetSqlType) throws SQLException{ BoundParam bp = new BoundParam(index, obj, targetSqlType); boundParams.remove(bp); boundParams.add(bp ); } /** *使用给出的对象设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param obj 包含参数值的对象 *@param targetSqlType 参数的数据库类型(常量定义在java.sql.Types中) *@param scale 精度,小数点后的位数 * (只对targetSqlType是Types.NUMBER或Types.DECIMAL有效,其它类型则忽略) */ public void setObject(int index, Object obj, int targetSqlType, int scale) throws SQLException{ BoundParam bp = new BoundParam(index, obj, targetSqlType, scale) ; boundParams.remove(bp); boundParams.add(bp); } /** *使用给出的字符串设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param str 包含参数值的字符串 */ public void setString(int index, String str)throws SQLException{ BoundParam bp = new BoundParam(index, str) ; boundParams.remove(bp); boundParams.add(bp); } /** *使用给出的字符串设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param timestamp 包含参数值的时间戳 */ public void setTimestamp(int index, Timestamp timestamp)throws SQLException{ BoundParam bp = new BoundParam(index, timestamp) ; boundParams.remove(bp); boundParams.add( bp ); } /** *使用给出的整数设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param value 包含参数值的整数 */ public void setInt(int index, int value)throws SQLException{ BoundParam bp = new BoundParam(index, new Integer(value)) ; boundParams.remove(bp); boundParams.add( bp ); } /** *使用给出的长整数设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param value 包含参数值的长整数 */ public void setLong(int index, long value)throws SQLException{ BoundParam bp = new BoundParam(index, new Long(value)) ; boundParams.remove(bp); boundParams.add( bp ); } /** *使用给出的双精度浮点数设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param value 包含参数值的双精度浮点数 */ public void setDouble(int index, double value)throws SQLException{ BoundParam bp = new BoundParam(index, new Double(value)) ; boundParams.remove(bp); boundParams.add( bp); } /** *使用给出的BigDecimal设置指定参数的值 *@param index 第一个参数为1,第二个为2,。。。 *@param bd 包含参数值的BigDecimal */ public void setBigDecimal(int index, BigDecimal bd)throws SQLException{ BoundParam bp = new BoundParam(index, bd ) ; boundParams.remove(bp); boundParams.add( bp); } private void setParams(PreparedStatement pst) throws SQLException{ if (pst==null || this.boundParams==null || this.boundParams.size()==0 ) return ; BoundParam param; for (Iterator itr = this.boundParams.iterator();itr.hasNext();){ param = (BoundParam) itr.next(); if (param==null) continue; if (param.sqlType == java.sql.Types.OTHER){ pst.setObject(param.index, param.value); }else{ pst.setObject(param.index, param.value, param.sqlType, param.scale); } } } /** * 执行查询取得一页数据,执行结束后关闭数据库连接 * @return RowSetPage * @throws SQLException */ public RowSetPage executeQuery() throws SQLException{ System.out.println(\"executeQueryUsingPreparedStatement\"); Connection conn = DBUtil.getConnection(); PreparedStatement pst = null; ResultSet rs = null; try{ pst = conn.prepareStatement(this.countSQL); setParams(pst); rs =pst.executeQuery(); if (rs.next()){ totalCount = rs.getInt(1); } else { totalCount = 0; } rs.close(); pst.close(); if (totalCount < 1 ) return RowSetPage.EMPTY_PAGE; pst = conn.prepareStatement(this.querySQL); System.out.println(querySQL); pst.setFetchSize(this.pageSize); setParams(pst); rs =pst.executeQuery(); //rs.setFetchSize(pageSize); this.rowSet = populate(rs); rs.close(); rs = null; pst.close(); pst = null; this.rowSetPage = RowSetPage(this.rowSet,startIndex,totalCount,pageSize); return this.rowSetPage; }catch(SQLException sqle){ //System.out.println(\"executeQuery SQLException\"); sqle.printStackTrace(); throw sqle; }catch(Exception e){ e.printStackTrace(); new throw new RuntimeException(e.toString()); }finally{ //System.out.println(\"executeQuery finally\"); DBUtil.close(rs, pst, conn); } } /** *将ResultSet数据填充进CachedRowSet */ protected abstract RowSet populate(ResultSet rs) throws SQLException; /** *取封装成RowSet查询结果 *@return RowSet */ public javax.sql.RowSet getRowSet(){ return this.rowSet; } /** *取封装成RowSetPage的查询结果 *@return RowSetPage */ public RowSetPage getRowSetPage() { return this.rowSetPage; } /** *关闭数据库连接 */ public void close(){ //因为数据库连接在查询结束或发生异常时即关闭,此处不做任何事情 //留待扩充。 } private class BoundParam { int index; Object value; int sqlType; int scale; public BoundParam(int index, Object value) { this(index, value, java.sql.Types.OTHER); } public BoundParam(int index, Object value, int sqlType) { this(index, value, sqlType, 0); } public BoundParam(int index, Object value, int sqlType, int scale) { this.index = index; this.value = value; this.sqlType = sqlType; this.scale = scale; } public boolean equals(Object obj){ if (obj!=null && this.getClass().isInstance(obj)){ BoundParam bp = (BoundParam)obj; if (this.index==bp.index) return true; } return false; } } } /////////////////////////////////// // // PagedStatementOracleImpl.java // author: evan_zhao@hotmail.com // /////////////////////////////////// package page; import java.sql.ResultSet; import java.sql.SQLException; import javax.sql.RowSet; import oracle.jdbc.rowset.OracleCachedRowSet; /** * Title: 分页查询Oracle数据库实现 * Copyright: Copyright (c) 2002 public class PagedStatementOracleImpl extends PagedStatement { /** * 构造一查询出所有数据的PageStatement * @param sql query sql */ public PagedStatementOracleImpl(String sql){ super(sql); } /** * 构造一查询出当页数据的PageStatement * @param sql query sql * @param pageNo 页码 */ public PagedStatementOracleImpl(String sql, int pageNo){ super(sql, pageNo); } /** * 构造一查询出当页数据的PageStatement,并指定每页显示记录条数 * @param sql query sql * @param pageNo 页码 * @param pageSize 每页容量 */ public PagedStatementOracleImpl(String sql, int pageNo, int pageSize){ super(sql, pageNo, pageSize); } /** *生成查询一页数据的sql语句 *@param sql 原查询语句 *@startIndex 开始记录位置 *@size 需要获取的记录数 */ protected String intiQuerySQL(String sql, int startIndex, int size){ StringBuffer querySQL = new StringBuffer(); if (size != super.MAX_PAGE_SIZE) { querySQL.append(\"select * from (select my_table.*,rownum as my_rownum from(\") .append( sql) .append(\") my_table where rownum<\").append(startIndex + size) .append(\") where my_rownum>=\").append(startIndex); } else { querySQL.append(\"select * from (select my_table.*,rownum as my_rownum from(\") .append(sql) .append(\") my_table \") .append(\") where my_rownum>=\").append(startIndex); } return querySQL.toString(); } /** *将ResultSet数据填充进CachedRowSet */ protected RowSet populate(ResultSet rs) throws SQLException{ OracleCachedRowSet ocrs = new OracleCachedRowSet(); ocrs.populate(rs); return ocrs; } } 相关连接: JSP页面查询显示常用模式,介绍查询结果集封装的几种常用模式。本程序使用了其中部分代码 RowSet规范原来是JDBC(TM) 2.0 Optional Package的一部分,现在已经并入JDBC3.0规范,并且将成为J2SE1.5的组成部分。 关于RowSet的实现各个数据库的jdbc driver应该都有提供,oracle实现可以到http://otn.oracle.com/software/tech/java/sqlj_jdbc/content.html下载(Additional RowSet support) Sun也提供了RowSet的参考实现,应该可以支持大多数数据库:http://java.sun.com/products/jdbc/download.html PetStore 是Sun关于J2EE设计模式的一个示例程序。 版权声明 给作者写信 本篇文章对您是否有帮助? 投票: 是 否 投票结果: 作者其它文章: 因篇幅问题不能全部显示,请点此查看更多更全内容 <%代码 姓名 <%<%= emp.getEmpCode()%> <%= emp.getRealName()%>
4. <%代码 姓名 <%<%=colMap.get(“EMP_CODE”)%> <%=colMap.get(“REAL_NAME”)%> <%代码 姓名 <%<%= empRS.get(“EMP_CODE”)%> <%= empRS.get(“REAL_NAME”)%>
* Copyright: Copyright (c) 2002
* @author evan_zhao@hotmail.com
* @version 1.0 */ \\n\")
\\n\"); \\n\") \\n\")
\\n\"); \\n\"); if (hasPreviousPage()){