随笔-348  评论-598  文章-0  trackbacks-0

第三版是对第二版的一些简化,多了一个抽象基础类,方便调用。

页面代码(变成了user.defaultDataModel):

    <f:view>
        
<h:form id="formlist">    
            
<rich:dataTable id="carList" width="483" columnClasses="col" rows="#{user.pageSize}"
                value
="#{user.defaultDataModel}" var="car">            
                
<f:facet name="header">
                    
<rich:columnGroup>
                        
<h:column>
                            
<h:outputText styleClass="headerText" value="Name" />
                        
</h:column>
                        
<h:column>
                            
<h:outputText styleClass="headerText" value="Decription" />
                        
</h:column>
                        
<h:column>
                            
<h:outputText styleClass="headerText" value="Base Price" />
                        
</h:column>
                        
<h:column>
                            
<h:outputText styleClass="headerText" value="Time" />
                        
</h:column>
                        
<h:column>
                            
<h:outputText styleClass="headerText" value="操作" />
                        
</h:column>                        
                    
</rich:columnGroup>
                
</f:facet>
    
                
<h:column>
                    
<h:outputText value="#{car.name}" />
                
</h:column>
                
<h:column>
                    
<h:outputText value="#{car.description}" />
                
</h:column>
                
<h:column>
                    
<h:outputText value="#{car.baseprice}" />
                
</h:column>
                
<h:column>
                    
<h:outputText value="#{car.timestamp}" />
                
</h:column>
                
<h:column>
                    
<h:commandLink action="#{user.delete}" value="删除" >
                        
<f:param name="id" value="#{car.id}"/>
                    
</h:commandLink>
                
</h:column>                
            
</rich:dataTable>
            
<rich:datascroller for="carList" id="dc1"
            style
="width:483px" page="#{user.scrollerPage}"/>                        
        
</h:form>
    
</f:view>

DataPage.java(没有变化):
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;

    
/**
     * 
     * 
@param datasetSize
     *            数据集大小
     * 
@param startRow
     *            起始行
     * 
@param data
     *            数据list
     
*/

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

        
this.datasetSize = datasetSize;

        
this.startRow = startRow;

        
this.data = data;

    }


    
/**
     * 
     * 
@return
     
*/

    
public int getDatasetSize()
    
{

        
return datasetSize;

    }


    
public int getStartRow()
    
{

        
return startRow;

    }


    
/**
     * 
     * 
@return 已填充好的数据集
     
*/

    
public List getData()
    
{

        
return data;

    }


}


PagedListDataModel.java(添加了一些注释):
package com.jsecode.util.pagination;

import java.util.List;

import javax.faces.model.DataModel;

/**
 * 
 * TODO 分页所使用的类

 * 
@author <a href="mailto:tianlu@jsecode.com">TianLu</a>
 * 
@version $Rev$ <br>
 *          $Id$
 
*/

/* 使用方法:
 * 前台的功能模块Bean(例如User)中继承PageListBaseBean类,可根据您的需要进行相应修改
 * 前台控件像这样使用
 * <rich:dataTable id="carList" width="483" columnClasses="col" rows="#{user.pageSize}"
    value="#{user.defaultDataModel}" var="car">            
    <f:facet name="header">
        <rich:columnGroup>
            <h:column>
                <h:outputText styleClass="headerText" value="Name" />
            </h:column>
            <h:column>
                <h:outputText styleClass="headerText" value="Decription" />
            </h:column>
            <h:column>
                <h:outputText styleClass="headerText" value="Base Price" />
            </h:column>
            <h:column>
                <h:outputText styleClass="headerText" value="Time" />
            </h:column>
            <h:column>
                <h:outputText styleClass="headerText" value="操作" />
            </h:column>                        
        </rich:columnGroup>
    </f:facet>

    <h:column>
        <h:outputText value="#{car.name}" />
    </h:column>
    <h:column>
        <h:outputText value="#{car.description}" />
    </h:column>
    <h:column>
        <h:outputText value="#{car.baseprice}" />
    </h:column>
    <h:column>
        <h:outputText value="#{car.timestamp}" />
    </h:column>
    <h:column>
        <h:commandLink action="#{user.delete}" value="删除" >
            <f:param name="id" value="#{car.id}"/>
        </h:commandLink>
    </h:column>                
</rich:dataTable>
<rich:datascroller for="carList" id="dc1"
style="width:483px" page="#{user.scrollerPage}"/>
*/


