Spring Data JPA分页和排序示例
在这个Spring Data JPA分页和排序示例中,我们将看到如何使用PagingAndSortingRepository通过提供每页记录数和页码来对访问进行分页。我们也可以通过传递对字段进行排序的字段(或者字段组)以及页面属性或者单独对记录进行排序。
我们将使用Spring Web MVC创建一个Rest Web服务,使用的JPA实现是Hibernate,DB是MySQL。
对于示例和设置EntityManagerFactory和Web应用程序的配置类所需的maven依赖关系,可以参考这篇文章。Spring Data JPA @Query Annotation Example
数据库表查询
可以使用以下查询创建用于此Spring数据JPA的MySQL DB表。
CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(45) DEFAULT NULL, `last_name` varchar(45) DEFAULT NULL, `department` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
JPA实体类
这是映射到DB中的employee表的实体类。
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name="first_name")
private String firstName;
@Column(name="last_name")
private String lastName;
@Column(name="department")
private String dept;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Id= " + getId() + " First Name= " +
getFirstName() + " Last Name= " + getLastName() +
" Dept= "+ getDept();
}
}
@Entity注释指定此模型类为实体。
@Table注释指定实体的主表。
@Id注释指定实体的主键。
@GeneratedValue指定主键生成策略,在这种情况下,该策略是自动递增的。
@Column注释指定该字段的映射表列名称。
Spring Data JPA存储库
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import com.theitroad.springproject.model.Employee;
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
List<Employee> findByLastName(String lastName, Pageable pageable);
List<Employee> findByDept(String dept, Sort sort);
}
EmployeeRepository接口有两种方法
findByLastName –传递Pageable对象以提供分页属性的位置。
findByDept –在此方法中,传递了Sort对象以提供排序选项。
我们可以看到EmployeeRepository接口扩展了JpaRepository,它使用域类来管理(在这种情况下为Employee),并且将域类的id类型作为类型参数。由于JpaRepository扩展了PagingAndSortingRepository,因此界面间接扩展了PagingAndSortingRepository。
PagingAndSortingRepository扩展了CrudRepository接口,并定义了自己的两种方法。
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
/**
* Returns all entities sorted by the given options.
*/
Iterable<T> findAll(Sort sort);
/**
* Returns a Page of entities meeting the paging restriction provided in the Pageable object.
*/
Page<T> findAll(Pageable pageable);
}
休息控制器
使用Rest控制器类,我们会将路径映射到要为请求调用的方法。在Controller类的方法中,也将通过@RequestParam接收用于传递Pageable和Sort对象创建的参数。
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.theitroad.springproject.model.Employee;
import com.theitroad.springproject.service.EmployeeService;
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
EmployeeService empService;
@GetMapping("/{id}")
public Employee getEmployeeById(@PathVariable int id) {
return empService.getEmployeeById(id);
}
@GetMapping
public List<Employee> getAllEmployees(@RequestParam(value="pageNo", defaultValue="0") Integer pageNo,
@RequestParam(value="sortKey", defaultValue="lastName") String sortKey)
{
return empService.getAllEmployees(pageNo, sortKey);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.OK)
public void deleteEmployeeById(@PathVariable int id){
empService.deleteEmployeeById(id);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Employee addEmployee(@RequestBody Employee emp) {
return empService.addEmployee(emp);
}
@GetMapping("/lastname/{lastName}")
public List<Employee> getEmployeeByLastName(@PathVariable String lastName,
@RequestParam(value="pageNo", defaultValue="0") Integer pageNo)
{
return empService.getEmployeeByLastName(lastName, pageNo);
}
@GetMapping("/dept/{department}")
public List<Employee> getEmployeeByDepartment(@PathVariable String department) {
return empService.getEmployeeByDepartment(department);
}
}
Spring Data JPA示例–服务类
在服务层,我们将调用存储库方法。请注意,必须将存储库实例注入服务类中。
在Service类中,我们将创建在方法中传递的Pageable和Sort对象。
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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 com.theitroad.springproject.dao.EmployeeRepository;
import com.theitroad.springproject.model.Employee;
@Service
public class EmployeeService {
@Autowired
private EmployeeRepository repository;
public Employee getEmployeeById(int id) {
return repository.findById(id).get();
}
public List<Employee> getAllEmployees(Integer pageNo, String sortKey)
{
// Setting no. of records in each page, page no., sort field
int noOfRecords = 2;
Pageable page = PageRequest.of(pageNo, noOfRecords, Sort.by(sortKey));
Page<Employee> pagedResult = repository.findAll(page);
// changing to List
return pagedResult.getContent();
}
public void deleteEmployeeById(int id){
repository.deleteById(id);
}
public Employee addEmployee(Employee emp) {
return repository.save(emp);
}
public List<Employee> getEmployeeByLastName(String lastName, Integer pageNo) {
// Setting no. of records in each page, page no., sort field
int noOfRecords = 2;
Pageable page = PageRequest.of(pageNo, noOfRecords, Sort.by("firstName"));
return repository.findByLastName(lastName, page);
}
public List<Employee> getEmployeeByDepartment(String department) {
// sort field
Sort sortKey = Sort.by("lastName");
return repository.findByDept(department, sortKey);
}
}
在getAllEmployees和getEmployeeByLastName方法中,创建org.springframework.data.domain.Pageable对象,其中页数,每页记录数和排序键作为参数传递。
在getEmployeeByDepartment方法中,通过传递进行排序的字段来创建org.springframework.data.domain.Sort对象。
分页和排序选项
如果要在分页记录中对记录进行排序,则可以在创建Pageable对象时传递Sort实例。
Pageable page = PageRequest.of(pageNo, noOfRecords, Sort.by(sortKey));
创建Pageable对象时,传递排序字段是可选的,因此我们也可以按如下方式创建一个Pageable实例。
Pageable page = PageRequest.of(pageNo, noOfRecords);
如果希望仅按排序顺序显示记录而没有任何分页,则仅传递"排序"对象。
Sort sortKey = Sort.by("lastName");
如果要对多个字段进行排序,则可以使用和方法组合排序字段。例如,如果我们要同时对lastName和firstName字段进行排序。
Sort sortKey = Sort.by("lastName").and(Sort.by("firstName"));
要指定升序(默认顺序)或者降序进行排序,可以使用ascending()和Descending()方法。
Sort sortKey = Sort.by("lastName").ascending().and(Sort.by("firstName"));
页面与切片
如果我们在Service类repository.findAll(page)的getAllEmployees()方法中注意到,则调用返回一个Page实例。通过分页访问返回数据的其他选项是"切片"和"列表"。
org.springframework.data.domain.Page <T> –这是一个表示对象列表的子列表的接口。它具有获取有关所包含的整个列表的信息的方法,如getTotalElements()和getTotalPages()
org.springframework.data.domain.Slice <T> –指示是否存在下一个或者上一个切片的数据切片。
部署Spring Data JPA应用程序
右键单击项目,然后选择"运行方式– Maven构建",提供目标为全新安装。如果构建成功,则将应用程序打包为战争,可以将其部署在像Tomcat这样的Web容器上,然后测试该应用程序。
为了测试RESTful Web服务,使用了Postman rest客户端。

