| 
         
     
     | 
     | 
    
  
    | 
    一个高效简洁的Struts分页方法(原创) | 
   
  
     | 
   
  
     | 
   
  
    | 
     作者:未知  来源:月光软件站  加入时间:2005-2-28 月光软件站  | 
   
  
        在网上看了几个Structs分页,感觉不是很完善,于是根据自己的经验,写了一个相对高效简洁的分页方法。由于本人水平有限,如果大家有什么更好的想法,欢迎不吝赐教。 
  一、 开发环境  我的开发环境是:JBuilder x + Weblogic 8.1 + Oracle 9i + Windows 2003 ,如果朋友们的开发环境不一样亦无妨。 
  二、开发思路  既然讲的是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,"                                  + "description,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.setDescription (rs.getString ("description")) ;                          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 ()) 是为了程序的健壮性考虑的,稍分析一下不难得出结论。 
  3、建立控制器组件:CertificateAction.java 
 
  
| java代码:  |  
| 
  package com.xindeco.presentation; 
  import javax.sql.* ;  import java.util.* ; 
  import javax.servlet.http.* ;  import javax.servlet.* ; 
  import org.apache.struts.action.* ;  import org.apache.struts.util.* ; 
  import com.xindeco.common.Pager;  import com.xindeco.business.graduatedata.CertificateDAO ; 
  public class CertificateAction          extends Action  {          private static final int PAGE_LENGTH = 5 ; //每页显示5条记录          public ActionForward execute (ActionMapping mapping, ActionForm form,                                                                    HttpServletRequest request,                                                                    HttpServletResponse response)          {                  ActionForward myforward = null ;                  String myaction = mapping.getParameter () ; 
                  if (isCancelled (request))                  {                          return mapping.findForward ("failure") ;                  }                  if ("".equalsIgnoreCase (myaction))                  {                          myforward = mapping.findForward ("failure") ;                  }                  else if        ("LIST".equalsIgnoreCase (myaction))                  {                          myforward = performList (mapping, form, request, response) ;                  }                  else                  {                          myforward = mapping.findForward ("failure") ;                  }                  return myforward ;          } 
          private ActionForward performList (ActionMapping mapping,                                                                             ActionForm actionForm,                                                                             HttpServletRequest request,                                                                             HttpServletResponse response)          {                       try                  {          DataSource ds = (DataSource) servlet.getServletContext().getAttribute(Action.DATA_SOURCE_KEY); 
                  CertificateDAO   certificateDAO  = new CertificateDAO  (ds) ; 
                          int offset = 0;   //翻页时的起始记录所在游标                          int length = PAGE_LENGTH;                           String pageOffset = request.getParameter("pager.offset");                  if (pageOffset == null || pageOffset.equals("")) {          offset = 0;        } else {          offset = Integer.parseInt(pageOffset);        }                          List certificateList = certificateDAO .findCertificateList (offset,length) ;                          int size = certificateDAO.getRows(); //  取得总记录数                          String url = request.getContextPath()+"/"+mapping.getPath()+".do";                          String pagerHeader = Pager.generate(offset, size, length, url); //分页处理 
                          request.setAttribute ("pager", pagerHeader) ;                          request.setAttribute ("list", certificateList) ;                  }                  catch (Exception e)                  {                          e.printStackTrace();                          return mapping.findForward ("error") ;                  }                  return mapping.findForward ("success") ;          }  }
  |   
  CertificateAction.java主要是把数据从DAO中取出,并放入一个ArrayList 中,然后通过配置文件再软件View的JSP页。 
  5、建立视图listcertificate.jsp文件。 
  
