既然讲的是 Struts ,那自然离不了 MVC ,分页显示也是如此。 
   
   1 、 建立数据库和对应的表,本例的表是 TCertificate 。 
   
   2 、 建立适当的模型组件,对应你要查询数据库中的表。这部分由 DAO 数据访问层来实现,如果有的朋友对 DAO 不熟悉可以查询一下相关资料。本例由 CertificateDAO.java 来实现。 
   
   3 、建立分页所需要的模型组件,由 javaBean 来充当,并与 CertificateDAO 实现分离。网上介绍的很多方法,都存在着数据与分页组件藕合的现象,这也是本方法与其它分页方法的主要不同之处。 
   
    4 、建立控制器组件,这部分由 Struts 中的 Action 来实现。主要负责将实例化 CertificateDAO ,只取要显示的数据记录,存入 ArrayList 对象然后返回,并放到 request 中。而分页部分则根据分页条件,单独进行构造,避免了与 DAO 混在一起的情况发生。网上其它介绍的一些分页方法中,基本上都是一次性读出所 有查询的数据,然后再由分页相关组件进行构造。这样,如果数据量大的话,很容易形成瓶颈。在本例中由于不是一次性地读出查询的所有数据,而只是读出一个页 面要显示的数据记录,这就节省了很多不必要的数据传输,提高了效率。本例中为 CertificateAction.java 。 
   
   5 、建立视图组件,这部分由 jsp 来充当,为了不出现 java 代码,我们使用 Struts 提供的标签库,主要负责从 request 中取出刚刚放入的对象,通过反复调用 CertificateAction 以及 action 参数,而实现分页显示。本例中为 listcertificate.jsp 。 
   
   6 、 建立并配置 struts-config.xml 。 
   
  三、实例代码 
   
  确定好上面的开发思路后,代码的实现就有单可循了。 
   
   1 、建数据库和相应的表。 
   
   2 、数据逻辑层的相关代码。 
   
   1 )、通用的 DAO 类: CommonDAO.java 
   
  这是一个很多 DAO 都要继承到的通用 DAO 类,是我根据实践总结出来的,为了减少篇幅,这里只显示和本例相关的代码。 
   
   java 代码 : 
   
  代码: 
   --------------------------------------------------------------------------------    package com.xindeco.business ;    import java.io.*;    import java.sql.*;    import java.util.*;    import javax.sql.*;    import java.lang.IllegalAccessException;    import java.lang.reflect.InvocationTargetException;    import org.apache.commons.beanutils.BeanUtils;    public class DAO    {    protected DataSource ds;    /**    * 说明 : 取得当前查询的总记录数    */    public int getRows ()    {    return this.count;    }    public void rsHandler (ResultSet rs, int offset, int limit)    {    try    {    count = 0;    rs.absolute ( -1) ;    count = rs.getRow () ;    if (offset <= 0)    {    rs.beforeFirst () ;    }    else    {    rs.absolute (offset) ;    }    }    catch (Exception e)    {    e.printStackTrace () ;    }    }    public DAO(DataSource ds) {    this.ds = ds;    }       public void setDataSource(DataSource ds) {    this.ds = ds;    }       protected void close(ResultSet rs) {    if (rs != null) {    try {    rs.close();    } catch (SQLException e) {    }    rs = null;    }    }       protected void close(PreparedStatement pstmt) {    if (pstmt != null) {    try {    pstmt.close();    } catch (SQLException e) {    }    pstmt = null;    }    }    protected void close(Connection conn) {    if (conn != null) {    try {    conn.close();    } catch (SQLException e) {    e.printStackTrace();    }    conn = null;    }    }       protected void rollback(Connection conn) {    if (conn != null) {    try {    conn.rollback();    } catch (SQLException e) {    e.printStackTrace();    }    conn = null;    }    }    }    
  这个类主要是通过子类传进来的先进结果集,取得查询的记录总数,并对数据库连接进行简单的管理。 2 )、对数据库进行访问: CertificateDAO.java 
   
   java 代码 : 
   
  代码: 
   --------------------------------------------------------------------------------    package com.xindeco.business;       import java.io.*;    import java.sql.*;    import java.util.*;    import javax.sql.*;       import com.xindeco.common.dbconn.DbConn;       public class CertificateDAO extends DAO    {       public NationDAO(DataSource ds) {    super(ds);    }       public List findCertificateList(int offset,int limit) throws SQLException    {    int countRows = 0 ;    ArrayList list = null ;    Connection conn = null;    PreparedStatement pstmt = null;    ResultSet rs = null;    try    {    conn = ds.getConnection();    String sql =    "SELECT certificateID, certificateCode,certificateName,photoURL,"    + "des.c.r.i.p.tion,graduateID FROM TCertificate " ;    pstmt = conn.prepareStatement(sql);    rs = pstmt.executeQuery();    /* 对游标进行处理, rsHandler 方法在父类 DAO 中 */    this.rsHandler(rs,offset,limit);    if (rs != null && rs.next ())    {    list = new ArrayList () ;    do    {    countRows++ ;    list.add (rs2VO (rs)) ;    }    while ( (countRows++ < limit) && rs.next ()) ;    }    close(rs);    close(pstmt);    } catch (SQLException e) {    close(rs);    close(pstmt);    rollback(conn);    e.printStackTrace();    }    finally {    close(conn);    }    return list ;    }       private CertificateVO rs2VO (ResultSet rs)    {    try    {    CertificateVO certificateVO = new CertificateVO () ;    certificateVO.setCertificateID (rs.getInt ("certificateID")) ;    certificateVO.setCertificateCode (rs.getString ("certificateCode")) ;    certificateVO.setCertificateName (rs.getString ("certificateName")) ;    certificateVO.setPhotoURL (rs.getString ("photoURL")) ;    certificateVO.setDes.c.r.i.p.tion (rs.getString ("des.c.r.i.p.tion")) ;    certificateVO.setGraduateID (rs.getInt ("graduateID")) ;    return certificateVO ;    }    catch (Exception ex)    {    ex.printStackTrace () ;    return null ;    }    }    }  
    findCertificateList(int offset,int limit) 是查得所有要显示的数据,并放入 ArrayList 中。看过网上有些例子,把数据记录放入 ArrayList 的动作过程直接在 while 循环 体里完成,如果字段多的话,会造成方法过于宠大,又不美观。 这里,数据记录放入 ArrayList 的动作过程由 rs2VO 方法完成,就比较整洁了。另外, if (rs != null && rs.next ()) 配合 while ( (countRows++ < limit) && rs.next ()) 是为了程序的健壮性考虑的,稍分析一下不难得出结论。 

