应用Myfaces 进行On-demand loading分页

第一章
引入myfaces的其中一个t标签:

<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>

<t:dataTable id="data"

styleClass="scrollerTable"

headerClass="standardTable_Header"

footerClass="standardTable_Header" rowClasses="standardTable_Row1,standardTable_Row2" columnClasses="standardTable_Column,standardTable_ColumnCentered,standardTable_Column"

var="car" value="#{scrollerList.list}"

preserveDataModel="false" rows="10"></t:dataTable>

讲解:

t:dataTable标签是用来分页输出List数组

id定义分页表的id,

styleClass定义表的样式css类

headerClass定义表头的样式css类

footerClass定义表尾的样式css类

rowClasses定义行的样式css类

columnClasses定义列的样式css类

var定义每一条记录

value指定要分页的数据

rows指定每页显示数据

<t:dataScroller id="scroll_1" for="data" fastStep="10"

pageCountVar="pageCount" pageIndexVar="pageIndex"

styleClass="scroller" paginator="true" paginatorMaxPages="5"

paginatorTableClass="paginator"

paginatorActiveColumnStyle="font-weight:bold;" immediate="true"

actionListener="#{scrollerList.scrollerAction}">

</t: dataScroller >

讲解:

t:dataScroller显示分页信息

id定义分页格式id

for指向数据源

fastStep向前向后快进的页数

pageCountVar总页数

pageIndexVar当前页数

styleClass定义分页格式的css类

paginator是否显示页数变化轨迹

paginatorMaxPages指定页数变化轨迹中的数量

第二章
应用Myfaces 进行On-demand loading分页

index.jsp>>>

<%@ page session="false" contentType="text/xml;charset=utf-8"%>

<%

response.sendRedirect("dataScroller.jsf");

%>

dataScroller.jsp>>>页面中的图片和css请参见myfaces.apache.org的simple

<%@ page session="false" contentType="text/html;charset=utf-8"%>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>

<html>

    <%@include file="inc/head.inc"%>

    <body>



       <f:view>

           <h:form>



              <f:loadBundle

                  basename="org.apache.myfaces.examples.resource.example_messages"

                  var="example_messages" />



              <h:panelGroup id="body">



                  <t:dataTable id="data" styleClass="scrollerTable"

                     headerClass="standardTable_Header"

                     footerClass="standardTable_Header"

                     rowClasses="standardTable_Row1,standardTable_Row2"

                      columnClasses="standardTable_Column,standardTable_ColumnCentered,standardTable_Column"

                     var="car" value="#{scrollerList.dataModel}" preserveDataModel="true"

                     rows="10">

                     <h:column>

                         <f:facet name="header">

                         </f:facet>

                         <h:outputText value="#{car.id}" />

                     </h:column>



                     <h:column>

                         <f:facet name="header">

                            <h:outputText value="#{example_messages['label_cars']}" />

                         </f:facet>

                         <h:outputText value="#{car.type}" />

                     </h:column>



                     <h:column>

                         <f:facet name="header">

                            <h:outputText value="#{example_messages['label_color']}" />

                         </f:facet>

                         <h:outputText value="#{car.color}" />

                     </h:column>



                  </t:dataTable>



                  <h:panelGrid columns="1" styleClass="scrollerTable2"

                     columnClasses="standardTable_ColumnCentered">

                     <t:dataScroller id="scroll_1" for="data" fastStep="10"

                         pageCountVar="pageCount" pageIndexVar="pageIndex"

                         styleClass="scroller" paginator="true" paginatorMaxPages="5"

                         paginatorTableClass="paginator"

                         paginatorActiveColumnStyle="font-weight:bold;"

                         actionListener="#{scrollerList.scrollerAction}">

                         <f:facet name="first">

                            <t:graphicImage url="images/arrow-first.gif" border="1" />

                         </f:facet>

                         <f:facet name="last">

                            <t:graphicImage url="images/arrow-last.gif" border="1" />

                         </f:facet>

                         <f:facet name="previous">

                            <t:graphicImage url="images/arrow-previous.gif" border="1" />

                         </f:facet>

                         <f:facet name="next">

                            <t:graphicImage url="images/arrow-next.gif" border="1" />

                         </f:facet>

                         <f:facet name="fastforward">

                            <t:graphicImage url="images/arrow-ff.gif" border="1" />

                         </f:facet>

                         <f:facet name="fastrewind">

                            <t:graphicImage url="images/arrow-fr.gif" border="1" />

                         </f:facet>

                     </t:dataScroller>

                     <t:dataScroller id="scroll_2" for="data" rowsCountVar="rowsCount"

                         displayedRowsCountVar="displayedRowsCountVar"

                         firstRowIndexVar="firstRowIndex" lastRowIndexVar="lastRowIndex"

                         pageCountVar="pageCount"

                         pageIndexVar="pageIndex">

                         <h:outputFormat value="#{example_messages['dataScroller_pages']}"

                            styleClass="standard">

                            <f:param value="#{rowsCount}" />

                            <f:param value="#{displayedRowsCountVar}" />

                            <f:param value="#{firstRowIndex}" />

                            <f:param value="#{lastRowIndex}" />

                            <f:param value="#{pageIndex}" />

                            <f:param value="#{pageCount}" />

                         </h:outputFormat>

                     </t:dataScroller>

                  </h:panelGrid>

              </h:panelGroup>

              <t:commandLink value="test" immediate="true" />

           </h:form>

       </f:view>

    </body>