| java代码:  |  
| 
  <%@ page contentType="text/html; charset=GBK" %>  <%@ taglib uri="/WEB-INF/struts-template.tld" prefix="template" %>  <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>  <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>  <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> 
  <table bgcolor="#666666" cellpadding="1" cellspacing="0" border="0" width="500">  <tr>  <td>  <table cellpadding="0" cellspacing="0" border="0" width="500">  <tr>  <td bgcolor="#fecc51">&</td>  </tr>  </table>  </td>  </tr>  <tr>  <td>  <table cellpadding="0" cellspacing="0" border="0" width="500">    <tr>  <td bgcolor="#d6e0ed">      &&<bean:message key="label.list4certificate"/>    </td>  </tr>  <tr bgcolor="#FFFFFF">  <td width="5%"></td><td width="19%"></td><td width="76%"></td>  </tr>      <tr>  <td>  <table bgcolor="#f2f2f2" width="500" cellspacing="0" border="0">        <tr bgcolor="#bacce1">          <td><b><bean:message key="Certificate.select"/> </b></td>          <td><b><bean:message key="Certificate.certificateID"/> </b></td>          <td><b><bean:message key="Certificate.certificateCode"/></b></td>          <td><b><bean:message key="Certificate.certificateName"/></b></td>          <td><b><bean:message key="Certificate.view"/></b></td>      ?/tr> 
  <bean:write name="pager" property="description"/>    <logic:equal name="pager" property="hasPrevious" value="true">                <a href="/graduatedata/list.do?viewPage=<bean:write name="pager" property="previousPage"/>" class="a02">             Previous          </a>    </logic:equal>    <logic:equal name="pager" property="hasNext" value="true">      ?a href="/graduatedata/list.do?viewPage=<bean:write name="pager" property="nextPage"/>" class="a02">       Next      ?/a>    </logic:equal> 
  <logic:notEmpty name="list" scope="request">  <logic:iterate id="certificate" name="list" type="com.xindeco.business.graduatedata.CertificateVO"scope="request">  <tr bgcolor="#FFFFFF">      ?td><html:text property="name" value="<bean:write name="certificate" property="certificateID" scope="page"/>"/>                  </td>      ?td> <bean:write name="certificate" property="certificateID" scope="page"/></td>      ?td> <bean:write name="certificate" property="certificateCode" scope="page"/></td>      ?td> <bean:write name="certificate" property="certificateName" scope="page"/></td>      ?td> <bean:write name="certificate" property="photoURL" scope="page"/></td>  </tr>  </logic:iterate>  </logic:notEmpty>  </table>  </td>  </tr>  </table>  </td>  </tr>  </table>
  |    6、对应的配置文件struts-config.xml。 
  
| java代码:  |  
| 
  <?xml version="1.0" encoding="UTF-8"?>  <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">  <struts-config>    <form-beans>      <form-bean name="certificateForm" type="com.xindeco.presentation.graduatedata.CertificateForm" />    </form-beans>    <global-forwards>      <forward name="error" path="/error/error.jsp" />    </global-forwards>    <action-mappings>        <action name="certificateForm" parameter="LIST" path="/graduatedata/list" scope="request" type="com.xindeco.presentation.graduatedata.CertificateAction" validate="true">        <forward name="success" path="/graduatedata/listcertificate.jsp" />      </action>    </action-mappings>  ……  </struts-config>
  |    7、最后当然是最重要的分页代码了:Pager.java 
  
| java代码:  |  
| 
  package com.xindeco.common; 
  import java.util.* ;  public class Pager {    private static int MAX_PAGE_INDEX = 10; //页脚显示多少页    private static String HEADER = "Result page";       public static String generate(int offset, int length, int size, String url) {          if (length > size) {            String pref;            if (url.indexOf("?") > -1) {                  pref = "&";            } else {                  pref = "?";            }            String header = "<font face='Helvetica' size='-1'>"+HEADER+": ";            if (offset > 0) {                  header += "&<a href=\""+url+pref+"pager.offset="+(offset-size)+"\">[<< Prev]</a>\n";            }            int start;            int radius = MAX_PAGE_INDEX/2*size;            if (offset < radius) {                  start = 0;            } else if(offset < length-radius) {                  start = offset - radius;            } else {                  start = (length/size-MAX_PAGE_INDEX)*size;            }            for(int i=start;i<length && i < start + MAX_PAGE_INDEX*size;i+=size) {                  if (i == offset) {                    header += "<b>"+(i/size+1)+"</b>\n";                  } else {                    header += "&<a href=\""+url+pref+"pager.offset="+i+"\">"+(i/size+1)+"</a>\n";                  }            }            if(offset < length - size) {                  header += "&<a href=\""+url+pref+"pager.offset="+((int)offset+(int)size)+"\">[Next >>]</a>\n";            }            header += "</font>";            return header;          } else {            return "";          }    }  }
  |    这部分代码的实现相当简洁,但已经足够完成所需了。
   
 
  | 
   
  
     | 
   
  
     相关文章:相关软件:  | 
   
   
      |