博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Data JPA教程, 第七部分: Pagination(未翻译)
阅读量:7119 次
发布时间:2019-06-28

本文共 9193 字,大约阅读时间需要 30 分钟。

The previous part of my . This blog entry will describe how you can paginate the query results by using Spring Data JPA. In order to demonstrate the pagination support of Spring Data JPA, I will add two new requirements for my example application:

  • The person search results should be paginated.
  • The maximum number of persons shown on a single search result page is five.

I will explain the pagination support of Spring Data JPA and my example implementation in following Sections.

Pagination with Spring Data JPA

The key of component of the Spring Data JPA pagination support is the  interface which is implemented by  class. You can get a specific page of your query results by following these steps:

  • Create an instance of the  class.
  • Pass the created object as a parameter to the correct repository method.

The available repository methods are described in following:

  • If you want to simply paginate all objects found from the database, you should use the public Page<T> findAll(Pageable pageable) method of the  interface.
  • If you are building your queries by using the , you can paginate the query results by passing the Pageable instance as a parameter of your method. Check the Spring Data JPA reference manual for more details ().
  • If you are , you should use the public Page<T> findAll(Specification specification, Pageable pageable) method of the interface.
  • If you are , you should use the public Page<T> findAll(Predicate predicate, Pageable pageable) method of the interface.

After you have obtained the requested page, you can get a list of entities by calling thegetContent() method of the  interface.

Enough with the theory, lets take a look how the given requirements can be implemented with JPA criteria API.

Adding Pagination to Person Search Results

The given requirements can be implemented with JPA criteria API by following these steps:

  • Obtain the wanted page number.
  • Create the needed Specification instance.
  • Create the instance of a PageRequest class.
  • Pass the created Specification and PageRequest objects to the person repository.

First, I modified the search() method of the PersonService interface. In order to obtain the wanted page from the database, the repository needs to know what page it should be looking for. Thus, I had to add a new parameter to the search() method. The name of this parameter ispageIndex and it specifies the index of the wanted page. The declaration of the new search()methods is given in following:

public
 
interface
 PersonService
 
{


   
 
/**
     * Searches persons for a given page by using the given search term.
     * @param searchTerm
     * @param pageIndex
     * @return  A list of persons whose last name begins with the given search term and who are belonging to the given page.
     *          If no persons is found, this method returns an empty list. This search is case insensitive.
     */

   
 
public
 List
<Person
>
 search
(
String
 searchTerm,
 
int
 pageIndex
)
;

}

Second, since I am using the JPA criteria API for building the actual query, theRepositoryPersonService will obtain the needed specification by calling the static lastNameIsLike()method of PersonSpecifications class. The source code of the PersonSpecifications class is given in following:

import
 
org.springframework.data.jpa.domain.Specification
;


import
 
javax.persistence.criteria.CriteriaBuilder
;

import
 
javax.persistence.criteria.CriteriaQuery
;

import
 
javax.persistence.criteria.Predicate
;

import
 
javax.persistence.criteria.Root
;


public
 
class
 PersonSpecifications
 
{


   
 
public
 
static
 Specification
<Person
>
 lastNameIsLike
(
final
 
String
 searchTerm
)
 
{

       
 

       
 
return
 
new
 Specification
<Person
>
(
)
 
{

            @Override

           
 
public
 Predicate toPredicate
(Root
<Person
>
 personRoot, CriteriaQuery
<?>
 query, CriteriaBuilder cb
)
 
{

               
 
String
 likePattern
 
=
 getLikePattern
(searchTerm
)
;

               
 
return
 cb.
like
(cb.
lower
(personRoot.
<String
>get
(Person_.
lastName
)
), likePattern
)
;

           
 
}

           
 

           
 
private
 
String
 getLikePattern
(
final
 
String
 searchTerm
)
 
{

                StringBuilder pattern
 
=
 
new
 StringBuilder
(
)
;

                pattern.
append
(searchTerm.
toLowerCase
(
)
)
;

                pattern.
append
(
"%"
)
;

               
 
return
 pattern.
toString
(
)
;

           
 
}

       
 
}
;

   
 
}

}