解决方案 »

  1.   

    帮你顶一下针对这个分页,我还有些小意见:在数据库层将满足条件的数据全部取出,扔给 Web 层,让 Web 层利用游标去选取需要的页数,再把大部分的扔掉!而且每翻一页都得重新做一遍这样的事情,加之还使用了游标移行,如果数据结果集是庞大的话,这样做会损失性能的。一般来说,像大数量的分页,是采用分页的 SQL 语句,也就是需要第几页数据,就直接从数据库中取出当前页的数据行,因为没有冗余的数据,这样在数据处理和传输方面都是很高效的。当然了,这样对数据库服务器造成的压力也是可想而知的,每翻一页都得跟数据库打一次交道,如果做得更好的话,可以从数据库中取出多页的数据,缓存起来,显示当前页的数据,翻页时如果缓存中有该页的数据,则从缓存里取,没有的话,再向数据库去要。但是要采用分页 SQL 语句的话,也是很麻烦的,像 MS SQL Server、Oracle、MySQL 之类的数据库实现方式都不是一样的,以 MySQL 最为简单,SQL Server 最为麻烦(特别是使用到多表联接查询的时候)。像 Hibernate 实现这样的分页,其关键就在于配置了所使用的数据库方言,根据不同的数据库采用不同的 SQL 语句。