一、 開發環境
我的開發環境是: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文件。
6、對應的配置文件struts-config.xml。
java代碼: |
?? ???? ?? ?? ???? ?? ?? ?????? ?????? ???? ?? …… |
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 = ""+HEADER+": "; ??????????if (offset > 0) { ????????????????header += "&[<< Prev]\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 ??????????????????header += ""+(i/size+1)+"\n"; ????????????????} else { ??????????????????header += "&"+(i/size+1)+"\n"; ????????????????} ??????????} ??????????if(offset < length - size) { ????????????????header += "&[Next >>]\n"; ??????????} ??????????header += " ??????????return header; ????????} else { ??????????return ""; ????????} ??} } |
這部分代碼的實現相當簡潔,但已經足夠完成所需了。
一、 開發環境
我的開發環境是: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" %>
|
6、對應的配置文件struts-config.xml。
java代碼: |
?? ???? ?? ?? ???? ?? ?? ?????? ?????? ???? ?? …… |
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 = ""+HEADER+": "; ??????????if (offset > 0) { ????????????????header += "&[<< Prev]\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 ??????????????????header += ""+(i/size+1)+"\n"; ????????????????} else { ??????????????????header += "&"+(i/size+1)+"\n"; ????????????????} ??????????} ??????????if(offset < length - size) { ????????????????header += "&[Next >>]\n"; ??????????} ??????????header += " ??????????return header; ????????} else { ??????????return ""; ????????} ??} } |
這部分代碼的實現相當簡潔,但已經足夠完成所需了。]]>