richfaces提供的rich:dataTable和rich:datascroller能够很好地,自动实现数据量较小的分页业务。
如果是海量的数据,一次将数据都放入cache做翻页会产生两个突出问题。一是会急剧消耗掉server的内存,另择对数据的变化无法及时更新到页面--除非及时更新cache,但这会带来并发,性能等问题。
都查出来的对立面是只查询当页数据。当然,也可以考虑中间方案--查询相邻几页信息。
为了描述简单起见,这里不对查询相邻页策略进行讨论,只对查询当页做进一步描述。
因为rich:datascroller是对rich:dataTable数据进行智能感知的,如果只查询当页,这里建议不使用该控件。怎么实现?自己实现分页!即实现首页/末页 前页/后页的控制。
<rich:panel id="scrollerPanel1" styleClass="scrollerPanel" bodyClass="panelBody"> <h:commandButton value="First" action="#{groupsBean.swichFirstPage}" style=" border-style: none; margin-right: 5px" disabled="#{groupsBean.disabledFirst}"/> <h:commandButton value="Previous" action="#{groupsBean.swichPreviousPage}" style=" border-style: none; margin-right: 5px" disabled="#{groupsBean.disabledFirst}"/> <h:panelGroup id="pagePanel"> <h:outputText value="Page " /> <h:selectOneMenu id="pageMenu" value="#{groupsBean.pageIndex}"> <f:selectItems value="#{groupsBean.pageNumbers}" /> <a4j:support event="onchange" action="#{groupsBean.swichPage}" reRender="groupForm" /> </h:selectOneMenu> <h:outputText value=" of #{groupsBean.pageCount}" /> </h:panelGroup> <h:commandButton value="Next" action="#{groupsBean.swichNextPage}" style=" border-style: none; margin-left: 5px; margin-right: 5px" disabled="#{groupsBean.disabledLast}"/> <h:commandButton value="Last" action="#{groupsBean.swichLastPage}" style=" border-style: none" disabled="#{groupsBean.disabledLast}"/> </rich:panel>
这里的groupsBean是关联页面的java类,它的scope是request级别,jsf页面要做keepAlive声明,否则翻页无法实现。
<a4j:keepAlive beanName="groupsBean"/>
按钮是否可用的逻辑是:
disabledFirst = pageIndex == 1;
disabledLast = pageIndex == pageCount;
这个赋值需要在构造时和翻页方法中处理。
为什么使用两个变量而不是把判断写在页面里:即
disabled="#{groupsBean.disabledFirst}
改成:
disabled="#{groupsBean.pageIndex == 1}
?因为我测试过,在翻页后,如果按F5刷新页面,此时pageIndex会初始化为1,而 groupsBean是keepAlive的,即没有离开该页面时,它的值是保留的,因此逻辑会产生歧义。
每执行一次翻页,访问一次数据库。其缺点是明显的--频繁访问数据库,即产生了频繁的服务器端和数据库服务器的网络交互,数据库服务器对IO的操作。但这要根据具体业务考虑,如果是频繁更新的业务,这么处理反而简单。
执行效果如下图: