java分页

来源:互联网 发布:欢乐购接单软件下载 编辑:程序博客网 时间:2024/05/17 00:53
 

////////////////////////////////////////////////////在struts中分页的一种实现////////////////////////////////////////////////////

 
          $$$$$$$$$$$$$$$在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<totalRowsAmount){
pageEndRow=currentPage*pageSize;
pageStartRow=pageEndRow-pageSize+1;

}else{
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",queryForm);
session.setAttribute("pageController",service.getPageController());

request.setAttribute("queryResult",result);
request.setAttribute("pageController",service.getPageController());
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",result);
request.setAttribute("pageController",pc);

//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中,翻页部分的代码片断

<bean:write name="pageController" property="description"/>

<logic:equal name="pageController" property="hasPrevious" value="true">
<a pageController" property="previousPage"/>" class="a02">
Previous
</a>
</logic:equal>

<logic:equal name="pageController" property="hasNext" value="true">
<a pageController" property="nextPage"/>" class="a02">
Next
</a>
</logic:equal>

 

这样一来,翻页的功能可以以你喜欢的方式表现给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;
%>

<table  cellspacing="0" width=”90%”>
    <tr>  <td>代码</td> <td>姓名</td>  </tr>
<%
  Employee emp;
  for (int i=0; i< empList.size(); i++){
    emp = (Employee) empList.get(i);
%>
    <tr> 
      <td><%= emp.getEmpCode()%></td>
      <td><%= emp.getRealName()%></td> 
    </tr>
<%
  }// end for
%>
</table>


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",rs.getString("Field1"));
map.put("Field2",rs.getString("Field2"));
*****
map.put("fieldn",rs.getString("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",rs.getString("rs"));
}/*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;
%>

<table  cellspacing="0" width=”90%”>
    <tr>  <td>代码</td> <td>姓名</td>  </tr>
<%
  Map colMap;
  for (int i=0; i< empList.size(); i++){
    colMap = (Map) empList.get(i);
%>
  <tr> 
    <td><%=colMap.get(“EMP_CODE”)%></td>
    <td><%=colMap.get(“REAL_NAME”)%></td> 
  </tr>
<%
  }// end for
%>
</table>


4.
    使用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”);
%>

<table  cellspacing="0" width=”90%”>
    <tr>  <td>代码</td> <td>姓名</td>  </tr>
<%
  if (empRS != null) while (empRS.next() ) {
%>
  <tr> 
    <td><%= empRS.get(“EMP_CODE”)%></td>
    <td><%= empRS.get(“REAL_NAME”)%></td> 
  </tr>
<%
  }// end while
%>
</table>


适用场合:
  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",rs.getString("Field1"));
map.put("Field2",rs.getString("Field2"));
*****
map.put("fieldn",rs.getString("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",rs.getString("rs"));
}/*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", myBean.getEmployee(gender, pageNo) );
    …

    //JSP显示部分代码
<%@ page import = "page.RowSetPage"%>
    …
    <script language="javascript">
        function doQuery(){
            form1.actionType.value="doQuery";
            form1.submit();
    }
    </script>
    …
    <form name=form1 method=get>
      <input type=hidden name=actionType>
      性别:
      <input type=text name=gender size=1 value="<%=request.getParameter("gender")%>">
      <input type=button value=" 查询 " onclick="doQuery()">
<%
    RowSetPage empPage = (RowSetPage)request.getAttribute("empPage");
    if (empPage == null ) empPage = RowSetPage.EMPTY_PAGE;
%>
    …
    <table  cellspacing="0" width="90%">
        <tr>  <td>ID</td> <td>代码</td> <td>用户名 </td> <td>姓名</td>  </tr>
<%
    javax.sql.RowSet empRS = (javax.sql.RowSet) empPage.getRowSet();
    if (empRS!=null) while (empRS.next() ) {
%>
        <tr>  
            <td><%= empRS.getString("EMP_ID")%></td> 
            <td><%= empRS.getString("EMP_CODE")%></td>  
            <td><%= empRS.getString("USER_NAME")%></td> 
            <td><%= empRS.getString("REAL_NAME")%></td>  
        </tr>
<%
    }// end while
%>
        <tr>
<%
    //显示总页数和当前页数(pageno)以及分页代码。
    //此处doQuery为页面上提交查询动作的javascript函数名, pageno为标识当前页码的参数名
%>
            <td colspan=4><%= empPage .getHTML("doQuery", "pageno")%></td>
        </tr>
    </table>
    </form>

  效果如图:


  因为分页显示一般都会伴有查询条件和查询动作,页面应已经有校验查询条件和提交查询的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.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: 分页对象<br>
 * Description:  用于包含数据及分页信息的对象<br>
 *                Page类实现了用于显示分页信息的基本方法,但未指定所含数据的类型,
 *               可根据需要实现以特定方式组织数据的子类,<br>
 *                如RowSetPage以RowSet 封装数据,ListPage以List封装数据<br>
 * Copyright:    Copyright (c) 2002 <br>
 * @author evan_zhao@hotmail.com <br>
 * @version 1.0
 */
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()<this.getTotalPageCount());
    }

    /**
     * 是否有上一页
     * @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 "<input type='hidden' name='"+pageNoParamName+"' value='1' >";
        }
        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("<script language=\"Javascript1.2\">\n")
             .append("function ").append(gotoPage).append("(pageNo){  \n")
             .append(  "   var curPage=1;  \n")
             .append(  "   try{ curPage = document.all[\"")
             .append(pageNoParamName).append("\"].value;  \n")
             .append(  "        document.all[\"").append(pageNoParamName)
             .append("\"].value = pageNo;  \n")
             .append(  "        ").append(queryJSFunctionName).append("(pageNo); \n")
             .append(  "        return true;  \n")
             .append(  "   }catch(e){ \n")
//             .append(  "      try{ \n")
//             .append(  "           document.forms[0].submit();  \n")
//             .append(  "      }catch(e){   \n")
             .append(  "          alert('尚未定义查询方法:function ")
             .append(queryJSFunctionName).append("()'); \n")
             .append(  "          document.all[\"").append(pageNoParamName)
             .append("\"].value = curPage;  \n")
             .append(  "          return false;  \n")
//             .append(  "      }  \n")
             .append(  "   }  \n")
             .append(  "}")
             .append(  "</script>  \n")
             .append(  "");
        html.append( "<table  border=0 cellspacing=0 cellpadding=0 align=center width=80%>  \n")
             .append( "  <tr>  \n")
             .append( "    <td align=left><br>  \n");
        html.append(  "       共" ).append( getTotalPageCount() ).append( "页")
             .append(  "       [") .append(getStart()).append("..").append(getEnd())
             .append("/").append(this.getTotalSize()).append("]  \n")
             .append( "    </td>  \n")
             .append( "    <td align=right>  \n");
        if (hasPreviousPage()){
             html.append( "[<a href='javascript:").append(gotoPage)
             .append("(") .append(getCurrentPageNo()-1) 
             .append( ")'>上一页</a>]   \n");
        }
        html.append(  "       第")
             .append(   "        <select name='")
             .append(pageNoParamName).append("' onChange='javascript:")
             .append(gotoPage).append("(this.value)'>\n");
        String selected = "selected";
        for(int i=1;i<=getTotalPageCount();i++){
            if( i == getCurrentPageNo() )
                 selected = "selected";
            else selected = "";
            html.append( "      <option value='").append(i).append("' ")
              .append(selected).append(">").append(i).append("</option>  \n");
        }
        if (getCurrentPageNo()>getTotalPageCount()){
            html.append( "      <option value='").append(getCurrentPageNo())
            .append("' selected>").append(getCurrentPageNo())
            .append("</option>  \n");
        }
        html.append( "    </select>页  \n");
        if (hasNextPage()){
             html.append( "    [<a href='javascript:").append(gotoPage)
               .append("(").append((getCurrentPageNo()+1)) 
               .append( ")'>下一页</a>]   \n");
        }
        html.append( "</td></tr></table>  \n");

        return html.toString();

    }
}

 


///////////////////////////////////
//
//  RowSetPage.java
//  author: evan_zhao@hotmail.com
//
///////////////////////////////////
package page;

import javax.sql.RowSet;


/**
 * <p>Title: RowSetPage</p>
 * <p>Description: 使用RowSet封装数据的分页对象</p>
 * <p>Copyright: Copyright (c) 2003</p>
 * @author evan_zhao@hotmail.com
 * @version 1.0
 */

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;

