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
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?
@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);
}
}
@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();
}
}
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);
}
}
@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();
}
}
<%@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>«</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>»</span>
</a></li>
</c:if>
</ul>
</nav>
</div>
</div>
</div>
</div>
</body>
</html>