Dúvida sobre paginação com Vraptor4 e Bootstrap

28 views
Skip to first unread message

Ricardo Johannsen

unread,
Jan 18, 2017, 8:06:14 PM1/18/17
to caelum-vraptor

Olá a todos,

Eu implementei um esquema de paginação utilizando o Vraptor4 com o Bootstrap, tentei fazer algo próximo(pelo menos a lógica) que o Spring Data utiliza para realizar a paginação dos registros, para isso criei as classes Pageable e Page.


Tudo funcionou perfeitamente, até o momento que coloquei uma busca na página, ou seja se eu pesquisar todos os usuários por nome “Maria”, se a consulta trouxer por exemplo 5 páginas, cada uma com 10 resultados, ao clicar na página 2, eu devo manter o parâmetro nome na requisição, ou seja, nos links do objeto de paginação devem ficar como no formato abaixo:



http://localhost:8080/seguranca/lista?page=0&nome=Maria

http://localhost:8080/seguranca/lista?page=1&nome=Maria

http://localhost:8080/seguranca/lista?page=2&nome=Maria

http://localhost:8080/seguranca/lista?page=3&nome=Maria

http://localhost:8080/seguranca/lista?page=4&nome=Maria



Para fazer esse tipo de tarefa no Spring utilizamos o componente UriComponentsBuilder, para enviar o parâmetro nome e substituir o parâmetro page.


Para manter esses parâmetros, tanto o page quanto o nome na requisição eu tentei utilizar um recurso da própria JSTL, tentei fazer assim



<c:set var="link" value="?${pageContext.request.queryString}&page=${pagina}" />



Sem sucesso, provavelmente porque eu estava fazendo errado mesmo.


Então parti para a solução atual, novamente implementar algo parecido com oque existe no Spring, criei meu próprio UriBuilder com a ajuda da biblioteca Http Components da apache, a cada click nos componentes de paginação envio a url atual e adiciono os parâmetros( código de paginação abaixo)


Minha dúvida é se essa forma de implementação é correta, se impacta alguma coisa na performance ou segurança da aplicação ou se existe alguma outra forma de implementar a paginação e manter o filtro nas páginas? A solução abaixo está funcionando mas fico meio receioso, os caras lá do Spring devem ter quebrado a cabeça pra implementar o UriComponentsBuilder, fazer vários testes complexos, bem ao contrário do meu que é bem simples. Ou então se existe alguma alternativa no Vraptor ou mesmo no CDI para fazer o build de urls ? Como vocês fazem paginação com filtros?


-Controlador


@Get("/usuario")

@Controller

public class UsuarioController {

@Inject

private UsuarioDAO repository;

@Inject

private Result result;


@Get

@Path("/lista")

public void lista(Pageable pageable, String nome){

Page<Usuario> pagina = repository.buscarPorNome(pageable,nome);

result.include("page",pagina);

}

}


-Converter para criar o objeto Pageable


@Convert(Pageable.class)

public class RequestConverter implements Converter<Pageable>{

@Inject

private HttpServletRequest request;


@Override

public Pageable convert(String arg0, Class<? extends Pageable> arg1) {

Pageable pageable = new Pageable(request);

return pageable;

}

}


public class Pageable {


private int pageNumber;

private int pageSize;

final private String queryString;

final private String urlRequested;


public Pageable(HttpServletRequest request) {


this.pageSize = 10;

String page = request.getParameter("page");

Integer currentPage = (page == null) ? 0 : Integer.valueOf(page);

this.pageNumber = currentPage;

this.queryString = request.getQueryString();

this.urlRequested = request.getRequestURL().toString();

}


public void setPageNumber(Integer page) {

this.pageNumber = page;

this.pageSize = 10;

}


public int getPageNumber() {

return pageNumber;

}


public int getPageSize() {

return pageSize;

}


public int getOffSet(){

return pageNumber * pageSize;

}


public void setPageNumber(int pageNumber) {

this.pageNumber = pageNumber;

}


public void setPageSize(int pageSize) {

this.pageSize = pageSize;

}


public String construirUrl(int page) throws URISyntaxException{

HttpGet httpget = new HttpGet(urlRequested);

URI uri = httpget.getURI();

URIBuilder builder = new URIBuilder(uri);

if (queryString != null && !queryString.isEmpty()) {

final List<NameValuePair> params = URLEncodedUtils.parse(queryString, StandardCharsets.UTF_8);

for (final NameValuePair param : params) {

builder.setParameter(param.getName(),param.getValue());

}

}

builder.setParameter("page",String.valueOf(page));

httpget = new HttpGet(builder.build());

return httpget.getURI().toString();

}

}


- Objeto que tem os dados para a paginação


public class Page<T> {


private List<T> lista;

private Long total;

private Pageable pageable;


public Page(List<T> lista,Pageable pageable, Long total) {


this.lista = lista;

this.total = total;

this.pageable = pageable;

}


public List<T> getLista() {

return lista;

}


public Long getTotal() {

return total;

}


public int getTotalPages() {

return total == 0 ? 1 : (int) Math.ceil((double) total / (double) 10);

}


public int getPageNumber(){

return this.pageable.getPageNumber();

}


public boolean isFirst() {

return this.pageable.getPageNumber() == 0;

}


public boolean isLast(){

return this.pageable.getPageNumber() == getTotalPages() -1;

}


public String buildUrl(int page) throws URISyntaxException{

return this.pageable.construirUrl(page);


}


}


- meu DAO


@Stateless