/**
 * <p>Title: 分页查询</p>
 * <p>Description: 根据查询语句和页码查询出当页数据</p>
 * <p>Copyright: Copyright (c) 2002</p>
 * @author evan_zhao@hotmail.com
 * @version 1.0
 */
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 = new 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();
            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;

/**
 * <p>Title: 分页查询Oracle数据库实现</p>
 * <p>Copyright: Copyright (c) 2002</p>
 * @author evan_zhao@hotmail.com
 * @version 1.0
 */
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设计模式的一个示例程序。

版权声明   给作者写信  本篇文章对您是否有帮助?  投票: 是    否     投票结果:       
 
 
 
作者其它文章:
JSP页面查询显示常用模式
使用jsp实现word、excel格式报表打印
作者全部文章 
 
 
  评论人:sun2bin    参与分: 108672    专家分: 985    来自: http://www.nju.edu.cn
 发表时间: 2003-09-06 09:31 
在我的印象里面,Oracle中如果使用where rownum > xxx的话将会一条记录也不返回。一般只使用rownum<xxx或rownum<=xxx。 
 
  评论人:sun2bin    参与分: 108672    专家分: 985    来自: http://www.nju.edu.cn
 发表时间: 2003-09-06 09:32 
对不起,看错了。:P 
 
  评论人:calmness    参与分: 3    专家分: 0  发表时间: 2003-09-08 22:12 
若使用EJB的CMP来获得大的查询结果,该如何控制呢 
 
  评论人:evan    参与分: 47686    专家分: 375    来自: Shanghai
 发表时间: 2003-09-09 09:17 
千万不要这么做,效率极其低下 
 
  评论人:mmgg    参与分: 49    专家分: 0  发表时间: 2003-09-11 10:19 
这是我写的测试代码,为什么只能看第一页,不能翻到第二页!
<%@ page import = "page.*"%>
<script language="javascript">
    function doQuery(){
        form1.actionType.value="doQuery";
        form1.submit();   
        }   
</script>
<form name=form1 method=get>
<input type=hidden name=actionType>
性别:<input type=text name=gender size=1 value="<%=request.getParameter("gender")%>">
<input type=button value=" 查询 " onclick="doQuery()">
</form>
<%! int pageNo;%>
<%

try{        //可以通过参数pageno获得用户选择的页码       
pageNo = Integer.parseInt(request.getParameter("pageno") );    }catch(Exception ex){       
//默认为第一页       
pageNo=1;   
}
String sql="select xh,xm,nsrsbh,nsrmc from fl_cjzgjcd";    //使用Oracle数据库的分页查询实现,每页显示5条

PagedStatement pst =new PagedStatementOracleImpl(sql,  pageNo, 3);       
//pst.setString(1, gender);
RowSetPage empPage = pst.executeQuery();

if (empPage == null )
empPage = RowSetPage.EMPTY_PAGE;
%>
<table  cellspacing="0" width="90%">
< tr> <td>ID</td> <td>代码</td>  <td>用户名</td> <td>姓名</td>  < /tr>
<%    javax.sql.RowSet empRS = (javax.sql.RowSet) empPage.getRowSet();
if (empRS!=null) while (empRS.next() ) {
%>       
<tr>
<td><%= empRS.getString("XH")%></td>
<td><%= empRS.getString("XM")%></td>
<td><%= empRS.getString("NSRSBH")%></td>
<td><%= empRS.getString("NSRMC")%></td>
</tr><%    }
// end while
%>       
<tr>
< %    //显示总页数和当前页数(pageno)以及分页代码。     //此处doQuery为页面上提交查询动作的javascript函数名,pageno为标识当前页码的参数名
%>           
<td colspan=4><%= empPage.getHTML("doQuery", "pageno")
%>
</td>       
</tr>   
</table> 
 
  评论人:mmgg    参与分: 49    专家分: 0  发表时间: 2003-09-11 11:08 
OK了,你的代码中有个小问题!</form>应该是在</table>的后边,否则无法传递pageno参数给页面! 
 
  评论人:evan    参与分: 47686    专家分: 375    来自: Shanghai
 发表时间: 2003-09-11 12:21 
谢谢!

jsp代码中不要这么申明:<%! int pageNo;%>,因为这样pageNo是servlet成员变量,会存在多线程问题 
 
  评论人:eppen    参与分: 21    专家分: 5  发表时间: 2003-09-11 12:59 
网上还有一个比较好的分页方法

http://tech.163.com/tm/030407/030407_89186.html
 
 
  评论人:mmgg    参与分: 49    专家分: 0  发表时间: 2003-09-12 13:28 
明白了,evan,期待您的下一篇文章! 
 
  评论人:mmgg    参与分: 49    专家分: 0  发表时间: 2003-09-12 16:44 
evan,每次查询都要连接一次数据库是否影响效率,我看到的其他的代码大都是连接数据库后将连接放到session中,下次用的时候取出,不知道你是怎么考虑的? 
 
  评论人:evan    参与分: 47686    专家分: 375    来自: Shanghai
 发表时间: 2003-09-16 21:29 
如果连接保存在session中什么时候关闭?如果用户很多也会有问题吧?
一般解决方法是使用连接池,大多应用服务器或web framework都支持,自己写一个也不难
 
 
  评论人:freedomlinux    参与分: 36    专家分: 0  发表时间: 2003-10-10 10:16 
there are a little problem in  JavaScript of "Page.java" .the writer use "document.all" ,but not "document.getElementById".so another browser (i.e mozilla) can not browse it.i correct the javaScript in it.
so the linux user can browse it smoothly,here is the code.
///////////////////////////////////////////////////////////////
    public String getHTML(String queryJSFunctionName, String pageNoParamName){
        if (getTotalPageCount()<1){
            return "<input type='hidden' name='"+pageNoParamName+"' value='1' >";
        }
        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("<script language=\"Javascript1.2\">\n")
             .append("function ").append(gotoPage).append("(pageNo){  \n")
             .append(  "   var curPage=1;  \n")
             .append(  "   try{ curPage = document.getElementById(\"")
             .append("select_id").append("\").value;  \n")
             .append(  "        document.getElementById(\"").append("select_id")
             .append("\").value = pageNo;  \n")
             .append(  "        ").append(queryJSFunctionName).append("(pageNo); \n")
             .append(  "        return true;  \n")
             .append(  "   }catch(e){ \n")
//             .append(  "      try{ \n")
//             .append(  "           document.forms[0].submit();  \n")
//             .append(  "      }catch(e){   \n")
              . append(  "           alert('Not define inquiry method : function ")
             .append(queryJSFunctionName).append("()'); \n")
             .append(  "          document.getElementById(\"").append("select_id")
             .append("\").value = curPage;  \n")
             .append(  "          return false;  \n")
//             .append(  "      }  \n")
             .append(  "   }  \n")
             .append(  "}")
             .append(  "</script>  \n")
             .append(  "");
        html.append( "<table  border=0 cellspacing=0 cellpadding=0 align=center width=80%>  \n")
             .append( "  <tr>  \n")
             .append( "    <td align=left><br>  \n");
         html.append(  "        共" ).append(  getTotalPageCount() ).append("页")
             .append(  "       [") .append(getStart()).append("..").append(getEnd())
             .append("/").append(this.getTotalSize()).append("]  \n")
             .append( "    </td>  \n")
             .append( "    <td align=right>  \n");
        if (hasPreviousPage()){
             html.append( "[<a href='javascript:").append(gotoPage)
             .append("(") .append(getCurrentPageNo()-1)
              . append( ")'>上一页</a>]   \n");
        }
        html.append(  "       第")
             .append(   "        <select name='")
             .append(pageNoParamName).append("' id='select_id'").append(" onChange='javascript:")
             .append(gotoPage).append("(this.value)'>\n");
        String selected = "selected";
        for(int i=1;i<=getTotalPageCount();i++){
            if( i == getCurrentPageNo() )
                 selected = "selected";
            else selected = "";
            html.append( "      <option value='").append(i).append("' ")
              .append(selected).append(">").append(i).append("</option>  \n");
        }
        if (getCurrentPageNo()>getTotalPageCount()){
            html.append( "      <option value='").append(getCurrentPageNo())
            .append("' selected>").append(getCurrentPageNo())
            .append("</option>  \n");
        }
        html.append( "    </select>页  \n");
        if (hasNextPage()){
             html.append( "    [<a href='javascript:").append(gotoPage)
               .append("(").append((getCurrentPageNo()+1))
                 .append( ")'>下一页</a>]   \n");
        }
        html.append( "</td></tr></table>  \n");

        return html.toString();

    }
