Paginação em spring boot, jpa e kotlin
Ao trabalhar com grandes volumes de dados, retornar todos os registros de uma única vez pode causar problemas de desempenho e aumentar o consumo de memória. Para resolver esse problema, o Spring Data JPA oferece suporte nativo à paginação através das interfaces Pageable e Page.
Configurando o Controller
No endpoint de listagem, utilizamos o parâmetro Pageable para receber automaticamente as informações de paginação enviadas na URL.
@GetMapping
fun findAll(@PageableDefault(page = 0, size = 10) pageable: Pageable):Page<BookResponse>{
return bookService.findAll(pageable).map { it.toResponse() }
}O que significa cada parâmetro?
page: página inicial (começa em 0).size: quantidade de registros por página.Pageable: objeto criado automaticamente pelo Spring contendo as informações de paginação e ordenação.
Exemplo de requisição:
GET /bookService
A camada de serviço apenas encaminha o objeto Pageable para o repositório.
fun findAll(pageable: Pageable): Page<BookModel> {
return bookRepository.findAll(pageable)
}Repository
Para utilizar paginação é necessário que o repositório herde de JpaRepository, pois esse método já disponibiliza a função findAll(Pageable).
interface BookRepository : JpaRepository<BookModel, String> {}Model
@Entity(name = "book")
data class BookModel(
@Id
@GeneratedValue(strategy = GenerationType.UUID)
@Column(length = 36, nullable = false, updatable = false)
@JdbcTypeCode(Types.VARCHAR)
var id: String? = null,
@Column(nullable = false)
var name:String,
@Column(nullable = false, precision = 10, scale = 2)
var price: BigDecimal,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "customer_id",
nullable = false,
foreignKey = ForeignKey(name = "fk_book_customer")
)
@OnDelete(action = OnDeleteAction.RESTRICT)
var customer: CustomerModel?=null
){
@Column(nullable = false)
@Enumerated(EnumType.STRING)
var status:BookStatus?=null
set(value){
if (field==BookStatus.CANCELED || field == BookStatus.DELETED){
throw Exception("Não é possível alterar um livro com status $field")
}
field=value
}
constructor(
id: String?=null,
name: String,
price: BigDecimal,
customer: CustomerModel?=null,
status: BookStatus?=null):this(id,name,price,customer){
this.status=status
}
}Conversão para Response
Para não expor nosso model na camada de controller, passamos um response no controller como função de extensão:
data class BookResponse(
var id: String? = null,
var name:String,
var price: BigDecimal,
var customer: CustomerModel?=null,
var status: BookStatus?=null
)fun BookModel.toResponse(): BookResponse {
return BookResponse(
id = this.id,
name = this.name,
status = this.status,
price = this.price,
customer = this.customer
)
}Podemos alterar o size e o page na url:
http://localhost:8080/book?size=1&page=0Exemplo de saída:
{
"content": [
{
"id": "2618f213-233e-405f-9216-da4496be0d1e",
"name": "livro0",
"price": 90.00,
"customer": {
"id": "a47504bb-f054-46dc-a687-5e8bcb221af8",
"name": "rafael",
"email": "email2",
"status": "ACTIVE"
},
"status": "ACTIVE"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 1,
"sort": {
"empty": true,
"unsorted": true,
"sorted": false
},
"offset": 0,
"unpaged": false,
"paged": true
},
"totalPages": 5,
"totalElements": 5,
"last": false,
"size": 1,
"number": 0,
"sort": {
"empty": true,
"unsorted": true,
"sorted": false
},
"numberOfElements": 1,
"first": true,
"empty": false
}
0 comentários