</html>



Car.java>>>

package org.apache.myfaces.examples.listexample;



import java.io.Serializable;



public class Car implements Serializable {

    /**

     * serial id for serialisation versioning

     */

    private static final long serialVersionUID = 1L;



    private String id;



    private String type;



    private String color;



    public Car() {



    }



    public Car(String id, String type, String color) {

       this.id = id;

       this.type = type;

       this.color = color;

    }



    public String getId() {

       return id;

    }



    public void setId(String id) {

       this.id = id;

    }



    public String getType() {

       return type;

    }



    public void setType(String type) {

       this.type = type;

    }



    public String getColor() {

       return color;

    }



    public void setColor(String color) {

       this.color = color;

    }

}





DataPage.java>>>

package org.apache.myfaces.examples.listexample;



import java.util.List;



public class DataPage {

    /**

     * 将需要的页的数据封装到一个DataPage中去, 这个类表示了我们需要的一页的数据,<br>

     * 里面包含有三个元素:datasetSize,startRow,和一个用于表示具体数据的List。<br>

     * datasetSize表示了这个记录集的总条数,查询数据的时候,使用同样的条件取count即可,<br>

     * startRow表示该页的起始行在数据库中所有记录集中的位置

     */

    private int datasetSize;



    private int startRow;



    private List data;



    /** */

    /**

     * Create an object representing a sublist of a dataset.

     *

     * @param datasetSize

     *            is the total number of matching rows available.

     *

     * @param startRow

     *            is the index within the complete dataset of the first element

     *            in the data list.

     *

     * @param data

     *            is a list of consecutive objects from the dataset.

     */

    public DataPage(int datasetSize, int startRow, List data) {

       this.datasetSize = datasetSize;

       this.startRow = startRow;

       this.data = data;

    }



    /** */

    /**

     * Return the number of items in the full dataset.

     */

    public int getDatasetSize() {

       return datasetSize;

    }



    /** */

    /**

     * Return the offset within the full dataset of the first element in the

     * list held by this object.

     */

    public int getStartRow() {

       return startRow;

    }



    /** */

    /**

     * Return the list of objects held by this object, which is a continuous

     * subset of the full dataset.

     */

    public List getData() {

       return data;

    }

}





DataScrollerList.java>>>

package org.apache.myfaces.examples.listexample;



import java.util.ArrayList;

import java.util.List;



import javax.faces.context.FacesContext;

import javax.faces.event.ActionEvent;

import javax.faces.model.DataModel;



import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.myfaces.custom.datascroller.ScrollerActionEvent;

import org.apache.myfaces.examples.dao.CarDAO;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;



public class DataScrollerList extends BasePagedBackingBean {

    private final Log log = LogFactory.getLog("DataScrollerList");



    private CarDAO carDAO = (CarDAO) getBean("carDAOBean");



    public DataScrollerList() {

       log.info("创建 DataScroller");

    }



    public void scrollerAction(ActionEvent event) {

       ScrollerActionEvent scrollerEvent = (ScrollerActionEvent) event;

       FacesContext.getCurrentInstance().getExternalContext().log(

              "scrollerAction: facet: " + scrollerEvent.getScrollerfacet()

                     + ", pageindex: " + scrollerEvent.getPageIndex());

    }



