example - spring boot custom pageable
Paginación en Spring Data JPA(límite y desplazamiento) (4)
Quiero que el usuario pueda especificar el límite (el tamaño de la cantidad devuelta) y el desplazamiento (el primer registro devuelto / índice devuelto) en mi método de consulta.
Aquí están mis clases sin ninguna capacidad de búsqueda. Mi entidad:
@Entity
public Employee {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@Column(name="NAME")
private String name;
//getters and setters
}
Mi repositorio
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id")
public List<Employee> findByName(@Param("name") String name);
}
Mi interfaz de servicio:
public interface EmployeeService {
public List<Employee> findByName(String name);
}
Mi implementación de servicio:
public class EmployeeServiceImpl {
@Resource
EmployeeRepository repository;
@Override
public List<Employee> findByName(String name) {
return repository.findByName(name);
}
}
Ahora aquí está mi intento de proporcionar capacidades de paginación que admitan desplazamiento y límite. Mi clase de entidad sigue siendo la misma.
Mi "nuevo" repositorio toma un parámetro paginable:
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id")
public List<Employee> findByName(@Param("name") String name, Pageable pageable);
}
Mi "nueva" interfaz de servicio tiene dos parámetros adicionales:
public interface EmployeeService {
public List<Employee> findByName(String name, int offset, int limit);
}
Mi "nueva" implementación de servicio:
public class EmployeeServiceImpl {
@Resource
EmployeeRepository repository;
@Override
public List<Employee> findByName(String name, int offset, int limit) {
return repository.findByName(name, new PageRequest(offset, limit);
}
}
Esto sin embargo no es lo que quiero. PageRequest especifica la página y el tamaño (número de página y tamaño de la página). Ahora, especificando el tamaño es exactamente lo que quiero, sin embargo, no quiero especificar la página de inicio #, quiero que el usuario pueda especificar el registro / índice inicial. Quiero algo similar a
public List<Employee> findByName(String name, int offset, int limit) {
TypedQuery<Employee> query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id", Employee.class);
query.setFirstResult(offset);
query.setMaxResults(limit);
return query.getResultList();
}
Específicamente los métodos setFirstResult () y setMaxResult (). Pero no puedo usar este método porque quiero usar la interfaz del repositorio del empleado. (¿O es realmente mejor definir consultas a través del entityManager?) De todos modos, ¿hay alguna manera de especificar el desplazamiento sin usar el entityManager? ¡Gracias por adelantado!
Tal vez la respuesta es un poco tarde, pero pensé en lo mismo. Calcule la página actual según el desplazamiento y el límite. Bueno, no es exactamente lo mismo porque "asume" que el desplazamiento es un múltiplo del límite, pero tal vez su aplicación sea adecuada para esto.
@Override
public List<Employee> findByName(String name, int offset, int limit) {
// limit != 0 ;)
int page = offset / limit;
return repository.findByName(name, new PageRequest(page, limit);
}
Sugeriría un cambio de la arquitectura. Cambie su controlador o lo que sea que llame al servicio para darle inicialmente la página y el límite si es posible.
Probablemente no pueda hacerlo con datos de primavera jpa. Si el desplazamiento es muy pequeño, puede eliminar las declaraciones X superiores de la consulta después de la recuperación.
De lo contrario, podría definir el tamaño de página como el desplazamiento y comenzar en la página + 1.
Puedes hacer eso creando tu propio paginable.
Pruebe esta muestra básica. Funciona bien para mí:
public class ChunkRequest implements Pageable {
private int limit = 0;
private int offset = 0;
public ChunkRequest(int skip, int offset) {
if (skip < 0)
throw new IllegalArgumentException("Skip must not be less than zero!");
if (offset < 0)
throw new IllegalArgumentException("Offset must not be less than zero!");
this.limit = offset;
this.offset = skip;
}
@Override
public int getPageNumber() {
return 0;
}
@Override
public int getPageSize() {
return limit;
}
@Override
public int getOffset() {
return offset;
}
@Override
public Sort getSort() {
return null;
}
@Override
public Pageable next() {
return null;
}
@Override
public Pageable previousOrFirst() {
return this;
}
@Override
public Pageable first() {
return this;
}
@Override
public boolean hasPrevious() {
return false;
}
}
Debajo del código debería hacerlo. Estoy usando mi propio proyecto y probado en la mayoría de los casos.
uso:
Pageable pageable = new OffsetBasedPageRequest(offset, limit);
return this.dataServices.findAllInclusive(pageable);
y el código fuente:
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.data.domain.AbstractPageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.io.Serializable;
/**
* Created by Ergin
**/
public class OffsetBasedPageRequest implements Pageable, Serializable {
private static final long serialVersionUID = -25822477129613575L;
private int limit;
private int offset;
private final Sort sort;
/**
* Creates a new {@link OffsetBasedPageRequest} with sort parameters applied.
*
* @param offset zero-based offset.
* @param limit the size of the elements to be returned.
* @param sort can be {@literal null}.
*/
public OffsetBasedPageRequest(int offset, int limit, Sort sort) {
if (offset < 0) {
throw new IllegalArgumentException("Offset index must not be less than zero!");
}
if (limit < 1) {
throw new IllegalArgumentException("Limit must not be less than one!");
}
this.limit = limit;
this.offset = offset;
this.sort = sort;
}
/**
* Creates a new {@link OffsetBasedPageRequest} with sort parameters applied.
*
* @param offset zero-based offset.
* @param limit the size of the elements to be returned.
* @param direction the direction of the {@link Sort} to be specified, can be {@literal null}.
* @param properties the properties to sort by, must not be {@literal null} or empty.
*/
public OffsetBasedPageRequest(int offset, int limit, Sort.Direction direction, String... properties) {
this(offset, limit, new Sort(direction, properties));
}
/**
* Creates a new {@link OffsetBasedPageRequest} with sort parameters applied.
*
* @param offset zero-based offset.
* @param limit the size of the elements to be returned.
*/
public OffsetBasedPageRequest(int offset, int limit) {
this(offset, limit, new Sort(Sort.Direction.ASC,"id"));
}
@Override
public int getPageNumber() {
return offset / limit;
}
@Override
public int getPageSize() {
return limit;
}
@Override
public int getOffset() {
return offset;
}
@Override
public Sort getSort() {
return sort;
}
@Override
public Pageable next() {
return new OffsetBasedPageRequest(getOffset() + getPageSize(), getPageSize(), getSort());
}
public OffsetBasedPageRequest previous() {
return hasPrevious() ? new OffsetBasedPageRequest(getOffset() - getPageSize(), getPageSize(), getSort()) : this;
}
@Override
public Pageable previousOrFirst() {
return hasPrevious() ? previous() : first();
}
@Override
public Pageable first() {
return new OffsetBasedPageRequest(0, getPageSize(), getSort());
}
@Override
public boolean hasPrevious() {
return offset > limit;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OffsetBasedPageRequest)) return false;
OffsetBasedPageRequest that = (OffsetBasedPageRequest) o;
return new EqualsBuilder()
.append(limit, that.limit)
.append(offset, that.offset)
.append(sort, that.sort)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(limit)
.append(offset)
.append(sort)
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("limit", limit)
.append("offset", offset)
.append("sort", sort)
.toString();
}
}