////////////////////////////////////////////////////////////////////////
Don't use document.all

I've lost count of the number of Javascript scripts I've seen floating around that include the equivalent of the following code snippet:

if (document.all) {
   element = document.all[id];
else {
   element = document.getElementById(id);
}

document.all was introduced in Internet Explorer 4, because the W3C DOM hadn't yet standardised a way of grabbing references to elements using their ID. By the time IE 5 came out, document.getElementById() had been standardised and as a result, IE 5 included support for it.

IE 5 was released in September 1998. A popular browser statistics site (insert usual disclaimer as to the reliability of any stats but your own here) show IE 4's market share to be in the region of 1%. Even Netscape 4 has more users than that!

Don't use document.all. document.getElementById() is supported by every Javascript supporting browser released since 1998. 
 
客人: michaellhj  发表时间: 2003-11-20 13:07 
你好,记得你在JavaResearchOrganization上发过的帖子:”JSP分页技术实现“吗?


我看过后觉得很不错,决定采用你的方法了。首先注明的是我是新手,希望一些很低级的问题和错误请你原谅。

我是用websphere
 
 
 
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

          $$$$$$$$$$$$$$$$解决MVC下分页显示的问题

 

  前几天做一个系统,用到的是Tomcat+struts+Mysql的MVC框架。由于很多模块都需要分页,网上很多方法都不是很适合,自己想写一个分页的方法,让所有的模块都能够使用,好不容易花了几天把问题给搞清楚了,觉得还是写些东西跟大家分享一下。如果那位有更好的方法的话,咱们共同探讨一下,让更多的人有所收获。在写这个代码的时候参考了网友evan_zhao的意见(http://www.javaresearch.org/article/showarticle.jsp?column=106&thread=8893). 他说常见的方法每次翻页都查询一次数据库,从ResultSet中只取出一页数据(使用rs.last();rs.getRow()获得总计录条数,使用 rs.absolute()定位到本页起始记录)。这种方式在某些数据库(如oracle)的JDBC实现中差不多也是需要遍历所有记录,实验证明在记录数很大时速度非常慢。
  至于缓存结果集ResultSet的方法则完全是一种错误的做法。因为ResultSet在Statement或Connection关闭时也会被关闭,如果要使ResultSet有效势必长时间占用数据库连接。
  因此比较好的分页做法应该是每次翻页的时候只从数据库里检索页面大小的块区的数据。这样虽然每次翻页都需要查询数据库,但查询出的记录数很少,网络传输数据量不大,如果使用连接池更可以略过最耗时的建立数据库连接过程。而在数据库端有各种成熟的优化技术用于提高查询速度,比在应用服务器层做缓存有效多了。

所以我用到了从数据库中查询当前页面记录的办法。由于设计到公司核心代码的缘故,我就简单的用一个图书的例子介绍一下是我的思路:
一 开发思路:
      我是用Struts的,当然就要使用到MVC这个模式,分页的时候也是这样的。
        首先要有一个和数据库链接的bean,我们暂时叫DBUtil吧,这里面封装了很多和数据库有关的东西,比如有查询,修改,插入等方法,这是一个基本的类,这里我们用到的是查询,这个方法返回的数据类型是Object[][]。这里大家要注意一下,你也可以返回别的类型,但是一定要注意把后面对应的程序也修改一下。一下是这个类的部分代码:
package com.model;

import com.attribute.Constants;

import java.sql.*;
import java.util.*;


/**
 * Created by IntelliJ IDEA.
 * User: 7612CE
 * Date: 2005-6-2
 * Time: 21:41:38
 * To change this template use Options | File Templates.
 */
public class DBUtil {

    String sDBDriver=Constants.DBDriver;
    String url=Constants.DBUrl;
    String dbUser=Constants.DBUser;
    String dbPassword=Constants.DBPassword;
    Connection conn=null;
    PreparedStatement stmt=null;
    ResultSet rs=null;

    public DBUtil()throws ClassNotFoundException{
        try{
            Class.forName(sDBDriver);
            conn=DriverManager.getConnection(url,dbUser,dbPassword);
        }catch(Exception e){
           System.out.println("DBUtil():"+e.getMessage());
        }
    }
/**
     * Search some record in object table
     * @param sql sql segment
     * @ param map values for match
     * @return Collection
     */
    public Object[][] doSearch(String sql,Object [] data)throws SQLException{
        PreparedStatement stmt = conn.prepareStatement(sql);
        for(int i=0;data!=null&&i<data.length;i++){
            System.out.print("the aql is ="+sql);
            System.out.println("data is " + data[i]);
            stmt.setObject(i+1,data[i]);
        }
        ResultSet rset = stmt.executeQuery();
        ResultSetMetaData rsm = rset.getMetaData();
        int col = rsm.getColumnCount();
        ArrayList list = new ArrayList();
        //Each element of list contains a record of resultset
        while(rset.next()){
            list.add(getLine(rset,col));
        }

        if(list.size()==0||col==0){
            closePrepStmt();
            return null;
        }

        closePrepStmt();
        //Construct box as a data matrix
        Object[][] box = new Object[list.size()][col];
        for(int i=0;i<list.size();i++)
            for(int j=0;j<col;j++)
            {
                box[i][j] =((Object[])list.get(i))[j];
            }
            return box;
    }
  由于是写分页的,当然也是要有一个page的类,具体代码如下,由于有很多注释,不用一一介绍了:
package com.util;

    /**
     * Title: 分页对象<br>
     * Description:  用于包含数据及分页信息的对象<br>
     *Page类实现了用于显示分页信息的基本方法,但未指定所含数据的类型,
     *可根据需要实现以特定方式组织数据的子类,<br>
     *如RowSetPage以RowSet封装数据,ListPage以List封装数据<br>
     * Copyright:    Copyright (c) 2002 <br>
     * @author evan_zhao@hotmail.com <br>
     * @version 1.0
     */
    public  class Page implements java.io.Serializable {
        public static final Page EMPTY_PAGE = new Page();
        public static final int  DEFAULT_PAGE_SIZE = 2;
        public static final  int MAX_PAGE_SIZE = 2;

        private int myPageSize = DEFAULT_PAGE_SIZE;

        private int start;
        private int avaCount,totalSize;
        private Object[][] data=null;

        private int currentPageno;
        private int totalPageCount;

        /**
         * 默认构造方法,只构造空页
         */
       public Page(){
            this.init(0,0,0,DEFAULT_PAGE_SIZE,null);
    }
        /**
              *构造分页对象
             *@param crs 包含一页数据的OracleCachedRowSet
               *@param start 该页数据在数据库中的起始位置
              *@param totalSize 数据库中包含的记录总数
             *@param pageSize 本页能容纳的记录数
             */
             public Page(Object[][] crs, int start, int totalSize, int pageSize) {
                 try{
                     int avaCount=0;
                     if (crs!=null) {
                             avaCount = crs.length;
                     }
                     data = crs;
                     this.init(start,avaCount,totalSize,pageSize,data);
                 }catch(Exception ex){
                     throw new RuntimeException(ex.toString());
                 }
             }

    /**
         * 分页数据初始方法
         * @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()<this.getTotalPageCount());
        }

        /**
         * 是否有上一页
         * @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;
        }

    }
  由于是用mvc这样的框架,所以在c这一层仅仅起到一个转向和收集页面信息的作用,所以这里我有写了一个分页查询的bean,暂时命名是PageCtBean,代码如下:
 package com.util;

import com.model.DBUtil;
import java.sql.*;
/**
 * Created by IntelliJ IDEA.
 * User: 7612ce
 * Date: 2005-6-23
 * Time: 10:36:57
 * To change this template use Options | File Templates.
 */
  public class  PageCtBean {
       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 Page setPage;
        protected Object[][] objTables=null;
        protected Object[][] objCount=null;
        protected Object[] obj=null;

       public PageCtBean(){

       }
    /**
         * 构造一查询出所有数据的PageStatement
.         * @param sql  query sql
         */
        public PageCtBean(String sql){
            this(sql,1,MAX_PAGE_SIZE);
    }
    /**
         * 构造一查询出当页数据的PageStatement
         * @param sql  query sql
         * @param pageNo  页码
         */
        public PageCtBean(String sql, int pageNo){
            this(sql, pageNo, Page.DEFAULT_PAGE_SIZE);
        }

        /**
         * 构造一查询出当页数据的PageStatement,并指定每页显示记录条数
         * @param sql query sql
         * @param pageNo 页码
         * @param pageSize 每页容量
         */
        public PageCtBean(String sql, int pageNo, int pageSize){
            this.pageNo = pageNo;
            this.pageSize = pageSize;
            this.startIndex = Page.getStartOfAnyPage(pageNo, pageSize);
            this.querySQL = intiQuerySQL(sql, this.startIndex, pageSize);
        }


      /**
         *生成查询一页数据的sql语句
         *@param sql 原查询语句
         *@ startIndex 开始记录位置
         *@ size 需要获取的记录数
         */
        protected String intiQuerySQL(String sql, int startIndex, int size){
            StringBuffer querySQL = new StringBuffer();
                querySQL.append(sql)
                        .append(" limit ")
                        .append(startIndex-1 )
                        .append(",").append(size);
                return querySQL.toString();
        }

        /**
         *使用给出的对象设置指定参数的值
         *@param obj 包含参数值的对象
         */
        public void setObject(Object obj[]) throws SQLException{
                    this.obj=obj;
                }

        public void setCountSql(String sql){
            this.countSQL=sql;
        }
    /**
         * 执行查询取得一页数据,执行结束后关闭数据库连接
         * @return RowSetPage
.         * @throws SQLException
         */
        public  Page executeQuery() throws ClassNotFoundException{
                   System.out.println("executeQueryUsingPreparedStatement");
                DBUtil DBean=new DBUtil();
                   try{
                    objCount = DBean.doSearch(this.countSQL,obj);
                       if (!objCount.equals(null)){
                        System.out.println("the count is ="+objCount[0][0].toString());
                           totalCount =Integer.parseInt(objCount[0][0].toString()) ;
                           System.out.println("the count is ="+totalCount);
                       } else {
                           totalCount = 0;
                       }
                       if (totalCount < 1 )
                           return null;
                       objTables= DBean.doSearch(this.querySQL,obj);
                    this.setPage = new Page(this.objTables,startIndex,totalCount,pageSize);
                       return this.setPage;
                   }catch(SQLException sqle){
                       //System.out.println("executeQuery SQLException");
                       sqle.printStackTrace();

                   }catch(Exception e){
                       e.printStackTrace();
                       throw new RuntimeException(e.toString());
                   }
           return null;
               }
        /**
         *取封装成Page的查询结果
         *@return Page
   */
        public Page getPage() {
            return this.setPage;
        }
    }
接下来是Action里面的代码,暂时定义这个Action 是ComputerAction,代码如下:
package com.action;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.form.LoginForm;
import com.util.LoginBean;
import com.util.ComputerBean;
import com.util.BaseView;
import com.util.Page;
import com.model.FunctionManager;
import com.attribute.Constants;
import com.attribute.SQLBook;

import java.sql.ResultSet;

/**
 * Created by IntelliJ IDEA.
 * User: 7612CE
 * Date: 2005-6-14
 * Time: 13:31:34
 * To change this template use Options | File Templates.
 */
public class ComputerAction extends BaseAction {
    private Log log=LogFactory.getLog(this.getClass().getName());

     public ActionForward execute(ActionMapping mapping,
                     ActionForm Form,
                     HttpServletRequest request,
                     HttpServletResponse response){
          boolean flag=false;
         Object[][] obj=null;
         Page page=new Page();
         Integer id=new Integer(Constants.id);
         String sql=SQLBook.Computer_select_SQL;
         BaseView view=new BaseView();
         String pageNo = request.getParameter("pageNo");
         if (pageNo == null || pageNo.equals("null") || pageNo.length() <= 0) {
                    pageNo = "1";
                }
         try{
             Object[] table={id};
             ComputerBean computerBean=new ComputerBean();
             computerBean.setBeanDate(sql,table);
             computerBean.setPageNo(pageNo);
             page=computerBean.getResult();
             obj=page.getData();
             if(!obj.equals(null)){
                 flag=true;
                 view.setObject(obj);
                 request.setAttribute(Constants.QUERY_RESULT,view);
                 request.setAttribute("page",page);
             }

         }catch(Exception ex){
             ex.printStackTrace();
         }
         log.info("system print the flag ="+flag);
         if(flag){
           return(mapping.findForward(Constants.FORWARD_SUCCESS));
         }else{
             return(mapping.findForward(Constants.FORWARD_FAILURE));
         }
      }
}
由于Action里面用到了查询的SQL语句,所有SQL语句写在一个特定的类中,这个类名定义为SQLBook,代码如下:
public class SQLBook {

    public SQLBook(){}
/**
     * computer sql
     */

    public static final String Computer_select_SQL=
           "select a.id,a.bookname,a.bookclass,b.classname,"+
           "a.author,a.publish,a.bookno,a.content,a.prince,a.amount,"+
           "a.Leav_number,a.regtime,a.picture from book a,bookclass b"+
           " where a.Bookclass = b.Id and a.bookclass=? "+
           " order by a.Id desc ";
    public static final String Computer_select_count_sql=
            "select count(*) from book a,bookclass b"+
           " where a.Bookclass = b.Id and a.bookclass=? "+
           " order by a.Id desc ";

}
到此为止,基本上分页的代码基本完成,为了使得分页的代码共用,我把他封装成了一个标签,这个方法是参考一个网友的文章上写的,在这里表示感谢。这个自定义的标签命名为PaginatorTag,代码如下:
package com.util;

import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class PaginatorTag extends BodyTagSupport {
    protected Log log = LogFactory.getLog(this.getClass());
//以下是一标签中的一些属性,后面有较详细的介绍
    int currentPage = 1;//当前页码
    String url = "";//转向的地址
    int totalSize = 0;//总的记录数
    int perPage = 20;//每页显示的记录数目
    boolean showTotal = true;//是否显示总数量
    boolean showAllPages = false;//是否显示总页码
    String strUnit ="";//计数单位

    //得到当前页码
    public int getCurrentPage() {
        return currentPage;
    }
    //设置当前页码
    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }
    //得到每页显示记录的数目
    public int getMaxPerPage() {
        return perPage;
    }
    //设置每页显示的记录数目
    public void setMaxPerPage(int perPage) {
        this.perPage = perPage;
    }
    //判断是否显示总的页码数目
    public boolean isShowAllPages() {
        return showAllPages;
    }
    //设置是否显示总的页码数目
    public void setShowAllPages(boolean showAllPages) {
        this.showAllPages = showAllPages;
    }
    //判断是否显示总的记录数目
    public boolean isShowTotal() {
        return showTotal;
    }
    //设置是否显示总的记录数目
    public void setShowTotal(boolean showTotal) {
        this.showTotal = showTotal;
    }
    //得到计数单位
    public String getStrUnit() {
        return strUnit;
    }
    //设置计数单位
    public void setStrUnit(String strUnit) {
        this.strUnit = strUnit;
    }
    //得到总的记录数目
    public int getTotalPut() {
        return totalSize;
    }
    //设置总的记录数目
    public void setTotalPut(int totalSize) {
        this.totalSize = totalSize;
    }
    //得到转向的链接地址
    public String getUrl() {
        return url;
    }
    //设置链接地址
    public void setUrl(String url) {
        this.url = url;
    }
    public int doStartTag() throws JspException {
        return SKIP_BODY;
    }


    public int doEndTag() throws JspException {
        String out = showPage(currentPage, url, totalSize, perPage, showTotal, showAllPages, strUnit);
        try {
            pageContext.getOut().print(out);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return EVAL_PAGE;
    }


    /**
     * 作 用:显示“上一页 下一页”等信息
     *
     * @param url
     *            ----链接地址
     * @ param totalSize
     *            ----总数量
     * @ param perPage
     *            ----每页数量
     * @param showTotal
     *            ----是否显示总数量
     * @param showAllPages
      *             ---是否用下拉列表显示所有页面以供跳转。有某些页面不能使用,否则会出现JS错误。
     * @param strUnit
     *            ----计数单位
     * @return .
     * @ throws IOException
     */
    protected String showPage(int currentPage,String url, int totalSize, int perPage,
            boolean showTotal, boolean showAllPages, String strUnit){
        int n = 0;
        StringBuffer buf = new StringBuffer();
        String strUrl;
        n = (totalSize + perPage -1) / perPage;
        buf.append("<table align='center'><tr><td>");
        if (showTotal == true)
             buf.append ("共 <b>" + totalSize + "</b>  " + strUnit
                    + "  ");
        strUrl = JoinChar(url);
        if (currentPage < 2) {
            buf.append("首页 上一页 ");
        } else {
             buf.append ("<a href='" + strUrl + "pageNo=1' title ='首页'>首页</a> ");
            buf.append("<a href='" + strUrl + "pageNo=" + (currentPage - 1)
                      + "' title='上一页'>上一页 </a> ");
        }
        if (n - currentPage < 1)
            buf.append("下一页 尾页");
        else {
            buf.append("<a href='" + strUrl + "pageNo=" + (currentPage + 1)
                      + "' title='下一页'>下一页 </a> ");
             buf.append("<a href='" + strUrl  + "pageNo=" + n + "' title='尾页'>尾页< /a>");
        }
         buf.append(" 页次:<strong> <font color=red>" + currentPage
                  + "</font>/" + n + "</strong>页  ");
        buf.append("  <b>" + perPage + "</b>" + strUnit  + "/页");
        if (showAllPages == true) {
            buf
                      .append(" 转到:<select  name='page' size='1' onchange=\"javascript:window.location='"
                            + strUrl
                            + "pageNo="
                            + "'+this.options[this.selectedIndex].value;\">");
            for (int i = 1; i <= n; i++) {
                buf.append("<option value='" + i + "'");
                if(currentPage == i)
                    buf.append(" selected ");
                  buf.append(">第" + i + "页< /option>");
            }
            buf.append("</select>");
        }
        buf.append("</td></tr></table>");
        return (buf.toString());
    }


    /**
     *  向地址中加入 ? 或 &
     * @param strUrl
     *            ----网址.
     * @return 加了 ? 或 & 的网址.
     */
    protected String JoinChar(String strUrl) {
        String result = "";
        if (strUrl.equals("") || strUrl.length() <= 0) {
            return result;
        }
        if (strUrl.indexOf("?") < strUrl.length()) {
            if (strUrl.indexOf("?") > -1) {
                if (strUrl.indexOf("&") < strUrl.length()) {
                    result = strUrl + "&";
                } else {
                    result = strUrl;
                }
            } else {
                result = strUrl + "?";
            }
        } else {
            result = strUrl;
        }
        return result;
    }
}
有了自定义标签,当然少不了用于处理标签的tld,我们定义一个swsoft-struts.tld,代码如下:
有了自定义标签,当然少不了用于处理标签的tld,我们定义一个swsoft-struts.tld,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>out</shortname>
<uri>http://www.swsoftware.com/</uri>
<info>Tab Library for PaginatorTag</info>
<tag>
    <name>paginator</name>
    <tagclass>com.swsoftware.tags.PaginatorTag</tagclass>
    <bodycontent>JSP</bodycontent>
    <info>Returns a paginator</info>
    <attribute>
        <name>currentPage</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
        <name>url</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
        <name>totalPut</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
        <name>maxPerPage</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
        <name>showTotal</name>
        <required>true</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
        <name>showAllPages</name>
        <required>true</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
        <name>strUnit</name>
        <required>true</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
</tag>
</taglib>
好了,到现在我们开始来真正看一下jsp中的处理,我们写一个computer.jsp,代码如下:
<%@ page import="com.util.BaseView,
                 com.attribute.Constants,
                 com.util.Page"%>
<%@ page contentType="text/html;charset=GB2312" language="java" errorPage=""%>
<%@ taglib uri="/WEB-INF/swsoft-struts.tld"prefix="swtag"%>
<html>
<head>
<title></title>

</head>
<body bgcolor="#e3edfc">
<div id="Layer1" style="position:absolute; left:1px; top:2px; width:780px; height:406px; z-index:1; background-color: #e3edfc; layer-background-color: #e3edfc; border: 1px none #000000;">
  <table width="100%" cellpadding="1">
    <tr>
      <td colspan="6">
      <table width="100%"  cellpadding="1">
    <tr>
      <td width="20%" align="center">BOOKNAME</td>
      <td width="10%" align="center">AUTHOR</td>
      <td width="10%" align="center">TYPE</td>
      <td width="30%" align="center">PUBLISH</td>
      <td width="10%" align="center">PRINCE</td>
      <td colspan="2" align="center">SELECT</td>
    </tr>
  <%
     String contextPath = request.getContextPath();
     String url=contextPath+"/computer.do";
    BaseView view=(BaseView)request.getAttribute(Constants.QUERY_RESULT);
    Page setpage=(Page)request.getAttribute("page");
    int currentPage=setpage.getCurrentPageNo();
      System.out.println("this is currentPage="+currentPage);
    int totalPut=setpage.getTotalSize();
      System.out.println("this is totalPut="+totalPut);
    int maxPerPage=setpage.getPageSize();
      System.out.println("this is maxPerPage="+maxPerPage);
    if(view.haveRecord()){
        String sBgcolor="";
        int length=view.getRecordCount();
        for(int i=0;i<length;i++){
           String type =view.getValue(i,2);
            if(type.equals("1")){
                type="computer";
            }
            if(i%2!=0){
                sBgcolor="#A5C6EB";
            }
            else{
                sBgcolor="#B7D7EF";
            }
%>
    <tr bgcolor=<%=sBgcolor%> height="10">
      <td align="center" ><%=view.getValue(i,1)%></td>
      <td align="center"><%=view.getValue(i,4)%></td>
      <td align="center"><%=type%></td>
      <td align="center"><%=view.getValue(i,5)%></td>
      <td align="center"><%=view.getValue(i,8)%></td>
      <td width="20%" align="center">BUY PARTICULAR</td>

    </tr>
<%}}%>
  </table>
  </td>
    </tr>

    <tr>
    <swtag:paginator url="<%=url%>"
    currentPage="<%=currentPage%>"
    totalPut="<%=totalPut%>"
    maxPerPage="<%=maxPerPage%>"
    showTotal="true"
    showAllPages="true"
    strUnit="页" />
    </tr>
  </table>
</div>

</body>
</html>
到此为止,分页的类基本完成,这样的话可以在别的模块都可以用这个标签,同时在开发别的系统的时候这个标签也可以使用,具有比较好的可移植性。这个数据库是mysql的,要是oracle的,仅仅在PageCtBean类中的intiQuerySQL方法里面改成
protected String intiQuerySQL(String sql, int startIndex, int size){
            StringBuffer querySQL = new StringBuffer();
            if (size != this.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();
        }
就可以了。
同时在数据库中,返回当前页需要显示的数据,主要有以下方法,。
a.使用mysql控制:
select * from user
order by Host
limit m, n
结果返回的是第m+1行到第n行的数据集。
比如
select * from user
order by Host
limit 1, 5
返回的是第2行到第5行的数据集
b.使用sqlserver
SELECT *
FROM (SELECT TOP m *
        FROM (SELECT TOP n *
                FROM Customers) A
        ORDER BY CustomerID DESC) B
ORDER BY CustomerID
获得的结果集数据为第n-m+1行到第n行。
对整个过程的解释:
首先按照升序得到前n行的结果集A,然后按照降序从A中得到后m行的结果集B,最后按照升序对B进行重新排序,返回结果集。
其中CustomerID为主键
比如:
SELECT *
FROM (SELECT TOP 5 *
        FROM (SELECT TOP 10 *
                FROM Customers) A
        ORDER BY CustomerID DESC) B
ORDER BY CustomerID
的意思就是返回包含第6行到第10行的数据结果集。
c.使用Oracle:
select * from (select rownum r ,* from test) tt
where tt.r > 50 and tt.r <= 100;
希望大家有好方法的话能说一下,大家共同进步.


版权声明   给作者写信  本篇文章对您是否有帮助?  投票: 是    否     投票结果:       
 
 
 
作者其它文章:
在Java中实现浮点数的精确计算
MYSQL和ORACLE的一些操作区别
JDBC常用类和方法
Oracle里时间的应用
Hibernate入门之One To One
作者全部文章 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

          $$$$$$$$$$$$$$$$struts实现分页处理

 

 
在网上看到这个觉的不错 就转过来 和大家一起分享
1.IFormPages接口,每个需要分页的form都继承这个接口:
package com.fellow.pub.servlet;

public interface IFormPages {
  int getCurrentPage();
  void setCurrentPage(int currentPage);
  int getItemPerPage();
  void setItemPerPage(int itemPerPage);
}

2.分页计算类Pages:
package com.fellow.pub.util;

import java.util.Vector;
import java.util.Collection;
import com.fellow.pub.servlet.IFormPages;

public class Pages {
  protected int itemCount;
  protected int itemPerPage;
  protected int currentPage;

  public Pages() {
    this.itemCount = 0;
    this.itemPerPage = 0;
    this.currentPage = 1;
  }

  public Pages(int itemCount, int itemPerPage) {
    this.itemCount = itemCount;
    this.itemPerPage = itemPerPage;
    this.currentPage = 1;
  }

  public Pages(int itemCount, int itemPerPage, int currentPage) {
    this.itemCount = itemCount;
    this.itemPerPage = itemPerPage;
    this.currentPage = currentPage;
  }

  public Pages(Collection collection, IFormPages formPages) {
    this.itemCount = collection.size();
    this.itemPerPage = formPages.getItemPerPage();
    this.currentPage = formPages.getCurrentPage();
  }

  public int getItemCount() {
    return this.itemCount;
  }

  public void setItemCount(int itemCount) {
    this.itemCount = itemCount;
  }

  public int getItemPerPage() {
    return this.itemPerPage;
  }

  public void setItemPerPage(int itemPerPage) {
    this.itemPerPage = itemPerPage;
  }

  public int getCurrentPage() {
    return this.currentPage;
  }

  public void setCurrentPage(int currentPage) {
    this.currentPage = currentPage;
  }

  public int getPrePage(){
    return this.currentPage - 1;
  }

  public int getNextPage(){
    return this.currentPage + 1;
  }

  protected void AssertErrors() throws Exception{
    if(itemPerPage <= 0 ||
       currentPage <= 0 ||
       itemCount < itemPerPage * (currentPage - 1)){
      throw new Exception("Pages object calculated error");
    }
  }

  public int getPageCount() throws Exception{
    if(itemCount <= 0) return 0;
    AssertErrors();
    if(itemCount % itemPerPage == 0){
      return itemCount / itemPerPage;
    }
    else{
      return itemCount / itemPerPage + 1;
    }
  }

  public int getPageItemCount() throws Exception{
    if(itemCount <= 0) return 0;
    int pageCount = getPageCount();

    if(pageCount == currentPage){
      return itemCount -itemPerPage * (currentPage - 1);
    }
    else{
      return itemPerPage;
    }
  }

  public int getPageItemCount(int currentPage) throws Exception{
    if(itemCount <= 0) return 0;
    int pageCount = getPageCount();

    if(pageCount == currentPage){
      return itemCount -itemPerPage * (currentPage - 1);
    }
    else{
      return itemPerPage;
    }
  }

  public boolean isFirstPage() throws Exception{
    return (currentPage == 1);
  }

  public boolean isLastPage() throws Exception{
    int pageCount = getPageCount();
    return (pageCount == currentPage);
  }

  public Collection getIndexList() throws Exception{
    int pageCount = getPageCount();
    Vector result = new Vector(pageCount);
    for(int i = 0; i < pageCount; i++){
      result.add(new Integer(i + 1));
    }
    return result;
  }
}

3.分页集合类CollectionPages,继承Pages:
package com.fellow.pub.util;

import java.util.*;

import com.fellow.pub.servlet.IFormPages;

public class CollectionPages extends Pages {
  protected Collection collection = null;
  protected Collection collectionPage = null;
  public CollectionPages(Collection collection, IFormPages formPages) throws Exception {
    super(collection, formPages);
    this.collection = collection;
    buildCollectionPage();
  }

  public Collection getCollection(){
    return this.collection;
  }

  public void setCollection(Collection collection){
    this.collection = collection;
  }

  public Collection getCollectionPage(){
    return this.collectionPage;
  }

  public Collection buildCollectionPage() throws Exception{
    if(collection == null){
      throw new Exception("collection object is null");
    }

    collectionPage = new Vector(itemPerPage);
    CollectionUtil.copy(collection, collectionPage,
                        (currentPage - 1) * itemPerPage,
                        (currentPage) * itemPerPage);
    return collectionPage;
  }
}

 

4.Action里面初始化:
CollectionPages collectionPages = new CollectionPages(collection, formPages);
其中collection就是需要分页的集合

5.保存到request
setAttribute(name, collectionPages);

6.在页面上使用collectionPages对象,collectionPages对象有两个子对象:
  i.collectionPage,就是分页以后的集合
    <bean:define id="collectionList" name="collectionPages" property="collectionPage" scope="request" />
  ii.indexList就是页码(由于我不知道怎么用简单的方法处理页码,就只好弄这样一个对象来iterate了)
    <bean:define id="indexList" name="collectionPages" property="indexList" scope="request"/>

 

版权声明  本篇文章对您是否有帮助?  投票: 是    否     投票结果:       
 
 
 
作者其它文章:
在webwork2的action里取request.getParameter参数
webwork2在weblogic下和tomcat下的中文问题解决
一个struts+sql server的分页存储过程
作者全部文章 
 
 
  评论人:niyboy    参与分: 300    专家分: 0  发表时间: 2005-05-12 17:33 
你这个分页只能用与少数据的;
如果数据过多肯定会出问题的 
 

这个文章共有 1 条评论,共 1 页 
 
上一篇文章   返回〔开发框架〕 
 下一篇文章 

 
 
 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

          $$$$$$$$$$$$$$$$用标准的SQL语句实现查询记录分页


在绝大多数的应用中,返回大量的符合条件的记录是司空见惯的,最典型的莫过于搜索了。在搜索的应用中,用户给出搜索条件,服务器查出符合条件的记录。但往往搜索会返回大量的数据记录,如果在网页中,往往是通过分页的方式来实现,页面提供诸如上一页,下一页等等按钮来实现分页。
现在主要有以下几中方式来实现分页:
1.EJB的Find方法
2.在显示第一页前将所有的记录放在collection对象中,后续的各页都在内存中取。
3.每一页都到数据库作一次重复的查询,然后将符合条件的记录显示出来。
4.保存前几页的搜索结果在内存中(经常使用到的),后续的记录(这些数据是多数用户都没有耐心看的)再通过连数据库取得。
5.其他各种cache机制。

我们可以根据实际情况来选择适合自己的方法,我给大家介绍一个通过标准的SQL语句来得到符合条件的数据。如从第10到20条的符合条件(where语句中的)的记录。通过这种方法取得记录有一个必要条件,必须有一个能够标识记录顺序的字段,如id,time等等。下面我为大家演示一个例子:
查询t_table表中所有记录第10到20条,按id排序。
SQL语句为:
SELECT * FROM t_table t1 WHERE (SELECT count(*) FROM t_table t2 WHERE t2.id < t1.id ) >= 10 AND (SELECT count(*) FROM t_table t2 WHERE t2.id < t1.id ) < 20

又如查询t_table表中key='123'第10到20条的记录,按id排序。
SELECT * FROM t_table t1 WHERE (SELECT count(*) FROM t_table t2 WHERE t2.id < t1.id AND t2.key = '123') >= 10 AND (SELECT count(*) FROM t_table t2 WHERE t2.id < t1.id AND t2.key = '123') < 20 AND t1.key = '123'

当然条件中的id可以换为任何能表识记录顺序的字段。

版权声明   给作者写信  本篇文章对您是否有帮助?  投票: 是    否     投票结果:       
 
 
 
作者其它文章:
应用服务器性能测试报告
Event Notifier, a Pattern for Event Notification
一种处理大型结果集的设计模式(DataListHandler)
复合设计模式(使用相同方式对待基本和复杂的对象)
使用零长度数组
作者全部文章 
 
 
  评论人:panwen    参与分: 27    专家分: 0  发表时间: 2002-10-28 10:46 
好是好,但是表中记录太多的话性能就很受影响,如果表中的记录有上百万条,光一个count(*)就可能耗去几十分钟。 
 
  评论人:javamonkey    参与分: 67337    专家分: 1082    来自: 北京海淀区三里河
 发表时间: 2002-10-28 12:11 
用minus呢

(select * from my_table where rounum<=20) minus (select * from my_table where rounum<10)

选取10-20条记录 
 
  评论人:menzy    参与分: 3    专家分: 0  发表时间: 2002-10-28 19:38 
Oracle中用rowid好像可以的 
 
  评论人:9310guo    参与分: 9    专家分: 0  发表时间: 2002-10-29 09:12 
mysql中可以用limit 
 
  评论人:support    参与分: 6    专家分: 0  发表时间: 2002-10-30 10:50 
像这样分页查询的性能太查了。 
 
  评论人:bigsoon    参与分: 27    专家分: 0  发表时间: 2002-11-04 15:47 
Oracle里用rownum就可以。
select * from (select rownum r,name from table1 where rownum<20) where r>1 
 
  评论人:bigsoon    参与分: 27    专家分: 0  发表时间: 2002-11-04 15:47 
Oracle里用rownum就可以。
select * from (select rownum r,name from table1 where rownum<20) where r>1 
 
  评论人:macula    参与分: 68    专家分: 0  发表时间: 2002-11-05 10:06 
不可以,oracle只用rownum的话order by就不对了。

只能用那种3层select或者minus,或者8i以上的rank 
 
  评论人:airlulu    参与分: 51    专家分: 0  发表时间: 2002-11-13 11:19 
是三层select性能好还是minus性能好?
为什么rownum不行? 
 
  评论人:feitian_008    参与分: 179    专家分: 10  发表时间: 2002-12-25 16:41 
有没有通用方法,这样就可以不必考虑后台是什么数据了?? 
 
  评论人:jasonshi    参与分: 12    专家分: 5  发表时间: 2002-12-27 15:43 
使用minus效率很差的,对于oracle可以使用下面的方法:

    sql="select * from (select rownum as my_rownum,table_a.* from("+sql0+") table_a where rownum<"+nEndBeginRecNum+") where my_rownum>="+nBeginRecNum;

其中sql0为原始的sql语句,可以进行排序等操作
nBeginRecNum,nEndBeginRecNum为起始和终止记录号

经过长期检验,效率很好,大数据量时也很快 
 
  评论人:quake_wang    参与分: 129    专家分: 25  发表时间: 2002-12-27 18:24 
用jdbc的api是通用的方法:
ResultSet.absolute(int rowNum) 
 
  评论人:Jevang    参与分: 3087    专家分: 20  发表时间: 2002-12-29 01:48 
原创提出的概念对路,但性能太差,不知各位知道EXCLUSIONCURSOR

WHERE
COLM1 => :COLM1     AND NOT
(    COLM1 = :COLM1     AND
    COLM2 <= :COLM2 )    AND NOT
{    COLM1 = :COLM1    AND
    COLM2 = :COLM2    AND
    COLM3 <= :COLM3    )
ORDER BY COLM1, COLM2, COLM3

Simple to setup and good performance with careful indexing


Using rs.absolute() as suggested by Quake is an elegant solution, but you may receive scrumbal display if underlying table records get modified frequently.  
 
  评论人:Jevang    参与分: 3087    专家分: 20  发表时间: 2002-12-29 01:48 
原创提出的概念对路,但性能太差,不知各位知道EXCLUSIONCURSOR

WHERE
COLM1 => :COLM1     AND NOT
(    COLM1 = :COLM1     AND
    COLM2 <= :COLM2 )    AND NOT
{    COLM1 = :COLM1    AND
    COLM2 = :COLM2    AND
    COLM3 <= :COLM3    )
ORDER BY COLM1, COLM2, COLM3

Simple to setup and good performance with careful indexing


Using rs.absolute() as suggested by Quake is an elegant solution, but you may receive scrumbal display if underlying table records get modified frequently.  
 
  评论人:Jevang    参与分: 3087    专家分: 20  发表时间: 2002-12-29 01:48 
原创提出的概念对路,但性能太差,不知各位知道EXCLUSIONCURSOR

WHERE
COLM1 => :COLM1     AND NOT
(    COLM1 = :COLM1     AND
    COLM2 <= :COLM2 )    AND NOT
{    COLM1 = :COLM1    AND
    COLM2 = :COLM2    AND
    COLM3 <= :COLM3    )
ORDER BY COLM1, COLM2, COLM3

Simple to setup and good performance with careful indexing


Using rs.absolute() as suggested by Quake is an elegant solution, but you may receive scrumbal display if underlying table records get modified frequently.  
 
  评论人:bigsoon    参与分: 27    专家分: 0  发表时间: 2002-12-30 16:25 
用rownum和group by可以实现排序。 
 
  评论人:gui_jq    参与分: 67448    专家分: 905    来自: 广州天河
 发表时间: 2002-12-30 17:02 
我有一次在处理大批量数据列表翻页的时候,我就把用户第一次查出来的,要显示的部分文字和行记录ID保存在session中,翻的时候就不再和数据库打交道,除非看详细内容或者用户重新查询一次。这个方法翻页非常快,即使是几百页,缺点就是第一次查询慢点,但是总比每次翻页和查询一样慢好。大家觉得这个做法怎样?有更好的吗?? 
 
  评论人:quake_wang    参与分: 129    专家分: 25  发表时间: 2002-12-30 18:32 
To Jevang,
   对于频繁修改的数据,如果用分页的话,除非一次性从数据库中先取出来放在一list,再每次从该list里sublist, 其他我目前所了解的方法都是没有避免dirt display的. 你说的EXCLUSIONCURSOR, 我没有听说过, 是依靠数据库(Oracle)实现的吗?它可以避免这样的情况吗:
1.user a选择了第一页, 每页显示10条
2.user b删除了第10条record
3.user a选择next, 由于删除的缘故,user a将会不能看到原来的第11条.

To gui_jq
    如果数据量大的话,放置在session中将会很消耗内存, 并发user数目多的话,就会out of memory. 
 
  评论人:Jevang    参与分: 3087    专家分: 20  发表时间: 2003-01-01 01:06 
to Quake,
EX using boundary records value( top record for move backward, last rec for forward) to construct query dynamically, so it can tolerate database insert or delete. the 11th record will be showed up correctly even you delete 10th one before "NEXT".
Of course, fetch BLOCK size(EX size) can be different than display size, this give you good layout with some optimization, but that's seperate topic.

-Wanchun 
 
  评论人:jini    参与分: 38793    专家分: 420  发表时间: 2003-01-02 08:33 
good! 
 
  评论人:henryzhou    参与分: 196    专家分: 0  发表时间: 2003-04-04 12:28 
这种方式不好;可以采用下的方式来处理:
1、查询需要的数据,不会太多;太多了没有用(1万条以下)
2、取出数据的第一页;将所有的数据使用“观察模式方式”存储到 Cache 中;可以是JCS
3、以后就是在 Cache 中取数据。很快! 
 
  评论人:linxr    参与分: 3    专家分: 0  发表时间: 2003-09-08 14:45 
如果记录有与用户权限相关呢?纯用SQL语句可以吗?还是要使用游标?

To henryzhou:
观察者模式如果是在分布式环境下,即机器A、B同时访问数据库C,这样A修改了记录,如何通知B? 
 

这个文章共有 22 条评论,共 1 页 
 
上一篇文章   返回〔数据库相关〕 
 下一篇文章 

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

 
          $$$$$$$$$$$$$$$$web翻页技术
 

 
在网上看到不少提供web翻页技术的指导,不过,感觉参考价值不大,所以我总结一下别人的经验,重写一次.
   大部分网站架构都是基于MVC,通常jsp作为显示层,或者用模板技术作为显示层,在此层将会显示查询记录总数,以及当前页,还有页面导航, 以及显示改页的记录(Model),.servlet通常作为控制层,用于收集查询条件,调用业务Bean,,完成翻页查询,并将结果返回到显示层.对于分页来说,每层次的主要任务如下:
  显示层:
                取出记录总数,并显示出来;
                指示当前在第几页
                  显示翻页导航条,如象google那样的翻页,或者象yahoo那样的翻页风格
                  取出记录集,并显示出来,通常,一页显示10-30条,并且,这是可以配置的
  控制层:
                 查询的时候,将用户输入的查询条将,通常表现形式是QueryValue放入会话中,以便下次翻页的时候重新取出查询条件
                 如果是第一次查询,调用业务Bean,需要查询记录总数,并查询出第一页的结果集,并传到显示层
                如果是其后后的翻页,则需要调用业务Bean查询指定范围内的结果集,并传到显示层
  业务Bean:
              业务Bean提供按照QueryValue查询出合乎条件总数
                业务Bean提供按照QueryValue,以及 范围(startIndex,endIndex)查询合乎条件的结果集
             
  现在举个例子,分别从业务Bean,控制层,显示层的具体实现来完成分页,我希望这个例子能被复制使用
  业务Bean:
  public class BusinuessFacade
  {
  ...........
   public int queryBookSize(BookQueryValue qv) throws ....
   {
   }
   public BookValueObject queryBooks(BookQueryValue qv,int startIndex,int endIndex) throws....
   {
   }
  }
 
  public class BookQueryValue
  {
   public String name;
   public String isbn
   ............
  
  }
 
  控制层,用serlvet举例
 
  public class BookQueryServelt
  {
     doGet(HttpServletRequest request, HttpServletResponse response....
     {
   String offset = request.getParameter("pager.offset");
      int startIndex = 0;
      int endIndex=0;
      BookQueryValue qv = null;
      HttpSession session = request.getSession();
      if(offset==null)
      {
         //第一次查询,需要查出记录总数
         qv = createQueryValue(request);
         int size = facade.queryBookSize(qv);
         session.setAttribute("resultSize",new Integer(size));
         session.setAttribyte("queryValue",qv);
         startIndex = 1;
         endIndex = Consts.MAX_PAGE_ITEMS;
         if(endIndex > size) endIndex = size;
      }
      else
      {
         startIndex = (new Integer(offset)).intValue() + 1;
         int size = ((Integer) session.getAttribute("resultSize")).intValue();
         endIndex = startIndex + Consts.MAX_PAGE_ITEMS;
         if(endIndex > size) endIndex = size;
         qv = (BookQueryValue)session.getAttribute("queryValue");
      }
      BookValueObject[] vos = facade.queryBooks(qv,startIndex,endIndex);
      request.setAttribute("result",vos);
      gotoQueryResultPage(request);
    }
  }
 
  显示层:上面俩层已经把数据准备好了,现在用pager tag(http://jsptags.com/tags/navigation/pager/download.jsp)来帮助完成分页的显示
 
  <%
 //初始化
 String contextPath = request.getContextPath(); 
 int size = ((Integer)session.getAttribute("resultSize")).intValue();
 String actionPath = contextPath+"/bookqueryservlet";
  %>
 
  <pg:pager items="<%=size%>"
 maxPageItems="<%=Consts.MAX_PAGE_ITEMS%>" //每页显示多少条记录
 maxIndexPages="<%=Consts.MAX_INDEX_PAGE%>" //翻页导航条显示多少个页面
 isOffset="<%= true %>"
 url="<%= actionPath %>" //翻页时调用的servelt
 export="offset,currentPageNumber=pageNumber"
 scope="request"
 >
  <logic:iterate id="vo" name="result" type="org.simple.BookValueObject" scope="request">
  <tr>
    <td align="center"><%=vo.name%></td>
    <td align="center"><%=vo.isbn%></td>  
  </tr>
  </logic:iterate>
 
  <tr>
    <td colspan="5"><div align="center">
      <jsp:include page="/common/yahooPageStyle.jsp" flush="true"/></div></td>
      <!-- 导航条 -->
  </tr>
  <tr>
    <td colspan="5"></td>
  </tr>
  </pg:pager>
 
  显示层用到struts的标记库,以及Pager tag技术,你需要对此了解,也推荐你了解这些技术
  来自我的blog:http://blog.csdn.net/quanjizhu


版权声明  
作者其它文章:
避免重启你的应用程序(二)
避免重启你的应用程序(一)
采用SimpleValue 解决TOP编程时候的视图层问题(下)
采用SimpleValue 解决TOP编程时候的视图层问题(上)
初评hibernate
作者全部文章 
 
 
  评论人:litf    参与分: 29523    专家分: 415    来自: 北京
 发表时间: 2004-11-19 20:05 
写的不错,有收获,呵呵 
 
  评论人:greenhand    参与分: 18    专家分: 0  发表时间: 2004-11-23 22:03 
你的queryBooks是如何实现的,请展示一下.这是实现速度的关键吧 
 
  评论人:javamonkey    参与分: 67247    专家分: 1082    来自: 北京海淀区三里河
 发表时间: 2004-11-23 22:28 
如果考虑性能,可以用如下参考实现(orlace)
 


StringBuffer sb = new StringBuffer();
sb = sb.append("select name,isbn from (select t.*,rownum rowno from Book t where ");
if(qv.name!= null)
{
      sb.append(" t.name like ? and ");
}
if(qv.isbn!=null)
{
     sb.append(" t.isbn = ? and ");
}

sb.append("1 = 1 order by t.name desc)").append(" where rowno between ? and ? ");
.........
PreparedStatement ps = conn.prepareStatement(sql);
int i = 1;
if(qv.name!= null)
{
     ps.setString(i++,"%"+qv.name+"%");
}
if(qv.isbn!= null)
{
     ps.setString(i++,qv.sibn);
}

ps.setInt(i++,startIndex);
ps.setInt(i++,endIndex);

Result rs = ps.executeQuery();

 

也可以考虑拼sql语句,但执行效率可能比较低,在此不举列了

具体实现可以考虑用hibernate,dao这样的ORM工具也可以实现.

如何??