    public int getTotalCount() {

       int totalCount = 0;

       totalCount = carDAO.getTotalCount();

       return totalCount;

    }



    /**

     * 在DataScrollerList这个 Backing Bean中加一些东西,<br>

     * 调用业务逻辑,并将数据交给PagedListDataModel,来帮我们完成最后的分页工作。

     */

    public DataPage getDataPage(int startRow, int pageSize) {

       DataPage dataPage = carDAO.getDataPage(startRow, pageSize);

       return dataPage;



    }

}



BasePagedBackingBean.java>>>

package org.apache.myfaces.examples.listexample;



import javax.faces.model.DataModel;



import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;



public abstract class BasePagedBackingBean {

    private final Log log = LogFactory.getLog("BasePagedBackingBean");



    protected abstract DataPage getDataPage(int startRow, int pageSize);



    public abstract int getTotalCount();



    private DataModel dataModel;



    private int i = 0;



    // 为什么getDataModel这个方法要调用两次?非常不解啊

    public DataModel getDataModel() {

       i++;

       log.info("第" + i + "次调用 getDataModel.");

       if (dataModel == null) {

           log.info("创建 DataModel");

           dataModel = new LocalDataModel(10);

       }

       return dataModel;

    }



    public Object getBean(String beanName) {

       ApplicationContext ac = new ClassPathXmlApplicationContext(

              "spring/applicationContext.xml");

       Object ob = (Object) ac.getBean(beanName);

       return ob;

    }



    private class LocalDataModel extends PagedListDataModel {

       public LocalDataModel(int pageSize) {

           super(pageSize);

       }



       public int fetchRowCount() {

           return getTotalCount();

       }



       public DataPage fetchPage(int startRow, int pageSize) {

           // call enclosing managed bean method to fetch the data

           return getDataPage(startRow, pageSize);

       }

    }

}



PagedListDataModel.java>>>

package org.apache.myfaces.examples.listexample;



import javax.faces.model.DataModel;



import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;



/** */

/**

* A special type of JSF DataModel to allow a datatable and datascroller to page

* through a large set of data without having to hold the entire set of data in

* memory at once.

* <p>

* Any time a managed bean wants to avoid holding an entire dataset, the managed

* bean should declare an inner class which extends this class and implements

* the fetchData method. This method is called as needed when the table requires

* data that isn\'t available in the current data page held by this object.

* <p>

* This does require the managed bean (and in general the business method that

* the managed bean uses) to provide the data wrapped in a DataPage object that

* provides info on the full size of the dataset.

*/

/**

* 这个类里面的方法被myfaces<t:dataTable>调用顺序为:<br>

* 1.构造函数public PagedListDataModel(int pageSize) <br>

* 2.getRowCount()<br>

* 3.setRowIndex()<br>

* 4.public boolean isRowAvailable()<br>

* 5.public Object getRowData()

*/

public abstract class PagedListDataModel extends DataModel {

    private final Log log = LogFactory.getLog("PagedListDataModel");



    int pageSize;



    int rowIndex;



    private int rowCount = -1;



    DataPage page;



    /** */

    /**

     * Create a datamodel that pages through the data showing the specified

     * number of rows on each page.

     */

    public PagedListDataModel(int pageSize) {

       super();

       this.pageSize = pageSize;

       this.rowIndex = -1;

       this.page = null;

    }



    /** */

    /**

     * Not used in this class; data is fetched via a callback to the fetchData

     * method rather than by explicitly assigning a list.

     */

    public void setWrappedData(Object o) {

       if (o instanceof DataPage) {

           this.page = (DataPage) o;

       } else {

           throw new UnsupportedOperationException("setWrappedData");

       }

    }



    public int getRowIndex() {

       return rowIndex;

    }



    /** */

    /**

     * Specify what the "current row" within the dataset is. Note that the

     * UIData component will repeatedly call this method followed by getRowData

     * to obtain the objects to render in the table.

     */

    public void setRowIndex(int index) {

       rowIndex = index;

    }



    /**

     * Return the total number of rows of data available (not just the number of

     * rows in the current page!).

     */

    public int getRowCount() {

       if (rowCount < 0) {

           log.info("默认rowCount:" + rowCount);

           rowCount = fetchRowCount();

           log.info("初始化rowCount:" + rowCount);

       }

       return rowCount;

    }



