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客户端。