/*
 * 进行删除等操作后会立即改变列表项并且返回列表页的,请调用本类的refresh方法刷新当前页面
 * 使用方法:
 *             dao.delete(bean);
 *            dataModel.refresh();
 
*/

public abstract class PagedListDataModel extends DataModel {
    
int pageSize;
    
int rowIndex;
    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() {
        
return getPage().getDatasetSize();
    }


    
/**
     * 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() {
        
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 < 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 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();
        
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 void refresh() {
        
if (this.page != null{
            
this.page = null;
            getPage();
        }

    }

}



新增加的PageListBaseBean.java文件,所有需要分页的bean继承此类,简化代码:
import com.jsecode.util.pagination.DataPage;
import com.jsecode.util.pagination.PagedListDataModel;

/*使用方法参考:
public class User extends PageListBaseBean
{
    @Override
    public PagedListDataModel getDefaultDataModel()
    {
        if ( defaultDataModel == null ) {
            defaultDataModel = new PagedListDataModel(pageSize)
            {
                public DataPage fetchPage(int startRow, int pageSize)
                {
                    // call enclosing managed bean method to fetch the data
                    CarBeanDAO dao = new CarBeanDAO();
                    String sql = "from CarBean model order by model.id desc";                
                    Query query = EntityManagerHelper.createQuery(sql);                    
                    query.setFirstResult(startRow);                    
                    query.setMaxResults(pageSize);                    
                    List list = query.getResultList();
                    Query q = EntityManagerHelper.createQuery("select count(*) from CarBean");
                    return new DataPage(Integer.parseInt(q.getSingleResult().toString()), startRow, list);                    
                }
            };
        }
        
        return defaultDataModel;
    }
}
* 如需添加多个分页功能,请自定义PagedListDataModel变量和实现相关getXXXDataModel方法
*/

/**
 * TODO 带分页功能的基类
 * 
 * 
@author <a href="mailto:tianlu@jsecode.com">TianLu</a>
 * 
@version $Rev$ <br>
 *          $Id$
 
*/

public abstract class PageListBaseBean {
    
/**
     * 当前页码,跟dataSroller的page属性绑定
     
*/

    
protected int scrollerPage = 1;
    
    
/**
     * 当前页面大小
     
*/

    
protected int pageSize = 10;
    
    
/**
     * 默认数据模型,如果你有多个数据集需要分页,请自定义PagedListDataModel和相应的getDataModel方法
     
*/

    
protected PagedListDataModel defaultDataModel;
    
    
public int getScrollerPage()
    
{
        
return scrollerPage;
    }


    
public void setScrollerPage(int scrollerPage)
    
{
        
this.scrollerPage = scrollerPage;
    }

    
    
public int getPageSize()
    
{
        
return pageSize;
    }


    
public void setPageSize(int pageSize)
    
{
        
this.pageSize = pageSize;
    }

    
    
public abstract PagedListDataModel getDefaultDataModel();


}



User中的delete方法:
    public String delete()
    
{
        FacesContext ctx 
= FacesContext.getCurrentInstance();
        
int id = Integer.parseInt(ctx.getExternalContext().getRequestParameterMap().get("id"));
        EntityManagerHelper.beginTransaction();
        CarBeanDAO dao 
= new CarBeanDAO();
        CarBean bean 
= dao.findById(id);
        
if(bean != null)
        
{            
            dao.delete(bean);
            dataModel.refresh();
        }

            
        EntityManagerHelper.commit();
        
return null;
    }

Faces-config.xml:
 <managed-bean>
  
<managed-bean-name>user</managed-bean-name>
  
<managed-bean-class>com.gcoresoft.jsfdemo.bean.User</managed-bean-class>
  
<managed-bean-scope>session</managed-bean-scope>
 
</managed-bean>

有人反映会出现获取两次DataModel的情况,为什么呢?
经过我的测试,是因为设置的datatable的rows属性的值大于了程序中pageSize的值,比如你设置rows="12",而你的pageSize设置的是10,那么JSF为了满足显示12条得条件,就会取两次数据集组成一个12跳得数据集显示出来,所以给定的rows属性最好可以使用相关管理bean的pageSize变量,这样前后台统一数据条目,提高性能和可操作性。

为了方便大家JSF的项目开发,后面我会推出一套我自己写的一个基于JSF的框架,当然此框架是基于实际项目成功实施后提取出来的,主要是简化了对表单的操作,增加一些常用的工具套件,例如分页,验证器等等。对表单操作部分的简化主要体现在:每种控件都可以和固定的模型绑定,这样操作模型就可以做到对前台控件的控制,比如后台取值可以使用attributes.get("username"),设置前台控件值可以使用attributes.put("username","admin"),对选择控件操作也更加简便,当使用put的方法的时候,前台会自动选择到那项,更重要的是这些简化不需要你写程序代码,写一些简单的配置文件即可,而且选择项不仅可以设置在配置文件中,还可以通过数据库等其他数据源获取,大大提高开发效率。

---------------------------------------------------------
专注移动开发

Android, Windows Mobile, iPhone, J2ME, BlackBerry, Symbian
posted on 2008-11-04 19:57 TiGERTiAN 阅读(3756) 评论(11)  编辑  收藏 所属分类: JavaJSF

评论:
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2008-11-05 10:13 | 千里冰封
怎么编码风格不一致,有些在大扩号在行的最后面,有些是大括号另起一行的。  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2008-11-05 13:15 | TiGERTiAN
@千里冰封
不好意思哦,有的是我自己的编码风格,有的是用了格式化工具格式化过的。  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2008-11-08 15:27 | ci
hehe  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2009-07-08 15:47 | Riverelt
楼主帮了我大忙了!实在是感谢~!  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2010-03-16 01:28 | Abby
我在JSF中就是用的你以上的方法,可是还是有一个很大的问题!比如:我现按照数据5条来分页,数据库中一共有11条数据,那么我的fetchPage()方法却被调用了3次后,开始报错!如下:
in getUserByPage Now!!
PagedListDataModel!!
1莉莉女19830101
10hhhfemale19630302
11ttmale19630302
2大飞男19800202
3Tinafemale19000203
count=11
rowIndex=0
startRow=0
rowIndex=1
startRow=0
rowIndex=2
startRow=0
rowIndex=3
startRow=0
rowIndex=4
startRow=0
PagedListDataModel!!
3Tinafemale19000203
count=11
rowIndex=5
startRow=5
PagedListDataModel!!
count=11
rowIndex=6
startRow=6
2010-3-15 17:36:06 com.sun.facelets.FaceletViewHandler handleRenderException
严重: Error Rendering View[/listPage.xhtml]
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at demo.PagedListDataModel.getRowData(PagedListDataModel.java:83)
at org.ajax4jsf.model.SequenceDataModel.getRowData(SequenceDataModel.java:147)
at org.richfaces.model.ModifiableModel$RowKeyWrapperFactory.wrapObject(ModifiableModel.java:75)
at org.richfaces.model.impl.expressive.ObjectWrapperFactory$2.convert(ObjectWrapperFactory.java:190)
at org.richfaces.model.impl.expressive.ObjectWrapperFactory.convertList(ObjectWrapperFactory.java:151)
at org.richfaces.model.impl.expressive.ObjectWrapperFactory.wrapList(ObjectWrapperFactory.java:188)
at org.richfaces.model.ModifiableModel.filter(ModifiableModel.java:252)
at org.richfaces.model.ModifiableModel.modify(ModifiableModel.java:240)
at org.richfaces.component.UIDataTable.createDataModel(UIDataTable.java:140)
at org.ajax4jsf.component.UIDataAdaptor.getExtendedDataModel(UIDataAdaptor.java:621)
at org.ajax4jsf.component.UIDataAdaptor.getRowCount(UIDataAdaptor.java:248)
at org.richfaces.component.UIDatascroller.getRowCount(UIDatascroller.java:362)
at org.richfaces.component.UIDatascroller.setupFirstRowValue(UIDatascroller.java:452)
at org.richfaces.component.RenderPhaseDataScrollerVisitor.afterRoot(RenderPhaseDataScrollerVisitor.java:191)
at org.richfaces.event.RenderPhaseComponentListener.beforePhase(RenderPhaseComponentListener.java:73)
at org.ajax4jsf.component.AjaxViewRoot.processPhaseListeners(AjaxViewRoot.java:183)
at org.ajax4jsf.component.AjaxViewRoot.encodeBegin(AjaxViewRoot.java:505)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:928)
at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:594)
at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:100)
at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:176)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:110)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
请指教??  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2010-03-16 01:34 | Abby