    /**

     * Return a DataPage object; if one is not currently available then fetch

     * one. Note that this doesn\'t ensure that the datapage returned includes

     * the current rowIndex row; see getRowData.

     */

    private DataPage getPage(String name) {

       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

       log.info("getPage:" + name + "创建page");

       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 < 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);

           rowCount = page.getDatasetSize();//

           log.info("getRowData:创建page");

       }

       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) {

           log.info("fetchPage:向前取数据,getRowData:创建page,rowIndex:" + rowIndex);

           page = fetchPage(rowIndex, pageSize);

           log.info("翻页之前rowCount:" + rowCount);

           rowCount = page.getDatasetSize();//

           log.info("翻页之后rowCount:" + rowCount);

           startRow = page.getStartRow();

       } else if (rowIndex >= endRow) {

           log.info("fetchPage:向后取数据,getRowData:创建page,rowIndex:" + rowIndex);

           page = fetchPage(rowIndex, pageSize);

           log.info("翻页之前rowCount:" + rowCount);

           rowCount = page.getDatasetSize();//

           log.info("翻页之后rowCount:" + rowCount);

           startRow = page.getStartRow();

       }

       return page.getData().get(rowIndex - startRow);

    }



    public Object getWrappedData() {

       return page.getData();

    }



    /** */

    /**

     * Return true if the rowIndex value is currently set to a value that

     * matches some element in the dataset. Note that it may match a row that is

     * not in the currently cached DataPage; if so then when getRowData is

     * called the required DataPage will be fetched by calling fetchData.

     */

    public boolean isRowAvailable() {

       DataPage page = getPage("isRowAvailable");

       if (page == null) {

           return false;

       }

       int rowIndex = getRowIndex();



       if (rowIndex < 0) {

           return false;

       } else if (rowIndex >= page.getDatasetSize()) {

           return false;

       } else {

           return true;

       }

    }



    /** */

    /**

     * Method which must be implemented in cooperation with the managed bean

     * class to fetch data on demand.

     */

    public abstract DataPage fetchPage(int startRow, int pageSize);



    public abstract int fetchRowCount();

}



CarDAO.java>>>

package org.apache.myfaces.examples.dao;



import org.apache.myfaces.examples.listexample.DataPage;



public interface CarDAO {

    public DataPage getDataPage(int startRow, int pageSize);



    public int getTotalCount();

}



CarDAOImpl.java>>>

package org.apache.myfaces.examples.dao.impl;



import java.util.List;



import org.apache.myfaces.examples.dao.CarDAO;

import org.apache.myfaces.examples.listexample.DataPage;

import org.hibernate.Query;

import org.hibernate.Session;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;



public class CarDAOImpl extends HibernateDaoSupport implements CarDAO {



    public DataPage getDataPage(int startRow, int pageSize) {

       DataPage page = new DataPage(getCountCars(), startRow, getCars(

              startRow, pageSize));

       return page;

    }



    public int getTotalCount() {

       return getCountCars();

    }



    public List getCars(int startRow, int pageSize) {

       Session session = this.getSession();

       String sql = "from Car";

       Query query = session.createQuery(sql);

       query.setFirstResult(startRow);

       query.setMaxResults(pageSize);

       List list = query.list();

       return list;

    }



    public int getCountCars() {

       String sql = "select count(*) from Car";

       List list = getHibernateTemplate().find(sql);

       int count = 0;

       if (list.size() > 0) {

           count = ((Long) list.get(0)).intValue();

       }

       return count;

    }

}

配置文件:

web.xml>>>

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"

    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <listener>

       <listener-class>

           org.apache.myfaces.webapp.StartupServletContextListener

       </listener-class>

    </listener>

    <listener>

       <listener-class>

           org.springframework.web.util.Log4jConfigListener

       </listener-class>

    </listener>

    <context-param>

       <param-name>contextConfigLocation</param-name>

       <param-value>

           /WEB-INF/classes/spring/applicationContext.xml

       </param-value>

    </context-param>

    <context-param>

       <param-name>log4jConfigLocation</param-name>

       <param-value>/WEB-INF/classes/log4j.properties</param-value>

    </context-param>

    <context-param>

       <param-name>log4jRefreshInterval</param-name>

       <param-value>60000</param-value>

    </context-param>

    <servlet>

       <servlet-name>context</servlet-name>

       <servlet-class>

           org.springframework.web.context.ContextLoaderServlet

       </servlet-class>

       <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet>

       <servlet-name>Faces Servlet</servlet-name>

       <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>

       <load-on-startup>0</load-on-startup>

    </servlet>

    <servlet-mapping>

       <servlet-name>Faces Servlet</servlet-name>

       <url-pattern>*.jsf</url-pattern>

    </servlet-mapping>

    <welcome-file-list>

       <welcome-file>index.jsp</welcome-file>

    </welcome-file-list>

    <error-page>

       <error-code>500</error-code>

       <location>/error.jsp</location>

    </error-page>

