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

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

The fifth part of my described how you can . This blog entry will describe how you can use Spring Data JPA for sorting the query results. As an example I will be adding two new requirements for my example application:

  • The list of persons shown in the front page should be sorted in ascending order by using the last name of a person.
  • The search results should be sorted in ascending order by using the last name of a person.

Spring Data JPA offers four different ways to sort the query results. Each of these approaches is described with more details in the following Sections.

Sorting with Method Name

If you are building your queries by using the , you can sort the query results by using the OrderBy keyword in the name of your query method. If you want to search for persons whose last name matches with the given parameter and sort the query results, you can use the following query methods:

//Results are sorted in ascending order

public
 List
<Person
>
 findByLastNameOrderByLastNameAsc
(
String
 lastName
)
;


//Results are sorted in descending order

public
 List
<Person
>
 findByLastNameOrderByLastNameDesc
(
String
 lastName
)

Sorting with JPQL

If you are creating query method by using either @NamedQuery or @Query annotation as explained , you can sort the query results by using the ORDER BYkeyword of the JPQL. For example, if you want to get all persons and sort the query results in ascending order by using the last name of a person, you can use the following query:

SELECT
 p
 
FROM
 Person p
 
ORDER
 
BY
 p
.lastName
 
ASC

You can now consult  for finding out how you can use the@NamedQuery or @Query annotation to implement the actual query method.

Sorting with Sort Class

The second way to sort query results with Spring Data JPA is to use the class. You can use this approach for sorting the query results by following these steps:

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

I am going to describe to you three different ways for sorting the query results by using the Sort class. After that I will choose one of those methods and implement my first requirement with the selected method.

Query Generation by Method Name

You can pass the Sort object as a parameter to a query method, which uses the query generation by method name strategy. For instance, if you want search persons by last name and sort the results of the created query, you should add following method to your repository interface:

public
 List
<Person
>
 findByLastName
(
String
 lastName, Sort sort
)
;

If you are interested of finding out more information about this query generation strategy, you should read the .

JpaRepository

As you might remember from the previous parts of this tutorial, Spring Data JPA repositories are just interfaces which extend other interfaces. One of those special interfaces is the interface. This interface declares the public List<T> findAll(Sort sort) method, which returns a list of all entities and sorts the entities in the order specified by the Sort object given as a parameter. If you are interested of obtaining a sorted list of all entities, using this method is the best way to do it.

The second part of my Spring Data JPA tutorial .

JPA Criteria API

If you are creating your queries with the JPA criteria API, your repository interface must extend the  interface. This interface declares the public List<T> findAll(Specification<T> spec, Sort sort) method, which returns a list of entities matching with the Specification given as a parameter. The returned entities are sorted in the order specified by the Sort object given as a parameter.

So, if you are interested of sorting the results of a query constructed by using the JPA criteria API, you can do it by using the described method. If you need more information about Spring Data JPA and the JPA criteria API, you can read  of this tutorial.

Example

I am going to describe next how you can implement the first requirement by using thefindAll(Sort sort) method provided by the JpaRepository interface.

First, my repository interface must extend the JpaRepository interface. The source code of thePersonRepository is given in following:

import
 
org.springframework.data.jpa.repository.JpaRepository
;


public
 
interface
 PersonRepository
 
extends
 JpaRepository
<Person, Long
>
 
{


}

Second, I created a private method called sortByLastNameAsc() to RepositoryPersonServiceclass. This method is used in the findAll() method to obtain an instance of the Sort class. Third, I passed the obtained Sort object to the findAll() method of the JpaRepository interface. 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.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
)
;

   
 

    @Resource

   
 
private
 PersonRepository personRepository
;


    @Transactional
(readOnly
 
=
 
true
)

    @Override

   
 
public
 List
<Person
>
 findAll
(
)
 
{

        LOGGER.
debug
(
"Finding all persons"
)
;

       
 
//Passes the Sort object to the repository.

       
 
return
 personRepository.
findAll
(sortByLastNameAsc
(
)
)
;

   
 
}


   
 
