<p:dataTable> 中的 sortMode="multiple" 和 lazy="true" 在分页期间清除多排序元数据
Posted
技术标签:
【中文标题】<p:dataTable> 中的 sortMode="multiple" 和 lazy="true" 在分页期间清除多排序元数据【英文标题】:sortMode="multiple" and lazy="true" in <p:dataTable> clears multisort meta during pagination 【发布时间】:2013-03-06 09:15:36 【问题描述】:我刚刚在“DataTable - Lazy Loading”的展示代码中启用了多重排序
datatableLazy.xhtml
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>CarDataTable</title>
</h:head>
<h:body>
<h:form id="form">
<p:dataTable var="car" value="#tableBean.lazyModel" paginator="true"
rows="10"
paginatorTemplate="RowsPerPageDropdown FirstPageLink PreviousPageLink CurrentPageReport NextPageLink LastPageLink"
rowsPerPageTemplate="5,10,15" id="carTable" lazy="true"
sortMode="multiple">
<p:ajax event="rowSelect" listener="#tableBean.onRowSelect"
update=":form:display" oncomplete="carDialog.show()" />
<p:column headerText="Model" sortBy="#car.model"
filterBy="#car.model">
<h:outputText value="#car.model" />
</p:column>
<p:column headerText="Year" sortBy="#car.year"
filterBy="#car.year">
<h:outputText value="#car.year" />
</p:column>
<p:column headerText="Manufacturer" sortBy="#car.manufacturer"
filterBy="#car.manufacturer">
<h:outputText value="#car.manufacturer" />
</p:column>
<p:column headerText="Color" sortBy="#car.color"
filterBy="#car.color">
<h:outputText value="#car.color" />
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
TableBean.java
package com.solartis.primefaces.sample;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.faces.bean.ManagedBean;
import org.primefaces.model.LazyDataModel;
@ManagedBean
public class TableBean
private LazyDataModel<Car> lazyModel;
private Car selectedCar;
private List<Car> cars = new ArrayList<Car>();
private final static String[] colors;
private final static String[] manufacturers;
static
colors = new String[10];
colors[0] = "Black";
colors[1] = "White";
colors[2] = "Green";
colors[3] = "Red";
colors[4] = "Blue";
colors[5] = "Orange";
colors[6] = "Silver";
colors[7] = "Yellow";
colors[8] = "Brown";
colors[9] = "Maroon";
manufacturers = new String[10];
manufacturers[0] = "Mercedes";
manufacturers[1] = "BMW";
manufacturers[2] = "Volvo";
manufacturers[3] = "Audi";
manufacturers[4] = "Renault";
manufacturers[5] = "Opel";
manufacturers[6] = "Volkswagen";
manufacturers[7] = "Chrysler";
manufacturers[8] = "Ferrari";
manufacturers[9] = "Ford";
public TableBean()
populateRandomCars(cars, 50);
lazyModel = new LazyCarDataModel(cars);
public Car getSelectedCar()
return selectedCar;
public void setSelectedCar(Car selectedCar)
this.selectedCar = selectedCar;
public LazyDataModel<Car> getLazyModel()
return lazyModel;
private void populateRandomCars(List<Car> list, int size)
for (int i = 0; i < size; i++)
list.add(new Car(getRandomModel(), getRandomYear(),
getRandomManufacturer(), getRandomColor()));
private String getRandomColor()
return colors[(int) (Math.random() * 10)];
private String getRandomManufacturer()
return manufacturers[(int) (Math.random() * 10)];
private int getRandomYear()
return (int) (Math.random() * 50 + 1960);
private String getRandomModel()
return UUID.randomUUID().toString().substring(0, 8);
LazyCarDataModel.java
package com.solartis.primefaces.sample;
import java.util.ArrayList;
/**
* Dummy implementation of LazyDataModel that uses a list to mimic a real
datasource like a database.
*/
public class LazyCarDataModel extends LazyDataModel<Car>
private List<Car> datasource;
public LazyCarDataModel(List<Car> datasource)
this.datasource = datasource;
@Override
public Car getRowData(String rowKey)
for(Car car : datasource)
if(car.getModel().equals(rowKey))
return car;
return null;
@Override
public void setRowIndex(int rowIndex)
if (rowIndex == -1 || getPageSize() == 0)
super.setRowIndex(-1);
else
super.setRowIndex(rowIndex % getPageSize());
@Override
public Object getRowKey(Car car)
return car.getModel();
@Override
public List<Car> load(int first, int pageSize,
List<SortMeta> multiSortMeta,Map<String, String> filters)
System.out.println("\nTHE INPUT PARAMETER VALUE OF LOAD METHOD :
\t"+"first=" + first + ", pagesize=" + pageSize + ", multiSortMeta=" +
multiSortMeta + " filter:" + filters);
System.out.println("\nTHE MULTISORTMETA CONTENT : \t");
if (multiSortMeta != null)
for (SortMeta sortMeta : multiSortMeta)
System.out.println("SORTFIELD:" +sortMeta.getSortField());
System.out.println("SORTORDER:" +sortMeta.getSortOrder());
System.out.println("SORTFUNCTION:"
+sortMeta.getSortFunction());
System.out.println("COLUMN:" +sortMeta.getColumn());
System.out.println("CLASS:" +sortMeta.getClass());
List<Car> data = new ArrayList<Car>();
//filter
for(Car car : datasource)
boolean match = true;
for(Iterator<String> it = filters.keySet().iterator(); it.hasNext();)
try
String filterProperty = it.next();
String filterValue = filters.get(filterProperty);
String fieldValue = String.valueOf(car.getClass().
getField(filterProperty).get(car));
if(filterValue == null || fieldValue.startsWith(filterValue))
match = true;
else
match = false;
break;
catch(Exception e)
match = false;
if(match)
data.add(car);
//rowCount
int dataSize = data.size();
this.setRowCount(dataSize);
//paginate
if(dataSize > pageSize)
try
return data.subList(first, first + pageSize);
catch(IndexOutOfBoundsException e)
return data.subList(first, first + (dataSize % pageSize));
else
return data;
它工作得很好,除了当我对多列排序进行分页时,List<SortMeta>
的 load()
方法不会给我当前排序的列详细信息以转移到其他页面,这与 load()
方法不同String sortField, SortOrder sortOrder
提供了这些排序细节。
例如:
点击“制造商”中的排序箭头,然后Ctrl+点击“年份”的排序箭头
您将获得load()
方法的排序列详细信息(我已在加载方法中打印了输入参数值)。
现在,进行分页。这里load()
方法无法给出排序列的详细信息
我该如何解决这个问题?
【问题讨论】:
你能解决这个问题吗? @Tiny:是的,通过手动处理多排序数据。 手动? 你的意思是使用你自己的 JS/jQuery 吗?如果可以的话,请将其添加为答案。 @Tiny: 当然..但不是通过 JS/JQuery 而是通过 java 编码本身。 您能否在此处添加该解决方案作为答案?如果您愿意,我可以针对您的问题发起bounty。 【参考方案1】:我临时解决了这个问题... 有一个 sessionscoped 托管 bean 用于存储排序列详细信息,以便在分页期间进入 load(), 喜欢:-
@ManagedBean
@SessionScoped
public class StoreSortColumnDetail implements Serializable
/** holds multisort values**/
private List<SortMeta> mMultiSortMeta;
public List<SortMeta> getMultiSortMeta()
return mMultiSortMeta;
public void setMultiSortMeta(List<SortMeta> multiSortMeta)
mMultiSortMeta = multiSortMeta;
public void clearMultiSortMeta()
if(this.mMultiSortMeta != null)
this.mMultiSortMeta.clear();
并像这样在 load() 中使用它:
@Override
public List<Car> load(int first, int pageSize,
List<SortMeta> multiSortMeta,Map<String, String> filters)
/** Instance to the SessionScoped scoped StoreSortColumnDetail managed bean*/
@ManagedProperty(value="#StoreSortColumnDetail ")
private StoreSortColumnDetail storeSortColumnDetail ;
public void setStoreSortColumnDetail (StoreSortColumnDetail sortColumnDetail )
this.storeSortColumnDetail = sortColumnDetail ;
/** to hold the handled sort column detail**/
List<SortMeta> handledMultiSortMeta = new ArrayList<SortMeta>();
/*Here starts the multisortmeta handling process*/
/** check for List<SortMeta> for null**/
if(multiSortMeta != null )
/** updates StoreSortColumnDetail's List<SortMeta> with Load()'s List<SortMeta>**/
storeSortColumnDetail.setMultiSortMeta(multiSortMeta);
handledMultiSortMeta = multiSortMeta;
/** check for List<SortMeta> for notnull **/
else if (multiSortMeta == null)
/**assigns Load()'s List<SortMeta> with StoreSortColumnDetail's List<SortMeta>**/
handledMultiSortMeta = storeSortColumnDetail.getMultiSortMeta();
/*Now u have handled multisortmeta from load()...
and u can process now from handledMultiSortMeta*/
我希望你知道我是如何处理的,如果不是亲密的话…… 但这是一种临时方式,需要通过primefaces方式处理...
【讨论】:
@Tiny:请看我的回答,然后给你的cmets 是的!感谢您回答这个问题。几天后我会看到这个,因为我这几天有点忙于其他事情。请继续保持。不要删除它。 是的,我试了一下,效果很好。尽管如此,它仍然不能满足我的要求,因为即使在呈现dataTable
之后,即当按下<p:commandButton>
将一行添加到数据库中时,客户端仍应保留sortColumn
(具有列突出显示和排序取消)因此进入dataTable
,这不会发生,因为使用了一些javascript魔法。我尝试了this 问题的答案,但不幸的是,它们都没有像预期的那样对我有用。你在你的应用程序中这样做了吗?非常感谢。
@Tiny: 很遗憾我没有接你的剧本。我会尽快通知你
@Tiny: 你能帮我解决这个不相关的问题吗:***.com/questions/17145023/…【参考方案2】:
虽然这种方法可能会奏效,但您可以轻松地将实际操作委托给您的lazyDataModel 中的 Primefaces。通过这样做,您可以使您的代码库更清晰,因为您不会有任何其他类可以操作,并且您将重用已经开发的组件(无论如何您都应该这样做)。
如果您检查了 PrimeFaces 源代码,您会发现 DataTable 使用具体的类来实现其每个功能,例如过滤、排序、扩展等...对于 Primefaces 排序使用一个名为 BeanPropertyComparator
的类,该类需要某些属性才能它的构造函数,但这些属性中的大多数可以从sortMeta
属性中获取,该属性发送到lazyDataModel 的load
方法。但是,如果您想获得所需的所有属性,则可以从 FacesContext
获得 DataTable 对象,前提是您知道相关 DataTable 的客户端 ID。
假设您在名为activeTable
的变量中拥有数据表实例,那么您所要做的就是:
UIColumn sortColumn = sortMeta.getSortColumn()
if(sortColumn.isDynamic())
((DynamicColumn)sortColumn).applyStatelessModel();
//for single mode sorting
ValueExpression sortByVal = activeTable.getValueExpression("sortBy");
//multiColumn sorting
ValueExpression sortByVal = sortColumn.getValueExpression("sortBy");
int caseSensitive = activeTable.isCaseSensitiveSort();
SortOrder order = sortMeta.getSortOrder();
MethodExpression exp = sortColumn.getSortFunction();
//pass required properties to constructor
//single mode sort
Collections.sort(filteredItems, new BeanPropertyComparator(......))
//for multi column sort use ChainedBeanPropertyComparator and add every new comparator to it than
Collections.sort(filteredItems, chainedComparator);
默认情况下,您的排序将支持 primefaces 默认机制支持的任何功能,而不会牺牲安全性。
【讨论】:
如果您覆盖核心 PF 类,最好也说明这是用于哪个版本! (事实上,最好随时提及版本信息) 你是对的,我相信这个解决方案适用于 5.0 以上的任何 primefaces 版本,这里也不是强制性的,我的意思是通过实例化一个新对象直接使用具体的 BeanPropertyComparator 类。以上是关于<p:dataTable> 中的 sortMode="multiple" 和 lazy="true" 在分页期间清除多排序元数据的主要内容,如果未能解决你的问题,请参考以下文章
<p:dataTable> 中的 sortMode="multiple" 和 lazy="true" 在分页期间清除多排序元数据
根据 p:dataTable 的每一行中的另一个 p:selectOneMenu 填充 p:selectOneMenu
如何从 p:dataTable 本身对 p:dataTable 进行 ajax 更新?