public class UsePage extends PageListBaseBean{

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
IUserDAO userDAO = (UserDAO)context.getBean("userDao");


//private IUserService userService;

private User user; // 当前对象

private String operation; // 操作标识符




public UsePage() {
datas = new ArrayList<User>();
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}



public void setDatas(List<User> datas) {
this.datas = datas;
}

public String getOperation() {
return operation;
}

public void setOperation(String operation) {
this.operation = operation;
}



/**
* 分页查询记录
*/



public String getUserByPage(){


defaultDataModel = this.getDefaultDataModel();
System.out.println("in getUserByPage Now!!");
return "listPage";
}


@Override
public PagedListDataModel getDefaultDataModel() {
// TODO Auto-generated method stub
if ( defaultDataModel == null ) {
defaultDataModel = new PagedListDataModel(pageSize)
{

public DataPage fetchPage(int startRow, int pageSize)
{
System.out.println("PagedListDataModel!!");
Map<String,Integer> pageMap = new HashMap<String,Integer>();
pageMap.put("start",startRow);
pageMap.put("end",pageSize);
//IUserDAO userDAO = (UserDAO)context.getBean("userDao");
List list= userDAO.getUserByPage(pageMap);
for(int i=0;i<list.size();i++){
User user = new User();
user = (User) list.get(i);
System.out.print(user.getId());
System.out.print(user.getName());
System.out.print(user.getSex());
System.out.println(user.getBirthday());
}
int count = userDAO.getCount();
System.out.println("count="+count);
return new DataPage(count, startRow, list);
}
};
}
return defaultDataModel;}

}其他代码都是一样的,就是这个地方不一样!!  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2010-03-16 13:08 | TiGERTiAN
明显数据没有取到,你最好检查一下。  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2010-03-17 22:26 | Abby
数据是取到了的,页面显示的就是我的pagesize规定的条数。可是问题是,我的<rich:datascroller>失效了,点击上一页、下一页都没有一点反映,页码也没有显示出来??这是什么原因呢??  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2010-03-17 22:43 | Abby
我的页面的内容以及写法,和你上面写的页面的代码是一样的,我采用的是xhtml的页面,可是结果却是上面提到的那样,实在不知道原因,请给点建议??谢谢!!  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2010-04-06 17:17 | luoyf
我和Abby碰到的情况一样,<rich:datascroller>失效了,点击下一页只跳到第二页就不动了;点击上一页,不管当前是几页,都是直接跳到第一页。求救...  回复  更多评论
  
# re: 【第三版】RichFaces中使用datatable和datascroller进行分页(使用数据库分页,改良版)(含源码)(JSF 1.2,RichFaces 3.2.1GA) 2010-04-06 19:11 | TiGERTiAN
@luoyf
你们debug一下呢,一年多前写的东西,我已经记的不太清楚了。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: