`
Augustan
  • 浏览: 52105 次
  • 性别: Icon_minigender_1
  • 来自: 江蘇
社区版块
存档分类
最新评论

改写JSF 分页控件使其能支持大容量数据分页以及查询分页

    博客分类:
  • java
阅读更多

 上一篇对分页的分页的封装是基于struts框架。如果要利用JSF组件实现类似的功能又该如何呢。我对JSF的痴迷始于半年以前,如今有所降温。当时对已有的分页组件作了较大的修改,并使其投入应用。 

对于JSF的学习我开始是看Core Java Server Faces和OReilly的一本Java Server Faces,个人觉得入门看前者是个不错的选择,本文关于分页组件的改写就基于Core Java Server Faces的一个分页组件的例子。

原例子是讲述JSF组件编写过程的好教材,但是其实用性不强,主要是:它把所有数据一次性的读入内存再进行分页,所以不支持大容量的分页;它不支持查询结果分页。


先贴上页面部分的代码:

 

<%@ page language="java" contentType="text/html; charset=GBK"%> <%@ page import="com.inventec.cmm.QueryBean" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://corejsf.com/pager" prefix="corejsf" %> <html> <f:view> <font color="red"><h:outputText value="#{queryBean.msg}"/></font> <HEAD><TITLE >中獎用戶信息查詢</TITLE> <META http-equiv=Content-Type content="text/html; charset=gb2312"> <link rel="stylesheet" type="text/css" href="style.css"> <script language="JavaScript" src="calendar.js" Type="Text/JavaScript" charset="gb2312" ></script> <LINK href=style.css type=text/css rel=stylesheet> </HEAD> <BODY> <TABLE cellSpacing=0 cellPadding=0 align=center bgColor=#EAEFF3 border="datagrid" width=60%> <h:form id="frmQuery"> <TR align=middle > <TD bgColor=#2153aa colSpan=7 height=34> <DIV id=reg> <font color="#FFFFD1"><STRONG>中獎信息查詢</STRONG></font> </DIV></TD></TR> <TR> <Th align=middle height=12>開始時間</Th> <TD align=center><IMG height=1 src="pics/empty.gif" width=10><h:inputText id="DATE_BEGIN" value="#{queryBean.dateBegin}" onfocus="calendar()" /><IMG height=1 src="pics/empty.gif" width=10></TD> <Th align=middle height=12 > 結束時間</Th> <TD align=center><IMG height=1 src="pics/empty.gif" width=10><h:inputText id="DATE_END" value="#{queryBean.dateEnd}" onfocus="calendar()" /><IMG height=1 src="pics/empty.gif" width=10></TD> <th align=center> 得獎用戶<IMG height=1 src="pics/empty.gif" width=10> <h:selectBooleanCheckbox value="#{queryBean.onlyPrize}" readonly="true"/> <IMG height=1 src="pics/empty.gif" width=10></th> <th align=center> 辦事處 </th> <td align=center> <IMG height=1 src="pics/empty.gif" width=10> <h:selectOneMenu id="city" required="true" value="#{queryBean.org}" > <f:selectItems value="#{queryBean.items}"/> </h:selectOneMenu><IMG height=1 src="pics/empty.gif" width=10> </td> </TR> <tr> <th>PSID號碼</th> <td align=center><IMG height=1 src="pics/empty.gif" width=5><h:inputText id="PSID" value="#{queryBean.psid}" /> <IMG height=1 src="pics/empty.gif" width=10></td> <th>驗證碼</th> <td align=center><IMG height=1 src="pics/empty.gif" width=10><h:inputText id="PWD" value="#{queryBean.pwd}" /><IMG height=1 src="pics/empty.gif" width=10></td> <td></td><th>電話號碼</th> <td align=center><IMG height=1 src="pics/empty.gif" width=10><h:inputText id="TEL" value="#{queryBean.tel}" /><IMG height=1 src="pics/empty.gif" width=10></td> </tr> <TR > <TD align=middle height=35 colspan=7><h:commandButton type="submit" value="查詢" id="Submit" actionListener="#{queryBean.reset}" /> <h:commandButton type="submit" value="导出" actionListener="#{queryBean.export}" /> </TD></TR> </h:form> <tr bgcolor=#fffff> <td align=center colspan=7 bgcolor=#FFFFD1>**提示:如果需要查看2006-10-1號信息,開始時間輸入2006-10-1,結束時間輸入2006-10-2</td></tr></table><p><h:outputText /> <p> <h:form id="frmData"> <h:dataTable styleClass="datagrid" cellspacing="0" cellpadding="1" border="1" id="userList" value="#{queryBean.dataModel}" var="p" rows="50" width="100%" rowClasses="evenColumn,oddColumn"> <h:column> <f:facet name="header"> <h:outputText value="序號"/> </f:facet> <h:outputText value="#{p.id}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="PSID"/> </f:facet> <h:outputText value="#{p.psid}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="姓名"/> </f:facet> <h:outputText value="#{p.name}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="獎項"/> </f:facet> <h:outputText value="#{p.prizeCode}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="電話號碼"/> </f:facet> <h:outputText value="#{p.tel}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="領獎號碼"/> </f:facet> <h:outputText value="#{p.telPrize}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="驗證碼"/> </f:facet> <h:outputText value="#{p.pwd}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="办事处"/> </f:facet> <h:outputText value="#{p.orgName}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="參與時間"/> </f:facet> <h:outputText value="#{p.joinDate}" /> </h:column> </h:dataTable> <corejsf:pager dataTableId="userList" showpages="20" selectedStyleClass="currentPage"/> </h:form> </BODY> </f:view> </HTML>


  
在<h:form>标签中,我依次放置了:若干查询参数的输入控件;查询列表的table控件,还有就是本文的主角了:<corejsf:pager >表示的分页控件。

分页控件的dataTableId属性关联了相对应的查询列表控件,以控制其显示。 我将后台的数据都封装在一个queryBean当中,这里没有进行更多的逻辑分层,仅为简化起见,特此说明。

 

在queryBean当中,有几个重要的函数,以及一个内部类

 

public void reset(javax.faces.event.ActionEvent e){ ((LocalDataModel)dataModel).resetPage(0,50); FacesContext facesContext = FacesContext.getCurrentInstance(); UIComponent c =facesContext.getViewRoot(); UIData data=null; String name="frmData:userList"; c=findComponent(c,name,facesContext); if (c!=null){ data=(UIData)c; data.setFirst(0); } } private UIComponent findComponent(UIComponent component, String id, FacesContext context) { String componentId = component.getClientId(context); if (componentId.equals(id)) return component; Iterator kids = component.getChildren().iterator(); while (kids.hasNext()) { UIComponent kid = (UIComponent) kids.next(); UIComponent found = findComponent(kid, id, context); if (found != null) return found; } return null; } public DataModel getDataModel() { if (dataModel == null ) { dataModel = new LocalDataModel(50); } return dataModel; } private class LocalDataModel extends PagedListDataModel { public LocalDataModel( int pageSize) { super (pageSize); } public DataPage fetchPage( int startRow, int pageSize) { return getDataPage(startRow, pageSize); } }


 

其中findComponent函数被用来根据服务器端id“寻找”form范围内的控件,这是个递归寻找的过程。

LocalDataModel  这个内部类可以说是整个控件改写的“灵魂”,它继承于PagedListDataModel   类,而该类实现了javax.faces.model.DataModel的接口。对于该接口的特定实现,可以解决大容量的分页的问题,同时兼顾代码结构的优雅,以及分页逻辑的完全隔离(与业务无关)。

reset函数的作用在于:当用户点查询的时候,所有之前的查询参数清0,记录定位到新的查询结果的第1条记录。

 

PagedListDataModel是个虚类,里面有两个重要函数:

private DataPage getPage() { if (page != null) return page; int rowIndex = getRowIndex(); int startRow = rowIndex; if (rowIndex == -1) { // even when no row is selected, we still need a page // object so that we know the amount of data available. startRow = 0; } // invoke method on enclosing class page = fetchPage(startRow, pageSize); return page; } /** * Return the object corresponding to the current rowIndex. * If the DataPage object currently cached doesn't include that * index then fetchPage is called to retrieve the appropriate page. */ public Object getRowData(){ //////////////////////////////////////////////////// if (rowIndex==-3){ setRowIndex(0); page=fetchPage(rowIndex, pageSize); return null; } ///////////////////////////////////////////////////// if (rowIndex < 0) { throw new IllegalArgumentException( "Invalid rowIndex for PagedListDataModel; not within page"); } // ensure page exists; if rowIndex is beyond dataset size, then // we should still get back a DataPage object with the dataset size // in it... if (page == null) { page = fetchPage(rowIndex, pageSize); } int datasetSize = page.getDatasetSize(); int startRow = page.getStartRow(); int nRows = page.getData().size(); int endRow = startRow + nRows; if (rowIndex >= datasetSize) { throw new IllegalArgumentException("Invalid rowIndex"); } if (rowIndex < startRow) { page = fetchPage(rowIndex, pageSize); startRow = page.getStartRow(); } else if (rowIndex >= endRow) { page = fetchPage(rowIndex, pageSize); startRow = page.getStartRow(); } return page.getData().get(rowIndex - startRow); }


这就是对分页数据进行处理的代码。但是具体的实现细节却留在虚函数 public abstract DataPage fetchPage(int startRow, int pageSize);中留待用户自己实现。我把这个在queryBean当中实现,

具体的比如说用分页的SQL语句直接在数据库端得到数据,也可以用hibernate,这个取决于自己的实际情况。

 

再贴一下控件部分的代码,主要是PageRender类里面encodeBegin和decode函数

public void encodeBegin(FacesContext context, UIComponent component) throws IOException { String id = component.getClientId(context); UIComponent parent = component; while (!(parent instanceof UIForm)) parent = parent.getParent(); String formId = parent.getClientId(context); ResponseWriter writer = context.getResponseWriter(); String styleClass = (String) get(context, component, "styleClass"); String selectedStyleClass = (String) get(context, component, "selectedStyleClass"); String dataTableId = (String) get(context, component, "dataTableId"); Integer a = (Integer) get(context, component, "showpages"); int showpages = a == null ? 0 : a.intValue(); // find the component with the given ID UIData data = (UIData) findComponent(context.getViewRoot(), getId(dataTableId, id), context); int first=0; int itemcount=0; int pagesize=20; if (data!=null){ first = data.getFirst(); itemcount = data.getRowCount(); pagesize = data.getRows(); }else{ // Operation opt=new Operation(); // itemcount=opt.getRowCount(" CMM_club_prize_joined_users "); } if (pagesize <= 0) pagesize = itemcount; int pages = itemcount / pagesize; if (itemcount % pagesize != 0) pages++; int currentPage = first / pagesize; if (first >= itemcount - pagesize) currentPage = pages - 1; int startPage = 0; int endPage = pages; if (showpages > 0) { startPage = (currentPage / showpages) * showpages; endPage = Math.min(startPage + showpages, pages); } writer.write("共计"+pages+"页"+itemcount+"条记录"); if (currentPage > 0) writeLink(writer, component, formId, id, "<", styleClass); if (startPage > 0) writeLink(writer, component, formId, id, "<<", styleClass); for (int i = startPage; i < endPage; i++) { writeLink(writer, component, formId, id, "" + (i + 1), i == currentPage ? selectedStyleClass : styleClass); } if (endPage < pages) writeLink(writer, component, formId, id, ">>", styleClass); if (first < itemcount - pagesize) writeLink(writer, component, formId, id, ">", styleClass); writeInput(writer,component,formId,id,styleClass); // FacesContext facesContext = FacesContext.getCurrentInstance(); // hidden field to hold result writeHiddenField(writer, component, id); } public void decode(FacesContext context, UIComponent component) { String id = component.getClientId(context); Map parameters = context.getExternalContext() .getRequestParameterMap(); String response = (String) parameters.get(id); String dataTableId = (String) get(context, component, "dataTableId"); Integer a = (Integer) get(context, component, "showpages"); int showpages = a == null ? 0 : a.intValue(); UIData data = (UIData) findComponent(context.getViewRoot(), getId(dataTableId, id), context); int first = data.getFirst(); int itemcount = data.getRowCount(); int pagesize = data.getRows(); if (pagesize <= 0) pagesize = itemcount; if (response.equals("<")) first -= pagesize; else if (response.equals(">")) first += pagesize; else if (response.equals("<<")) first -= pagesize * showpages; else if (response.equals(">>")) first += pagesize * showpages; else { int page=0; int num=convertNum(response); if ((num>0)&&(num<=itemcount/pagesize+1)){ page = Integer.parseInt(response); first = (page - 1) * pagesize; } } if (first < 0) first = 0; data.setFirst(first); }


贴张投入应用的图:

分享到:
评论
4 楼 zifeng858 2008-06-02  
分页控件 中 输入查询的页数是如何显示出来的
3 楼 tomyguan 2008-04-11  
問題自己解決,那個法子不錯。
2 楼 tomyguan 2008-04-10  
PagedListDataModel類能寫一下嗎?
1 楼 tomyguan 2008-04-10  
能把那些類具體寫一下嗎?

相关推荐

    JSF分页控件 ,支持大容量可查询分页

    本文将深入探讨JSF分页控件的关键知识点,以及如何实现大容量数据的可查询分页。 首先,理解JSF(JavaServer Faces)框架的基础是必要的。JSF是一种用于构建Web应用程序的Java标准,它提供了一种模型-视图-控制器...

    jsf分页 jsf分页 jsf分页

    在JavaServer Faces (JSF)框架中,分页是一种常用的技术,用于处理大量数据时提供更好的用户体验。当数据集过大,一次性加载所有记录到页面上会导致性能下降且用户界面响应变慢。通过分页,我们可以将数据分成多个...

    jsf自带分页

    JSF的分页通常与数据库操作紧密关联,你可以使用JPA、Hibernate等ORM工具来查询和管理数据。在查询时,通过设置适当的SQL语句(如LIMIT和OFFSET)或使用ORM的分页方法,可以只获取当前页所需的数据。 4. 事件处理...

    JSF分页组件2

    **JSF分页组件2详解** JavaServer Faces (JSF) 是Java平台上的一个用于构建Web应用程序的MVC(Model-View-Controller)框架。在处理大量数据时,分页功能是必不可少的,它能够帮助用户更有效地浏览和管理信息。在...

    jsf分页——详细源码 测试通过

    源代码的测试部分可能会包括单元测试和集成测试,确保分页功能在不同情况下都能正常工作,比如空数据集、单页数据、多页数据以及边缘情况的处理。 总的来说,这个源码示例对于学习和理解如何在JSF项目中实现分页...

    JSF分页组件

    本篇文章将深入探讨JSF中的分页组件,以及如何利用它们来实现高效的数据分页。 **1. 分页组件的基本概念** 分页组件通常由两个主要部分组成:分页导航和数据显示区。分页导航包括上一页、下一页、首页和末页等按钮...

    JSF经典的js分页

    在JavaServer Faces (JSF)框架中,分页是一种常见的需求,特别是在处理大量数据时,以提高用户体验并优化页面加载速度。"JSF经典的js分页"是一个示例,展示了如何在JSF应用中实现纯JavaScript(js)的分页功能。这个...

    jsf 分页实例jsf 分页实例

    **JSF分页实例详解** JSF(JavaServer Faces)是一种用于构建用户界面的Java EE技术,它提供了组件模型和事件处理机制,使得开发者能够更方便地创建Web应用程序。在处理大量数据时,分页是一种必不可少的功能,它...

    jsf 分页

    在JavaScript框架中,JSF(JavaServer Faces)是一种用于构建Web应用程序的技术,它提供了一种声明式的方式来处理用户界面和...无论哪种方式,关键在于理解分页的基本原理,以及如何在JSF环境中有效地应用这些原理。

    JSF数据分页的简单例子(源码)

    在这个简单的例子中,我们关注的是如何在JSF应用中实现数据分页。 **数据分页**是一种在大量数据展示时优化用户体验的技术,它允许用户逐步加载和查看数据,而不是一次性加载所有内容,这可以提高页面加载速度,...

    JSF数据分页的简单实现

    JSF分页有不少的组件可以使用,但用起来都不是想象的那么简单,这里自己实现了一个简单的分页实现,以提供大家分享。 有更好的意见请留言。或者去...

    JSF分页实现,内含建表语句

    在本项目中,我们主要探讨的是如何利用JavaServer Faces (JSF) 框架实现分页功能,并结合MySQL数据库和SQL语句进行数据管理。JSF是一种用于构建Web应用程序的MVC(Model-View-Controller)框架,它提供了一种组件化...

    JSF控件详细说明

    在JSF中,控件是这些组件的实例,它们负责处理用户输入、显示数据以及与其他组件和应用程序逻辑进行交互。 ### JSF控件分类 JSF控件通常分为以下几类: 1. **输入控件**:如`&lt;h:inputText&gt;`用于文本输入,`...

    jsf常用控件的使用

    在JavaScript Server Faces (JSF) 中,控件是构建用户界面的关键组成部分,它们允许开发者创建交互式的Web应用程序。...在实际项目中,通常会结合使用JSF的内置控件以及第三方库的组件,以实现更丰富的用户交互体验。

    jsf 动态分页 带jar包 解压直接导入eclipse即可,方便学习~

    以上就是关于JSF动态分页的基本概念、工作原理以及使用MyFaces Extensions进行分页的详细说明。通过这样的方式,你可以轻松地在JSF应用中实现高效且用户友好的数据分页功能。记住,实践是检验真理的唯一标准,动手...

    JSF2datatable分页控件与左侧菜单

    JSF2.xdatatable分页控件与左侧菜单最简单应用  JSF2.x,功能强大,使用方便。全世界使用JSF的人越来越多。而且也有很多很好的控件给发出来了,如:richfaces、primefaces、myfaces等,就日前来讲primefaces功能...

    struts和jsf分页

    Struts和JSF是两种广泛使用的Java Web框架,它们各自有着独特的特性和优点,而“分页”则是Web开发中的一个重要概念,特别是在处理大量数据时,分页能提高用户体验并优化性能。以下将详细介绍这两个框架如何实现分页...

    JSF分页代码和学习文件1

    分页是Web应用中常见的功能,特别是在数据量较大的时候,为了提高用户体验,通常会将大量数据分成多个页面显示。JSF提供了多种实现分页的方法,包括使用核心标签库(Core Tags)、自定义组件或者利用第三方库如...

    JSF日历控件

    JSF日历控件可以与其他组件协同工作,如命令按钮、数据表等,以实现更复杂的业务逻辑。例如,用户可以选择一个日期,然后点击按钮触发一个动作,该动作可能会根据所选日期执行数据库查询或其他业务操作。 总结,JSF...

Global site tag (gtag.js) - Google Analytics