/**
     * 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"
)
;

   
 
}

}

The last step was to fix the unit test of the findAll() method. The source code of the fixed unit test is given in following:

import
 
org.junit.Before
;

import
 
org.junit.Test
;

import
 
org.mockito.ArgumentCaptor
;

import
 
org.springframework.data.domain.Sort
;


import
 
static
 junit.
framework.
Assert.
assertEquals
;

import
 
static
 org.
mockito.
Mockito.
*;


public
 
class
 RepositoryPersonServiceTest
 
{

   
 

   
 
private
 RepositoryPersonService personService
;


   
 
private
 PersonRepository personRepositoryMock
;


    @Before

   
 
public
 
void
 setUp
(
)
 
{

        personService
 
=
 
new
 RepositoryPersonService
(
)
;


        personRepositoryMock
 
=
 mock
(PersonRepository.
class
)
;

        personService.
setPersonRepository
(personRepositoryMock
)
;

   
 
}


    @Test

   
 
public
 
void
 findAll
(
)
 
{

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

        when
(personRepositoryMock.
findAll
(any
(Sort.
class
)
)
).
thenReturn
(persons
)
;

       
 

        List
<Person
>
 returned
 
=
 personService.
findAll
(
)
;


        ArgumentCaptor
<Sort
>
 sortArgument
 
=
 ArgumentCaptor.
forClass
(Sort.
class
)
;

        verify
(personRepositoryMock, times
(
1
)
).
findAll
(sortArgument.
capture
(
)
)
;


        verifyNoMoreInteractions
(personRepositoryMock
)
;


        Sort actualSort
 
=
 sortArgument.
getValue
(
)
;

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


        assertEquals
(persons, returned
)
;

   
 
}

}

I have now demonstrated to you, how you can sort the persons presented in the front page of my example application in ascending order by using the last name of a person.

Sorting with Querydsl

If you are using Querydsl for building your queries, you can sort the query results by following these steps:

  • Create an instance of the  class.
  • Pass the created instance as a parameter to the findAll(Predicate predicate, OrderSpecifier order) method of the  interface.

I will now describe to you how you can implement my second requirement with Querydsl.

First, I am ensuring that my repository extends the QueryDslPredicateExecutor interface. The source code of the PersonRepository is given in following:

import
 
org.springframework.data.jpa.repository.JpaRepository
;

import
 
org.springframework.data.querydsl.QueryDslPredicateExecutor
;


public
 
interface
 PersonRepository
 
extends
 JpaRepository
<Person, Long
>, QueryDslPredicateExecutor
<Person
>
 
{


}

Second, I created a class called PersonPredicates which has one method: lastNameIsLike(). This method is used to build the required query predicate. The source code of this class is given in following:

import
 
com.mysema.query.types.Predicate
;

import
 
net.petrikainulainen.spring.datajpa.model.QPerson
;


public
 
class
 PersonPredicates
 
{


   
 
public
 
static
 Predicate lastNameIsLike
(
final
 
String
 searchTerm
)
 
{

        QPerson person
 
=
 QPerson.
person
;

       
 
return
 person.
lastName.
startsWithIgnoreCase
(searchTerm
)
;

   
 
}

}

The next step was to made some changes to the search() method of the RepositoryPersonServiceclass. This method is explained with more details in following:

  • The predicate is still obtained by calling the lastNameIsLike() method of the PersonPredicatesclass.
  • The OrderSpecifier instance is obtained by calling a private orderByLastNameAsc() method ofRepositoryPersonService class.
  • The predicate and the OrderSpecifier instance are passed as a parameter to thefindAll(Predicate predicate, OrderSpecifier order) method of my repository implementation.

The source code of the relevant parts of the RepositoryPersonService class is given in following:

import
 
com.mysema.query.types.OrderSpecifier
;

import
 
net.petrikainulainen.spring.datajpa.model.QPerson
;

import
 
org.slf4j.Logger
;

import
 
org.slf4j.LoggerFactory
;

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
)
;

   
 

    @Resource

   
 
private
 PersonRepository personRepository
;

   
 

    @Transactional
(readOnly
 
=
 
true
)

    @Override

   
 
public
 List
<Person
>
 search
(
String
 searchTerm
)
 
{

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


       
 
//Passes the specification created by PersonPredicates class and the OrderSpecifier object to the repository.

        Iterable
<Person
>
 persons
 
=
 personRepository.
findAll
(lastNameIsLike
(searchTerm
), orderByLastNameAsc
(
)
)
;


       
 
return
 constructList
(persons
)
;

   
 
}


   
 
/**
     * Returns an OrderSpecifier object which sorts person in ascending order by using the last name.
     * @return
     */

   
 