</web-app>



Car.hbm.xml>>>

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!--

    Mapping file autogenerated by MyEclipse - Hibernate Tools

-->

<hibernate-mapping>

    <class name="org.apache.myfaces.examples.listexample.Car" table="CAR">

        <id name="id" type="java.lang.String">

            <column name="ID" precision="22" scale="0" />

            <generator class="assigned" />

        </id>

        <property name="type" type="java.lang.String">

            <column name="TYPE" length="20" />

        </property>

        <property name="color" type="java.lang.String">

            <column name="COLOR" length="20" />

        </property>

    </class>

</hibernate-mapping>

faces-config.xml>>>

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">



<faces-config>

    <!-- Managed Beans for dataScroller.jsp -->

    <managed-bean>

        <managed-bean-name>scrollerList</managed-bean-name>

       <managed-bean-class>

           org.apache.myfaces.examples.listexample.DataScrollerList

       </managed-bean-class>

       <managed-bean-scope>session</managed-bean-scope>

    </managed-bean>

    <navigation-rule>

       <navigation-case>

           <from-outcome>go_datascroller</from-outcome>

           <to-view-id>/dataScroller.jsp</to-view-id>

       </navigation-case>

    </navigation-rule>

</faces-config>

applicationConfig.xml>>>

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <!-- 

       <bean id="dataSource"

       class="org.springframework.jndi.JndiObjectFactoryBean">

       <property name="jndiName">

       <value>java:comp/env/VSPN18DATASOURCE</value>

       </property>

       </bean>

    -->

    <bean id="dataSource"

       class="org.apache.commons.dbcp.BasicDataSource"

       destroy-method="close">

       <property name="driverClassName"

           value="oracle.jdbc.driver.OracleDriver" />

       <property name="url"

           value="jdbc:oracle:thin:@localhost:1521:oracle" />

       <property name="username" value="vst" />

       <property name="password" value="vst" />

       <property name="maxActive" value="100" />

       <property name="maxIdle" value="30" />

       <property name="maxWait" value="1000" />

    </bean>

    <bean id="sessionFactory"

       class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

       <property name="dataSource">

           <ref bean="dataSource" />

       </property>

       <property name="mappingResources">

           <list>

              <value>org\apache\myfaces\examples\listexample\Car.hbm.xml</value>

           </list>

       </property>

       <property name="hibernateProperties">

           <props>

              <prop key="hibernate.dialect">

                  org.hibernate.dialect.OracleDialect

              </prop>

              <prop key="hibernate.show_sql">true</prop>

           </props>

       </property>

    </bean>

    <bean id="transactionManager"

       class="org.springframework.orm.hibernate3.HibernateTransactionManager">

       <property name="sessionFactory">

           <ref local="sessionFactory" />

       </property>

    </bean>

    <bean id="carDAO"

       class="org.apache.myfaces.examples.dao.impl.CarDAOImpl">

       <property name="sessionFactory">

           <ref local="sessionFactory" />

       </property>

    </bean>

    <bean id="carDAOBean"

       class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

       <property name="transactionManager">

           <ref bean="transactionManager" />

       </property>

       <property name="target">

           <ref local="carDAO" />

       </property>

       <property name="transactionAttributes">

           <props>

              <prop key="insert*">PROPAGATION_REQUIRED</prop>

              <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>

           </props>

       </property>

    </bean>

</beans>



log4j.properties>>>

log4j.rootLogger=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

#log4j.logger.uk.ltd.getahead.dwr = ERROR

log4j.logger.org.hibernate = ERROR

log4j.logger.org.springframework= ERROR

log4j.logger.org.apache.myfaces= ERROR

你可能感兴趣的:(apache,bean,Hibernate,log4j,JSF)