Third, I need to create an instance of a PageRequest class and pass this instance to thePersonRepository. I created a private method called constructPageSpecification() to theRepositoryPersonService. This method simply creates a new instance of the PageRequest object and returns the created instance. The search method obtains the PageRequest instance by calling the constructPageSpecification() method.

The last step is to pass the created objects forward to the PersonRepository. The source code of the relevant parts of the RepositoryPersonService is given in following:

import
 
org.slf4j.Logger
;

import
 
org.slf4j.LoggerFactory
;

import
 
org.springframework.data.domain.Page
;

import
 
org.springframework.data.domain.PageRequest
;

import
 
org.springframework.data.domain.Pageable
;

import
 
org.springframework.data.domain.Sort
;

import
 
org.springframework.stereotype.Service
;

import
 
org.springframework.transaction.annotation.Transactional
;


import
 
javax.annotation.Resource
;


@Service

public
 
class
 RepositoryPersonService
 
implements
 PersonService
 
{

   
 

   
 
private
 
static
 
final
 Logger LOGGER
 
=
 LoggerFactory.
getLogger
(RepositoryPersonService.
class
)
;


   
 
protected
 
static
 
final
 
int
 NUMBER_OF_PERSONS_PER_PAGE
 
=
 
5
;


    @Resource

   
 
private
 PersonRepository personRepository
;


    @Transactional
(readOnly
 
=
 
true
)

    @Override

   
 
public
 List
<Person
>
 search
(
String
 searchTerm,
 
int
 pageIndex
)
 
{

        LOGGER.
debug
(
"Searching persons with search term: "
 
+
 searchTerm
)
;


       
 
//Passes the specification created by PersonSpecifications class and the page specification to the repository.

        Page requestedPage
 
=
 personRepository.
findAll
(lastNameIsLike
(searchTerm
), constructPageSpecification
(pageIndex
)
)
;


       
 
return
 requestedPage.
getContent
(
)
;

   
 
}


   
 
/**
     * Returns a new object which specifies the the wanted result page.
     * @param pageIndex The index of the wanted result page
     * @return
     */

   
 
private
 
Pageable
 constructPageSpecification
(
int
 pageIndex
)
 
{

       
 
Pageable
 pageSpecification
 
=
 
new
 PageRequest
(pageIndex, NUMBER_OF_PERSONS_PER_PAGE, sortByLastNameAsc
(
)
)
;

       
 
return
 pageSpecification
;

   
 
}


   
 
/**
     * Returns a Sort object which sorts persons in ascending order by using the last name.
     * @return
     */

   
 
private
 Sort sortByLastNameAsc
(
)
 
{

       
 
return
 
new
 Sort
(Sort.
Direction.
ASC,
 
"lastName"
)
;

   
 
}

}

I also had to modify the unit tests of the RepositoryPersonService class. The source code of the modified unit test is given in following:

import
 
org.junit.Before
;

import
 
org.junit.Test
;

import
 
org.mockito.ArgumentCaptor
;

import
 
org.springframework.data.domain.Page
;

import
 
org.springframework.data.domain.PageImpl
;

import
 
org.springframework.data.domain.Pageable
;

import
 
org.springframework.data.domain.Sort
;

import
 
org.springframework.data.jpa.domain.Specification
;


import
 
static
 junit.
framework.
Assert.
assertEquals
;

import
 
static
 org.
mockito.
Mockito.
*;


public
 
class
 RepositoryPersonServiceTest
 