private
 OrderSpecifier
<String
>
 orderByLastNameAsc
(
)
 
{

       
 
return
 QPerson.
person.
lastName.
asc
(
)
;

   
 
}


   
 
private
 List
<Person
>
 constructList
(Iterable
<Person
>
 persons
)
 
{

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

       
 
for
 
(Person person
:
 persons
)
 
{

            list.
add
(person
)
;

       
 
}

       
 
return
 list
;

   
 
}

}

The last step was to the fix the unit test of the search() method. The source code of the fixed unit test is given in following:

import
 
com.mysema.query.types.Order
;

import
 
com.mysema.query.types.OrderSpecifier
;

import
 
com.mysema.query.types.expr.BooleanExpression
;

import
 
net.petrikainulainen.spring.datajpa.model.QPerson
;

import
 
org.junit.Before
;

import
 
org.junit.Test
;

import
 
org.mockito.ArgumentCaptor
;


import
 
static
 junit.
framework.
Assert.
assertEquals
;

import
 
static
 org.
mockito.
Mockito.
*;


public
 
class
 RepositoryPersonServiceTest
 
{

   
 
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
>
(
)
;

        when
(personRepositoryMock.
findAll
(any
(BooleanExpression.
class
), any
(OrderSpecifier.
class
)
)
).
thenReturn
(expected
)
;

       
 

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


        ArgumentCaptor
<OrderSpecifier
>
 orderArgument
 
=
 ArgumentCaptor.
forClass
(OrderSpecifier.
class
)
;

        verify
(personRepositoryMock, times
(
1
)
).
findAll
(any
(BooleanExpression.
class
), orderArgument.
capture
(
)
)
;


        verifyNoMoreInteractions
(personRepositoryMock
)
;


        OrderSpecifier actualOrder
 
=
 orderArgument.
getValue
(
)
;

        assertEquals
(Order.
ASC, actualOrder.
getOrder
(
)
)
;

        assertEquals
(QPerson.
person.
lastName, actualOrder.
getTarget
(
)
)
;


        assertEquals
(expected, actual
)
;

   
 
}

}

I have now demonstrated to you how you can you use Querydsl to sort the person search results in ascending order by using the last name of a person.

What is Next?

I have now described to you three different ways to sort the query results with Spring Data JPA. I have also implemented a fully functional example application, which is available at . The next part of my tutorial describes .

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

你可能感兴趣的文章
Response. AppendHeader使用大全及文件下载.net函数使用注意点(转载)
查看>>
jQuery最佳实践
查看>>
centos64i386下apache 403没有权限访问。
查看>>
jquery用法大全
查看>>
PC-BSD 9.2 发布,基于 FreeBSD 9.2
查看>>
css斜线
查看>>
Windows phone 8 学习笔记(3) 通信
查看>>
Revit API找到风管穿过的墙(当前文档和链接文档)
查看>>
Scroll Depth – 衡量页面滚动的 Google 分析插件
查看>>
Windows 8.1 应用再出发 - 视图状态的更新
查看>>
自己制作交叉编译工具链
查看>>
Qt Style Sheet实践(四):行文本编辑框QLineEdit及自动补全
查看>>
[物理学与PDEs]第3章习题1 只有一个非零分量的磁场
查看>>
onInterceptTouchEvent和onTouchEvent调用时序
查看>>
android防止内存溢出浅析
查看>>
4.3.3版本之引擎bug
查看>>
SQL Server表分区详解
查看>>
STM32启动过程--启动文件--分析
查看>>
垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
查看>>
淘宝的几个架构图
查看>>