Spring Data JPA分页和排序示例

时间:2020-01-09 10:44:33  来源:igfitidea点击:

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