public class UsuarioDAO {


@Inject

private EntityManager manager;


public Page<Usuario> buscarPorNome(Pageable pageable, String nome){


CriteriaBuilder builder = manager.getCriteriaBuilder();

CriteriaQuery<Usuario> usuarioQuery = builder.createQuery(Usuario.class);

Root<Usuario> usuarioRoot = usuarioQuery.from(Usuario.class);

Path<String> nomePath = usuarioRoot.<String>get("nome");

Predicate predicate = builder.and();

if(nome != null && !nome.trim().equals("")){

predicate = builder.and(predicate,builder.like(nomePath,"%"+nome+"%"));

}

TypedQuery<Usuario> query = manager.createQuery(usuarioQuery.where(predicate));

query.setFirstResult(pageable.getOffSet());

query.setMaxResults(pageable.getPageSize()).getResultList();

return new Page<Usuario>(query.getResultList(),pageable,total(nome));

}


private Long total(String nome) {

CriteriaBuilder builder = manager.getCriteriaBuilder();

CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);

CriteriaQuery<Usuario> cqEntity = builder.createQuery(Usuario.class);

Root<?> entityRoot = criteriaQuery.from(cqEntity.getResultType());

Path<String> path = entityRoot.<String>get("nome");

criteriaQuery.select(builder.count(entityRoot));

Predicate predicate = builder.and();

if(nome != null && !nome.trim().equals("")){

predicate = builder.and(predicate,builder.like(path,"%"+nome+"%"));

}

return manager.createQuery(criteriaQuery.where(predicate)).getSingleResult();

}


}



- jsp que tem a lista paginada e um campo de pesquisa


<%@taglib tagdir="/WEB-INF/tags/template" prefix="template"%>

<!DOCTYPE html>

<html>

<head>

<script src="<c:url value='/assets/js/jquery-2.1.4.min.js'/>"></script>

<script src="<c:url value='/assets/js/bootstrap.min.js'/>"></script>

<script src="<c:url value='/assets/js/jquery.jqpagination.js'/>"></script>

<link rel="stylesheet"

href="<c:url value='/assets/css/pagination/jqpagination.css'/>" />

<link rel="stylesheet"

href="<c:url value='/assets/css/bootstrap.min.css'/>">

<link rel="stylesheet"

href="<c:url value='/assets/css/bootstrap-theme.min.css'/>">

<link rel="stylesheet" href="<c:url value='/assets/css/index.css'/>">

<link rel="stylesheet" href="<c:url value='/assets/css/forms.css'/>">

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

<div>

<div class="container min-container">

<h2 class="basic-title">Listar Usuários</h2>

<div class="container-fluid">

<form method="GET">

<div class="row">

<div class="form-group col-sm-6">

<label class="control-label" for="nome">Nome</label> <input

type="text" name="nome" value="${param.nome}" /> <input

type="submit" value="Pesquisar">

</div>

</div>

</form>

</div>

<div class="well">

<table

class="table table-condensed table-bordered table-striped table-hover">

<thead>

<tr>

<td>id</td>

<td>Nome</td>

<td>matricula <span class="dropup"><span

class="caret"></span></span>

</td>

<td>actions</td>

</tr>

</thead>

<tbody>

<c:forEach items='${page.lista}' var='object'>

<tr>

<td><a href="<c:url value='/usuario'/>/${object.usuarioId}">${object.usuarioId}</a></td>

<td>${object.nome}</td>

<td>${object.matricula}</td>

<td><a

href="<c:url value='/usuario/remove'/>/${object.usuarioId}">Remove</a></td>

</tr>

</c:forEach>

</tbody>

</table>

<div class="col-sm-12 text-center">

<nav>

<ul class="pagination pagination-sm">

<c:if test="${!page.first}">

<li><a href="${page.buildUrl(page.pageNumber-1)}"><span>&laquo;</span></a></li>

</c:if>

<c:forEach begin="1" end="${page.totalPages}" var="index">

<c:set var="pagina" value="${index-1}" />

<c:set var="link" value="${pagina}" />

<li

class="${page.pageNumber eq (index-1) ? 'active' : 'nonactive'}">

<a href="${page.buildUrl(link)}">${index}</a>

</li>

</c:forEach>

<c:if test="${!page.last}">

<li><a href="${page.buildUrl(page.pageNumber+1)}"> <span>&raquo;</span>

</a></li>

</c:if>

</ul>

</nav>

</div>

</div>

</div>

</div>

</body>

</html>


Carlos Spohr

unread,
Jan 19, 2017, 5:50:37 AM1/19/17
to caelum-...@googlegroups.com
Bom dia Ricardo,

O que eu costumo fazer que acabou com o meu sofrimento nesses casos, é quando o usuário preencher no form de busca esses dados fiquem num pequeno objeto na sessão do usuário...logo as suas URIs de nagevação entre as páginas somente necessitam do número da página mesmo.

O form de busca você pode preencher ele injetando esse objeto no result para facilitar a vida do usuário.

Daí sempre que o usuário clicar no botão de buscar, no seu método 'doBuscarQualquerCoisa', você volta a paginação pra zero por exemplo :)

Uma dica pra ti é criar um Map<String, InterfaceDosObjetosDeBusca> na session do seu usuário, assim você pode obter esses objetos de uma forma simples:

//....

FiltroBuscaUsuario filtros = this.sessionUsuario.getFiltro(SuaController.UMA_CONSTANTE_QUALQUER);

//....


--
Você recebeu essa mensagem porque está inscrito no grupo "caelum-vraptor" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para caelum-vraptor+unsubscribe@googlegroups.com.
Para postar nesse grupo, envie um e-mail para caelum-...@googlegroups.com.
Acesse esse grupo em https://groups.google.com/group/caelum-vraptor.
Para mais opções, acesse https://groups.google.com/d/optout.



--
Atenciosamente,
Carlos Alberto Junior Spohr Poletto

Reply all
Reply to author
Forward
0 new messages