Estou com dúvidas (na verdade perdido mesmo) em como implementar true pagination, que traz os dados paginados do banco e não pegar tudo do banco e paginar na memória.
Pesquisando, encontrei a classe abaixo, porém não sei o que vai no Managed Bean e no xhml (Uso richfaces e hibernate)
Um exemplo seria bem-vindo.
Muito obrigado,
Marques
import java.util.List;
import javax.faces.model.DataModel;
public class PagedDataModel extends DataModel {
private int rowIndex = -1;
private int totalNumRows;
private int pageSize;
@SuppressWarnings("unchecked")
private List list;
public PagedDataModel() {
super();
}
@SuppressWarnings("unchecked")
public PagedDataModel(List list, int totalNumRows) {
super();
setWrappedData(list);
this.totalNumRows = totalNumRows;
this.pageSize = list.size();
}
@SuppressWarnings("unchecked")
public PagedDataModel(List list, int totalNumRows, int pageSize) {
super();
setWrappedData(list);
this.totalNumRows = totalNumRows;
this.pageSize = pageSize;
}
@Override
public boolean isRowAvailable() {
if (list == null)
return false;
int rowIndex = getRowIndex();
if (rowIndex >= 0 && rowIndex < list.size())
return true;
else
return false;
}
@Override
public int getRowCount() {
return totalNumRows;
}
@Override
public Object getRowData() {
if (list == null)
return null;
else if (!isRowAvailable())
throw new IllegalArgumentException();
else {
int dataIndex = getRowIndex();
return list.get(dataIndex);
}
}
@Override
public int getRowIndex() {
try {
return (rowIndex % pageSize);
} catch (ArithmeticException e) {
return 0;
}
}
@Override
public void setRowIndex(int rowIndex) {
this.rowIndex = rowIndex;
}
@Override
public Object getWrappedData() {
return list;
}
@SuppressWarnings("unchecked")
@Override
public void setWrappedData(Object list) {
this.list = (List) list;
}
}
blz meu amigo, vou tentar te ajudar, bom esta classe ai vai te retornar um datamodel, para vc fazer um binding em seu datatable.
1 - pode ver que no construtor vc vai passar a lista, o numero total de linhas e da paginação e a quantidade de linhas por pagina;
2 - em seu managedbean vc tem que ter um atributo do tipo datamodel tipo:
public DataModel getTableModel(){
int totalSize = 0;
int first = 0;
int rows = 6;
//aqui é só para garantir que o table não fique nullo, ha vc precisa de um atributo table do tipo UIData
if(table != null){
first = table.getFirst();
rows = table.getRows();
}
try {
//aqui eu consulto a lista de usuarios passando o numero do primeiro resultado, e o numero de linhas para mostrar
usuarios = getFachada().consultaTodosUsuarios(first, rows);
//aqui eu consulto o numero total de usuarios cadastrados no banco
totalSize = getFachada().consultarTotalTodosUsuarios();
} catch (ServicoException ex) {
ex.printStackTrace();
}
// aqui eu retorno o datamodel com a lista, o numero total e o numero por página
return super.getPaginationDataModel( usuarios, totalSize, rows); // este cara aqui faz a mesma coisa que sua classe faz
}
lá no seu arquivo gui, vc vai fazer:
<rich:dataTable
id="tabelaPaginada"
styleClass="styleTable" rowClasses="odd-row,even-row"
cellspacing="0" value="#{actionUsuario.tableModel}" <!-- aqui o seu atributo do tipo DataModel -->
var="row"
binding="#{actionUsuario.table}" <!-- este aqui é o binding do atributo UIData do seu managedbean -->
rows="6"> <!-- este cara aqui é o numero de linhas para mostrar nesta tabela -->
.....
e vc pode usar o proprio componente do table para paginar e não vai ficar na memoria pq vc já esta tratando com a classe que vc criou ai
<f:facet name="footer">
<rich:datascroller for="tabelaPaginada" maxPages="10" /> <!-- um campo é o id do datatable e o outro é o número de paginas da paginação, vai aparecer de 10 em 10 números -->
</f:facet>
e quando há 2 lista(grid) na mesma página?!?
as 2 grids não aparecem ao mesmo tempo,
são apresentadas em diferentes status!
quando a 2ª grid esta sendo apresentada e a mesma possui paginação,
ao clicar para mudar de página, a ação gerada no backing esta sendo
como se fosse para a 1ª grid que no momento nem esta sendo exibida.
Bom dia galera… Estou tentando usar esse exemplo com SEAM mas estou com problemas:
PagedDataModel:
public class PagedDataModel extends DataModel {
private int rowIndex = -1;
private int totalNumRows;
private int pageSize;
private List<?> list;
public PagedDataModel() {
super();
}
public PagedDataModel(List<?> list, int totalNumRows) {
super();
setWrappedData(list);
this.totalNumRows = totalNumRows;
this.pageSize = list.size();
}
public PagedDataModel(List<?> list, int totalNumRows, int pageSize) {
super();
setWrappedData(list);
this.totalNumRows = totalNumRows;
this.pageSize = pageSize;
}
@Override
public boolean isRowAvailable() {
if (list == null)
return false;
int rowIndex = getRowIndex();
if (rowIndex >= 0 && rowIndex < list.size())
return true;
else
return false;
}
@Override
public int getRowCount() {
return totalNumRows;
}
@Override
public Object getRowData() {
if (list == null)
return null;
else if (!isRowAvailable())
throw new IllegalArgumentException();
else {
int dataIndex = getRowIndex();
return list.get(dataIndex);
}
}
@Override
public int getRowIndex() {
try {
return (rowIndex % pageSize);
} catch (ArithmeticException e) {
return 0;
}
}
@Override
public void setRowIndex(int rowIndex) {
this.rowIndex = rowIndex;
}
@Override
public Object getWrappedData() {
return list;
}
@Override
public void setWrappedData(Object list) {
this.list = (List<?>) list;
}
}
ManagedBean:
@Name("usuarioBean")
@Scope(ScopeType.PAGE)
public class UsuarioBean extends BaseBean{
private static final long serialVersionUID = -8176266937869789953L;
List<Usuario> usuarios;
@In(create = true, required=false)
private UsuarioSessionLocal usuarioSessionLocal;
@In(create = true)
private PagedDataModel pagedDataModel;
@In(create = true)
@Out
private UIData table;
private javax.faces.model.DataModel tableModel;
public javax.faces.model.DataModel getTableModel(){
int totalSize = 0;
int first = 0;
int rows = ConstantesUtil.MAX_RESULT;
//aqui é só para garantir que o table não fique nulo, ha vc precisa de um atributo table do tipo UIData
if(table != null){
first = table.getFirst();
rows = table.getRows();
}
try {
//aqui eu consulto a lista de usuarios passando o numero do primeiro resultado, e o numero de linhas para mostrar
usuarios = usuarioSessionLocal.getUsuarios(first, rows);
//aqui eu consulto o numero total de usuarios cadastrados no banco
totalSize = usuarioSessionLocal.getTotalUsuarios();
} catch (Exception e) {
e.printStackTrace();
}
// aqui eu retorno o datamodel com a lista, o numero total e o numero por página
pagedDataModel = new PagedDataModel(usuarios, totalSize, rows);
return (javax.faces.model.DataModel) pagedDataModel;
}
}
O problema que eu estou tendo inicialmente é no VALUE do datatable, ele não chama o método do meu bean que vai fazer a paginação (getTableModel). Se no value do dataTable eu passar #{usuarioBean.tableModel} ele dá o seguinte erro:
11:30:46,713 ERROR [viewhandler] Error Rendering View[/pages/acesso/usuario/usuarioMain.xhtml]
javax.faces.FacesException: javax.el.ELException: /pages/acesso/usuario/usuarioMain.xhtml @29,25 value="#{usuarioBean.tableModel}": Error reading 'tableModel' on type br.com.bb.acesso.bean.UsuarioBean_$$_javassist_seam_2
at javax.faces.component.UIData.getValue(UIData.java:612)
Se eu deixo como está, a tela abre, mas não chama o método que vai fazer a paginação.
Ai com isso ta fazendo a paginação certinha.
Com um porém, rss. Qdo eu clico pra ir pra segunda paginação, ele está entrando 3 vezes no getTableModel(), fazendo a mesma consulta 3 vezes.
[quote]Qdo eu clico pra ir pra segunda paginação, ele está entrando 3 vezes no getTableModel(), fazendo a mesma consulta 3 vezes.
Alguém tem idéia do pq ??[/quote]
Já vi essa dúvida em vários posts aqui mesmo no GUJ (e nao lembro de ter visto a resposta).
Sugiro a leitura do Capítulo " 6.7 Factory and manager components " do livro Seam In Action.
Pelo que compreendi: durante o ciclo de vida do JSF, o componente ui pode ser acessado/visitado várias vezes. É o comportamento normal do JSF.
A sugestão é utilizar o @Factory que executará a consulta na primeira vez e armazenará o valor na variável de contexto. Nas solicitações seguintes é recuperado o valor que foi armazenado.
Acredito que será necessário estudar sobre o @Factory, @Unwrap, @Observer para que você saiba como utilizá-los de uma forma onde a consulta no banco seja executada nos momentos apropriados.
Olá, pessoal.
Achei muito interessante o modelo de vocês, mas estou tendo problemas com a view, onde às vezes, tenho simplesmente a tela sem o layout do richfaces, sem tema. nada…
A imagem diz o que acontece mais do que se explicasse, muito embora, enquanto executo obtenho todos os dados do modo como preciso, porém após clicar duas vezes sobre o botão que chama o dataModel a rich:dataTable fica sem layout algum.
Podem me ajudar?
Este é o código da página:
public DataModel getDataModel() throws RegraNegocioException {
int totalListSize = 0;
int first = 0;
int rows = 0;
if (uiDataTable != null) {
first = uiDataTable.getFirst();
rows = uiDataTable.getRows();
}
List<Atendimento> atendimentos = new AtendimentoService().listarTodos(first, rows);
totalListSize = new AtendimentoService().count();
dataModel = new PagedDataModel(atendimentos, totalListSize, rows);
return dataModel;
}