{


   
 
private
 
static
 
final
 
long
 PERSON_COUNT
 
=
 
4
;

   
 
private
 
static
 
final
 
int
 PAGE_INDEX
 
=
 
1
;

   
 
private
 
static
 
final
 
Long
 PERSON_ID
 
=
 
Long.
valueOf
(
5
)
;

   
 
private
 
static
 
final
 
String
 FIRST_NAME
 
=
 
"Foo"
;

   
 
private
 
static
 
final
 
String
 FIRST_NAME_UPDATED
 
=
 
"FooUpdated"
;

   
 
private
 
static
 
final
 
String
 LAST_NAME
 
=
 
"Bar"
;

   
 
private
 
static
 
final
 
String
 LAST_NAME_UPDATED
 
=
 
"BarUpdated"
;

   
 
private
 
static
 
final
 
String
 SEARCH_TERM
 
=
 
"foo"
;

   
 

   
 
private
 RepositoryPersonService personService
;


   
 
private
 PersonRepository personRepositoryMock
;


    @Before

   
 
public
 
void
 setUp
(
)
 
{

        personService
 
=
 
new
 RepositoryPersonService
(
)
;


        personRepositoryMock
 
=
 mock
(PersonRepository.
class
)
;

        personService.
setPersonRepository
(personRepositoryMock
)
;

   
 
}

   
 

    @Test

   
 
public
 
void
 search
(
)
 
{

        List
<Person
>
 expected
 
=
 
new
 ArrayList
<Person
>
(
)
;

        Page expectedPage
 
=
 
new
 PageImpl
(expected
)
;

        when
(personRepositoryMock.
findAll
(any
(Specification.
class
), any
(
Pageable.
class
)
)
).
thenReturn
(expectedPage
)
;

       
 

        List
<Person
>
 actual
 
=
 personService.
search
(SEARCH_TERM, PAGE_INDEX
)
;


        ArgumentCaptor
<Pageable
>
 pageArgument
 
=
 ArgumentCaptor.
forClass
(
Pageable.
class
)
;

        verify
(personRepositoryMock, times
(
1
)
).
findAll
(any
(Specification.
class
), pageArgument.
capture
(
)
)
;

        verifyNoMoreInteractions
(personRepositoryMock
)
;


       
 
Pageable
 pageSpecification
 
=
 pageArgument.
getValue
(
)
;


        assertEquals
(PAGE_INDEX, pageSpecification.
getPageNumber
(
)
)
;

        assertEquals
(RepositoryPersonService.
NUMBER_OF_PERSONS_PER_PAGE, pageSpecification.
getPageSize
(
)
)
;

        assertEquals
(Sort.
Direction.
ASC, pageSpecification.
getSort
(
).
getOrderFor
(
"lastName"
).
getDirection
(
)
)
;

       
 

        assertEquals
(expected, actual
)
;

   
 
}

}

I have now described the parts of the source code which are using Spring Data JPA for implementing the new requirements. However, my example application has a lot of web application specific “plumbing” code in it. I recommend that you take a look of the because it can help you to get a better view of the big picture.

What is Next?

I have now demonstrated to you how you can paginate your query results with Spring Data JPA. If you are interested of seeing my example application in action, you can . The next part of my Spring Data JPA tutorial will describe .

转载地址:http://nlnel.baihongyu.com/

你可能感兴趣的文章
js定义到执行(转)
查看>>
Google陆续收购技能机器人技术公司——智能机器人未来是否会发热?
查看>>
前端埋点方法解析及优缺点分析
查看>>
笔记:Gitlab-CI部署流程
查看>>
面向对象-day02
查看>>
如果要学习web前端,需要学习什么
查看>>
《编写高质量代码:改善Java程序的151个建议》笔记
查看>>
LeetCode每日一题: 搜索插入位置(No.35)
查看>>
利用装饰器实现mock和api的局部分离切换
查看>>
-[UIView hitTest:withEvent:] 方法总结
查看>>
springboot
查看>>
ios设计规范(下)
查看>>
Git-github 的基本应用
查看>>
前端基础8:HTML5新增标签及CSS3新属性 viewport 动画
查看>>
GitHub+Hexo 搭建个人网站
查看>>
使用BitmapFactory压缩图片遇到的问题总结
查看>>
vue指令和特殊特性
查看>>
Wings-让单元测试智能全自动生成
查看>>
LAMP(CentOS 7.2)环境下搭建WordPress
查看>>
css几个居中的方法
查看>>