




已閱讀5頁(yè),還剩13頁(yè)未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
在JSF中實(shí)現(xiàn)分頁(yè)(一) 對(duì)于大多數(shù)Web應(yīng)用,分頁(yè)都是必不可少的功能,當(dāng)然在JSF中也一樣,我在這里用兩篇文章介紹兩種方法來(lái)展示一下,如何在JSF中實(shí)現(xiàn)分頁(yè)。本文假定你已經(jīng)對(duì)JSF有了一些簡(jiǎn)單的了解,懂得基本配置和使用,并建立起一個(gè)blank項(xiàng)目。Myfaces是Apache基金會(huì)中的一個(gè)一級(jí)項(xiàng)目,除了實(shí)現(xiàn)JSF標(biāo)準(zhǔn)外,做了很多的擴(kuò)展工作,在Myfaces包中有一個(gè)擴(kuò)展包Tomahawk,我們將主要使用其中的兩個(gè)Component實(shí)現(xiàn)分頁(yè):一個(gè)是,另一個(gè)是,在第一篇里面,我們簡(jiǎn)易的組合這兩個(gè)Component來(lái)實(shí)現(xiàn)一種簡(jiǎn)單,但并不高效的分頁(yè)。下面的例子來(lái)自于Myfaces-Sample,我省去了其中和分頁(yè)邏輯無(wú)關(guān)的內(nèi)容,詳細(xì)的例子可以下載Myfaces-Sample包或者訪問(wèn)http:/www.irian.at/myfaces/home.jsf 查看。第一部分:dataTable在這一部分中,dataTable綁定了一個(gè)backing bean - pagedSort中的cars屬性,我們可以在這個(gè)屬性中加入數(shù)據(jù)訪問(wèn)邏輯,從數(shù)據(jù)庫(kù)或者其他來(lái)源取得用于顯示的數(shù)據(jù)。比如我們可以通過(guò)Hibernate獲取一個(gè)List,其中包含有我們用于顯示的POJOs。注意,dataTable中的rows屬性指的是每頁(yè)的行數(shù),是必須指定的,否則是無(wú)法進(jìn)行分頁(yè)的,如果在項(xiàng)目中會(huì)使用固定行數(shù)的分頁(yè),建議把這個(gè)值寫(xiě)在BaseBackingBean中,并暴露一個(gè)property,供頁(yè)面調(diào)用,所以每次在頁(yè)面中就可以這么寫(xiě)#backingBean.pageSize。第二部分:dataScroller這里定義了我們用于分頁(yè)的,最主要的是配置該分頁(yè)Component針對(duì)哪個(gè)dataTable進(jìn)行分頁(yè)的“for”屬性,該屬性與dataTable綁定,并對(duì)其進(jìn)行分頁(yè),在這里,綁定了第一部分中的id=data的dataTable,下面有很多的是指定分頁(yè)的導(dǎo)航樣式的,這里使用了圖片作為導(dǎo)航,可以把他們改成文字形式的導(dǎo)航。當(dāng)然這只是最簡(jiǎn)單,也是一種不推薦的分頁(yè)方式,因?yàn)樵诿看芜M(jìn)行分頁(yè)的時(shí)候,將會(huì)從數(shù)據(jù)庫(kù)中取回所有的記錄放入List中,然后,dataScroller在對(duì)這個(gè)List進(jìn)行分頁(yè),如果在數(shù)據(jù)量很大的情況下,這種方式顯然是不符合要求的,假設(shè)每條記錄占用1k內(nèi)存,數(shù)據(jù)庫(kù)中有100萬(wàn)條記錄,每次要把這個(gè)List全部讀取出來(lái)將占用1G內(nèi)存。我們需要一種Load on demand方式的讀取,也就是只在需要查看某頁(yè)的時(shí)候讀取該頁(yè)的數(shù)據(jù)。另外一方面,JSF的生命周期中有多個(gè)階段會(huì)調(diào)用到#pagedSort.cars中對(duì)應(yīng)的方法,如果在這里調(diào)用了數(shù)據(jù)訪問(wèn)邏輯,就會(huì)在只顯示一次頁(yè)面的情況下進(jìn)行多次數(shù)據(jù)庫(kù)操作,也是相當(dāng)?shù)暮馁M(fèi)資源的。所以我們需要有更好的分頁(yè)方式去解決以上問(wèn)題,下一篇我將介紹另一種方法以改善這些問(wèn)題。前面一篇直接使用了Myfaces中的兩個(gè)Component完成了一個(gè)簡(jiǎn)單的分頁(yè),這里將會(huì)介紹一種On-demand loading的方法來(lái)進(jìn)行分頁(yè),僅僅在需要數(shù)據(jù)的時(shí)候加載。 先來(lái)說(shuō)一些題外話,為了實(shí)現(xiàn)這種方式的分頁(yè),公司里大約5-6個(gè)人做了半個(gè)多月的工作,擴(kuò)展了dataTable,修改了dataScrollor,以及各種其他的方法,但是都不是很優(yōu)雅。在上個(gè)月底的時(shí)候,在Myfaces的Mail List中也針對(duì)這個(gè)問(wèn)題展開(kāi)了一系列的討論,最后有人總結(jié)了討論中提出的比較好的方法,提出了以下的分頁(yè)方法,也是目前實(shí)現(xiàn)的最為優(yōu)雅的方法,也就是不對(duì)dataTable和dataScrollor做任何修改,僅僅通過(guò)擴(kuò)展DataModel來(lái)實(shí)現(xiàn)分頁(yè)。 DataModel 是一個(gè)抽象類(lèi),用于封裝各種類(lèi)型的數(shù)據(jù)源和數(shù)據(jù)對(duì)象的訪問(wèn),JSF中dataTable中綁定的數(shù)據(jù)實(shí)際上被包裝成了一個(gè)DataModel,以消除各種不同數(shù)據(jù)源和數(shù)據(jù)類(lèi)型的復(fù)雜性,在前面一篇中我們?cè)L問(wèn)數(shù)據(jù)庫(kù)并拿到了一個(gè)List,交給dataTable,這時(shí)候,JSF會(huì)將這個(gè)List包裝成 ListDataModel ,dataTable訪問(wèn)數(shù)據(jù)都是通過(guò)這個(gè)DataModel進(jìn)行的,而不是直接使用List。 接下來(lái)我們要將需要的頁(yè)的數(shù)據(jù)封裝到一個(gè)DataPage中去,這個(gè)類(lèi)表示了我們需要的一頁(yè)的數(shù)據(jù),里面包含有三個(gè)元素:datasetSize,startRow,和一個(gè)用于表示具體數(shù)據(jù)的List。datasetSize表示了這個(gè)記錄集的總條數(shù),查詢(xún)數(shù)據(jù)的時(shí)候,使用同樣的條件取count即可,startRow表示該頁(yè)的起始行在數(shù)據(jù)庫(kù)中所有記錄集中的位置。/*/ /* *Asimpleclassthatrepresentsapageofdataoutofalongerset,iea*listofobjectstogetherwithinfotoindicatethestartingrowandthefull*sizeofthedataset.EJBscanreturninstancesofthistypewhenreturning*subsetsofavailabledata. */ public class DataPage private int datasetSize; private int startRow; private Listdata; /*/ /* *Createanobjectrepresentingasublistofadataset.* param datasetSize*isthetotalnumberofmatchingrowsavailable.* param startRow*istheindexwithinthecompletedatasetofthefirstelement*inthedatalist.* param data*isalistofconsecutiveobjectsfromthedataset. */ public DataPage( int datasetSize, int startRow,Listdata) this .datasetSize = datasetSize; this .startRow = startRow; this .data = data; /*/ /* *Returnthenumberofitemsinthefulldataset. */ public int getDatasetSize() return datasetSize; /*/ /* *Returntheoffsetwithinthefulldatasetofthefirstelementinthe*listheldbythisobject. */ public int getStartRow() return startRow; /*/ /* *Returnthelistofobjectsheldbythisobject,whichisacontinuous*subsetofthefulldataset. */ public ListgetData() return data; 接下來(lái),我們要對(duì)DataModel進(jìn)行封裝,達(dá)到我們分頁(yè)的要求。該DataModel僅僅持有了一頁(yè)的數(shù)據(jù)DataPage,并在適當(dāng)?shù)臅r(shí)候加載數(shù)據(jù),讀取我們需要頁(yè)的數(shù)據(jù)。 /*/ /* *AspecialtypeofJSFDataModeltoallowadatatableanddatascrollertopage*throughalargesetofdatawithouthavingtoholdtheentiresetofdatain*memoryatonce.*Anytimeamanagedbeanwantstoavoidholdinganentiredataset,themanaged*beanshoulddeclareaninnerclasswhichextendsthisclassandimplements*thefetchDatamethod.Thismethodiscalledasneededwhenthetablerequires*datathatisntavailableinthecurrentdatapageheldbythisobject.*Thisdoesrequirethemanagedbean(andingeneralthebusinessmethodthat*themanagedbeanuses)toprovidethedatawrappedinaDataPageobjectthat*providesinfoonthefullsizeofthedataset. */ public abstract class PagedListDataModel extends DataModel int pageSize; int rowIndex;DataPagepage; /*/ /* *Createadatamodelthatpagesthroughthedatashowingthespecified*numberofrowsoneachpage. */ public PagedListDataModel( int pageSize) super (); this .pageSize = pageSize; this .rowIndex = - 1 ; this .page = null ; /*/ /* *Notusedinthisclass;dataisfetchedviaacallbacktothefetchData*methodratherthanbyexplicitlyassigningalist. */ public void setWrappedData(Objecto) if (o instanceof DataPage) this .page = (DataPage)o; else throw new UnsupportedOperationException( setWrappedData ); public int getRowIndex() return rowIndex; /*/ /* *Specifywhatthecurrentrowwithinthedatasetis.Notethatthe*UIDatacomponentwillrepeatedlycallthismethodfollowedbygetRowData*toobtaintheobjectstorenderinthetable. */ public void setRowIndex( int index) rowIndex = index; /*/ /* *Returnthetotalnumberofrowsofdataavailable(notjustthenumberof*rowsinthecurrentpage!). */ public int getRowCount() return getPage().getDatasetSize(); /*/ /* *ReturnaDataPageobject;ifoneisnotcurrentlyavailablethenfetch*one.Notethatthisdoesntensurethatthedatapagereturnedincludes*thecurrentrowIndexrow;seegetRowData. */ private DataPagegetPage() if (page != null ) return page; int rowIndex = getRowIndex(); int startRow = rowIndex; if (rowIndex = - 1 ) / evenwhennorowisselected,westillneedapage / objectsothatweknowtheamountofdataavailable. startRow = 0 ; / invokemethodonenclosingclass page = fetchPage(startRow,pageSize); return page; /*/ /* *ReturntheobjectcorrespondingtothecurrentrowIndex.IftheDataPage*objectcurrentlycacheddoesntincludethatindexthenfetchPageis*calledtoretrievetheappropriatepage. */ public ObjectgetRowData() if (rowIndex = datasetSize) throw new IllegalArgumentException( InvalidrowIndex ); if (rowIndex = endRow) page = fetchPage(rowIndex,pageSize);startRow = page.getStartRow(); return page.getData().get(rowIndex - startRow); public ObjectgetWrappedData() return page.getData(); /*/ /* *ReturntrueiftherowIndexvalueiscurrentlysettoavaluethat*matchessomeelementinthedataset.Notethatitmaymatcharowthatis*notinthecurrentlycachedDataPage;ifsothenwhengetRowDatais*calledtherequiredDataPagewillbefetchedbycallingfetchData. */ public boolean isRowAvailable() DataPagepage = getPage(); if (page = null ) return false ; int rowIndex = getRowIndex(); if (rowIndex = page.getDatasetSize() return false ; else return true ; /*/ /* *Methodwhichmustbeimplementedincooperationwiththemanagedbean*classtofetchdataondemand. */ public abstract DataPagefetchPage( int startRow, int pageSize); 最后,我們需要在Backing Bean中加一些東西,調(diào)用業(yè)務(wù)邏輯,并將數(shù)據(jù)交給PagedListDataModel,來(lái)幫我們完成最后的分頁(yè)工作。 public SomeManagedBean . private DataPagegetDataPage( int startRow, int pageSize) / accessdatabasehere,orcallEJBtodoso public DataModelgetDataModel() if (dataModel = null ) dataModel = new LocalDataModel(20); return dataModel; private class LocalDataModel extends PagedListDataModel public LocalDataModel( int pageSize) super (pageSize); public DataPagefetchPage( int startRow, int pageSize) / callenclosingmanagedbeanmethodtofetchthedata return getDataPage(startRow,pageSize); 這里面有一個(gè)getDataPage的方法,只需要把所有業(yè)務(wù)邏輯的調(diào)用放在這里就可以了,最后業(yè)務(wù)邏輯調(diào)用的結(jié)果返回一個(gè)List,總條數(shù)返回一個(gè)int型的count放到DataPage中去就可以了。 為了實(shí)現(xiàn)復(fù)用,把上面第三段的代碼中的LocalDataModel類(lèi)和getDataPage方法抽到BasePagedBackingBean中,把getDataPage方法改成: protected abstract DataPage getDataPage(int startRow, int pageSize); 這樣我們把所有需要分頁(yè)的Backing Bean繼承自這個(gè)抽象類(lèi),并實(shí)現(xiàn)getDataPage方法即可很容易的實(shí)現(xiàn)分頁(yè)。 在具體應(yīng)用中可以這么寫(xiě): protected DataPagegetDataPage( int startRow, int pageSize) ListscheduleList = scheduleService.getSchedulesByDate(scheduleDate,startRow,pageSize); int dataSetSize = scheduleService.getSchedulesCountByDate(scheduleDate); return new DataPage(dataSetSize,startRow,scheduleList); 在數(shù)據(jù)訪問(wèn)中,我們只需要取出我們需要行數(shù)的記錄就可以了,這在hibernate中非常容易實(shí)現(xiàn)。 如果使用Criteria查詢(xún)的話,只要加上: criteria.setFirstResult(startRow); criteria.setMaxResults(pageSize); 使用Query查詢(xún)的話,只要加上 query.setFirstResult(startRow); query.setMaxResults(pageSize); 并把兩個(gè)參數(shù)傳入即可。 我們還需要另外寫(xiě)一個(gè)Count的DAO,取出相同查詢(xún)條件的記錄條數(shù)即可。 還要修改一下Backing Bean中與dataTable綁定的property,將返回類(lèi)型由List改成DataModel,而第一篇中用到的頁(yè)面不需要做任何修改就可以滿(mǎn)足新的需求了。 里面最重要的是 PagedListDataModel 中 fetchPage 這個(gè)方法,當(dāng)滿(mǎn)足取數(shù)據(jù)的條件時(shí),都會(huì)調(diào)用它取數(shù)據(jù),因?yàn)闃I(yè)務(wù)邏輯不同,不便于將業(yè)務(wù)邏輯的調(diào)用放在里面實(shí)現(xiàn),于是將其作為抽象方法,將具體的實(shí)現(xiàn)放到具體的Backing Bean中進(jìn)行,在BaseBackingBean中,實(shí)現(xiàn)了這個(gè)方法,調(diào)用了getDataPage(startRow, pageSize)這個(gè)方法,而在BaseBackingBean中,這個(gè)方法又推遲到更具體的頁(yè)面中實(shí)現(xiàn),這樣,我們?cè)诰唧w的頁(yè)面中只需要實(shí)現(xiàn)一個(gè)getDataPage(startRow, pageSize)這個(gè)方法訪問(wèn)業(yè)務(wù)邏輯。 大功告成,這個(gè)實(shí)現(xiàn)把前面遇到的兩個(gè)問(wèn)題都解決了, On-demand loading 是沒(méi)有問(wèn)題了,因?yàn)橹挥性谑状巫x取和換頁(yè)的時(shí)候DataModel才會(huì)向數(shù)據(jù)庫(kù)請(qǐng)求數(shù)據(jù),雖然在JSF的生命周期中多次調(diào)用與dataTable綁定的方法,但是因?yàn)槊看螛I(yè)務(wù)邏輯請(qǐng)求以后,數(shù)據(jù)都會(huì)存放在DataPage中,如果里面的數(shù)據(jù)滿(mǎn)足需求的話,就不再請(qǐng)求訪問(wèn)數(shù)據(jù)庫(kù),這樣多次訪問(wèn)數(shù)據(jù)庫(kù)的問(wèn)題也解決了。 雖然這樣的話,dataScrollor的Tag使用起來(lái)還是很復(fù)雜,通常在同一個(gè)項(xiàng)目中,我們只會(huì)使用一種樣式的分頁(yè)導(dǎo)航,不過(guò)沒(méi)關(guān)系,我們只需要修改以下DataScrollor的Render Kit,把一些可以定義的值固定下來(lái),再定義一個(gè)TLD文件,就可以在項(xiàng)目中使用簡(jiǎn)化版的Tag了。 這個(gè)方法一開(kāi)始發(fā)布在Myfaces的Wiki中,/myfaces/WorkingWithLargeTables,那里很少有人關(guān)注到,大家有興趣可以看看原文,本文只是對(duì)這種方法做一些簡(jiǎn)單的介紹,并非自創(chuàng),希望大家能夠多多關(guān)注開(kāi)源社區(qū),因?yàn)槟抢镉凶钚伦詈玫臇|西。 從Nightly Build服務(wù)器中拿到的12.27的Myfaces包,發(fā)現(xiàn)里面擴(kuò)充了很多新的Component,只是并沒(méi)有正式發(fā)布,大家有興趣的話可以研究研究。 好久沒(méi)有寫(xiě)點(diǎn)東西了,這次想把JSF中的分頁(yè)系列文章再擴(kuò)充一點(diǎn),說(shuō)明一下查詢(xún)和分頁(yè)結(jié)合的情況,當(dāng)我們把查詢(xún)條件和查詢(xún)結(jié)果放到一個(gè)頁(yè)面上時(shí),查詢(xún)還是非常容易實(shí)現(xiàn)的,甚至不需要我們手工去從數(shù)據(jù)庫(kù)中查詢(xún)。 在本系列文章中的第二篇中,介紹了一種 Load On Demand的方式,我們?cè)谶@里需要繼續(xù)利用這種方式,并對(duì)其做一些小小的擴(kuò)展。這里我們使用 Hibernate3 作為持久化方案。 簡(jiǎn)單的介紹一下應(yīng)用情景,一個(gè)系統(tǒng)中包含了一些 Customer 的信息,我們需要對(duì)其進(jìn)行查詢(xún)并對(duì)查詢(xún)結(jié)果進(jìn)行分頁(yè)。 首先處理?xiàng)l件查詢(xún)的情況,通常會(huì)根據(jù) VO 中的字段進(jìn)行 like 型查詢(xún),有時(shí)候時(shí)間或數(shù)字之類(lèi)的會(huì)使用Between查詢(xún),因?yàn)椴樵?xún)條件一般不會(huì)很復(fù)雜,在這里,使用 Hibernate3 中的 Criteria 查詢(xún)來(lái)處理這樣的情況,我們把所有的查詢(xún)條件通過(guò) Customer 這個(gè) VO 傳進(jìn)來(lái),然后只對(duì)非空字段進(jìn)行 like 查詢(xún),我們用到這樣的方法。 public ListqueryByConditions(Customercustomer, int startRow, int pageSize)Criteriacriteria = getSession().createCriteria(Customer. class ); if ( ! StringUtils.isEmpty(customer.getCustomerName()criteria.add(QueryUtils.getCriteriaParam( customerName ,customer.getCustomerName(); if ( ! StringUtils.isEmpty(customer.getAddress()criteria.add(QueryUtils.getCriteriaParam( address ,customer.getAddress(); if ( ! StringUtils.isEmpty(customer.getFax()criteria.add(QueryUtils.getCriteriaParam( fax ,customer.getFax(); return criteriaPagedList(criteria,startRow,pageSize); 另外對(duì)應(yīng)的一個(gè)count方法略去,只需要在前面加入一個(gè)criteria.setProjection(Projections.count(customerId); 因?yàn)榭紤]到以后的擴(kuò)展,使用了一個(gè)Utils方法,QueryUtils.getCriteriaParam方法 public static final SimpleExpressiongetCriteriaParam(Stringname,Stringparam) return Expression.lik
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030年中國(guó)鑄造機(jī)械制造行業(yè)運(yùn)營(yíng)狀況與發(fā)展前景分析報(bào)告
- 2025-2030年中國(guó)金屬波紋管市場(chǎng)發(fā)展趨勢(shì)規(guī)劃研究報(bào)告
- 2025-2030年中國(guó)聚氨酯慢回彈海綿女性?xún)?nèi)衣市場(chǎng)運(yùn)營(yíng)狀況及發(fā)展規(guī)劃分析報(bào)告
- 2025-2030年中國(guó)綜合肺功能測(cè)定儀市場(chǎng)發(fā)展?fàn)顩r及投資策略研究報(bào)告
- 2025-2030年中國(guó)純鋯珠行業(yè)運(yùn)行現(xiàn)狀及發(fā)展前景分析報(bào)告
- 2025-2030年中國(guó)礦渣粉行業(yè)運(yùn)營(yíng)格局及發(fā)展趨勢(shì)分析報(bào)告
- 2025-2030年中國(guó)真空搬運(yùn)機(jī)械行業(yè)競(jìng)爭(zhēng)格局及發(fā)展趨勢(shì)分析報(bào)告
- 2025-2030年中國(guó)盆景行業(yè)競(jìng)爭(zhēng)狀況規(guī)劃研究報(bào)告
- 濮陽(yáng)職業(yè)技術(shù)學(xué)院《藥物合成實(shí)驗(yàn)》2023-2024學(xué)年第二學(xué)期期末試卷
- 吉林電子信息職業(yè)技術(shù)學(xué)院《施工技術(shù)與施工組織》2023-2024學(xué)年第二學(xué)期期末試卷
- 文化產(chǎn)業(yè)管理專(zhuān)業(yè)大學(xué)生職業(yè)生涯規(guī)劃書(shū)
- DSM-V美國(guó)精神疾病診斷標(biāo)準(zhǔn)
- 文獻(xiàn)的載體課件
- 2023年高考語(yǔ)文全國(guó)乙卷《長(zhǎng)出一地的好蕎麥》解析
- 混凝土強(qiáng)度回彈檢測(cè)方案
- 歷年中考地理生物變態(tài)難題
- 研學(xué)旅行課程標(biāo)準(zhǔn)(一)-前言、課程性質(zhì)與定位、課程基本理念、課程目標(biāo)
- 部編版二年級(jí)下冊(cè)語(yǔ)文教案全冊(cè)
- 解放牌汽車(chē)CA10B后鋼板彈簧吊耳加工工藝及夾具設(shè)計(jì)哈
- 大學(xué)專(zhuān)科《機(jī)電傳動(dòng)控制》課件
- 高中地理高清區(qū)域地理填圖冊(cè)
評(píng)論
0/150
提交評(píng)論