使用 Spring Boot、ThymeLeaf、Spring Data JPA、Hibernate、MySQL 进行分页和排序

在前面的教程中,我们使用Spring Boot和 Thymeleaf 开发了一个 CRUD Web 应用程序。

在本教程中,我们将扩展spring boot CRUD web 应用程序,并使用 spring boot、thymeleaf、spring data JPA、Hibernate 和 MySQL 数据库实现分页和排序操作。

如您所知,分页允许用户一次查看一小部分数据(一页),排序允许用户以更有条理的方式查看数据。分页和排序都可以帮助用户更轻松、更方便地消费信息。

让我们从可以从本教程下载的员工管理系统项目开始,该项目基于 Spring Boot、Spring Data JPA、Hibernate、Thymeleaf 和 MySQL 数据库。

先决条件 

带有 Thymeleaf、Spring MVC、Spring Data JPA、Hibernate、MySQL 的 Spring Boot CRUD Web 应用程序

项目要求

这是实现员工列表页面(员工管理系统) 的分页和排序的高级项目需求。 
用户应该能够:
  • 在员工列表页面上执行分页
  • 在员工列表页面上进行排序

我们将建造什么?

我们将扩展spring boot CRUD web 应用程序,并使用 spring boot、thymeleaf、spring data JPA、Hibernate 和 MySQL 数据库实现分页和排序。

下面的截图总结了我们将在本教程中开发的分页和排序操作。

分页:

 

排序:


首先,我们将逐步实现分页操作,然后我们将完成排序操作。

一、分页实现

了解 Spring Data JPA 的分页 API

要使用 Spring Data JPA 提供的分页和排序 API,您的存储库接口必须扩展 PagingAndSortingRepository 接口,该接口定义了以下几个方法(T 指的是实体类):
@NoRepositoryBean
public interface PagingAndSortingRepository < T, ID > extends CrudRepository < T, ID > {

    /**
     * Returns all entities sorted by the given options.
     *
     * @param sort
     * @return all entities sorted by the given options
     */
    Iterable < T > findAll(Sort sort);

    /**
     * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
     *
     * @param pageable
     * @return a page of entities
     */
    Page < T > findAll(Pageable pageable);
}

JpaRepository 接口扩展 了 PagingAndSortingRepository 接口,因此如果您的存储库接口的类型为 JpaRepository,则无需对其进行更改。
例如,使用以下命令从数据库中获取第一页,每页 5 个项目:
int pageNumber = 1;
int pageSize = 5;
Pageable pageable = PageRequest.of(pageNumber, pageSize);
 
Page page = repository.findAll(pageable);

然后就可以得到实际内容如下:
List listEmployees = page.getContent();

使用 Page 对象,您可以根据给定的页面大小了解数据库中的总行数和总页数:
long totalItems = page.getTotalElements();
int totalPages = page.getTotalPages();

此信息对于使用 Thymeleaf 模板在视图中实现分页很有用。

分页的后端更改

EmployeeService.java 接口更改

在此接口中添加以下方法:
Page findPaginated(int pageNo, int pageSize);

完整代码:
package net.javaguides.springboot.service;

import java.util.List;

import org.springframework.data.domain.Page;

import net.javaguides.springboot.model.Employee;

public interface EmployeeService {
    List < Employee > getAllEmployees();
    void saveEmployee(Employee employee);
    Employee getEmployeeById(long id);
    void deleteEmployeeById(long id);
    Page < Employee > findPaginated(int pageNo, int pageSize);
}

EmployeeServiceImpl.java 类更改

将以下方法添加到 EmployeeServiceImpl 类:
@Override
public Page findPaginated(int pageNo, int pageSize) {
 Pageable pageable = PageRequest.of(pageNo - 1, pageSize);
 return this.employeeRepository.findAll(pageable);
}

EmployeeController.java 类更改

将以下处理程序方法添加到 EmployeeController 类以执行分页:
@GetMapping("/page/{pageNo}")
public String findPaginated(@PathVariable(value = "pageNo") int pageNo, Model model) {
    int pageSize = 5;

    Page < Employee > page = employeeService.findPaginated(pageNo, pageSize);
    List < Employee > listEmployees = page.getContent();

    model.addAttribute("currentPage", pageNo);
    model.addAttribute("totalPages", page.getTotalPages());
    model.addAttribute("totalItems", page.getTotalElements());
    model.addAttribute("listEmployees", listEmployees);
    return "index";
}

此外,我们需要对现有方法进行更改,如下所示:
// display list of employees
@GetMapping("/")
public String viewHomePage(Model model) {
 return findPaginated(1, model);  
}

分页的前端更改

将以下分页代码添加到 index.html:
Total Rows: [[${totalItems}]]
[[${i}]] [[${i}]]    
Next Next
Last Last

完整代码:




    
    Employee Management System

    





    

Employees List

Add Employee
Employee First Name Employee Last Name Employee Email Actions
Update Delete
Total Rows: [[${totalItems}]]
[[${i}]] [[${i}]]    
Next Next
Last Last

2.排序实现

了解 Spring Data JPA 的排序 API

Spring Data JPA 提供了 PagingAndSortingRepository 接口,该接口支持使用以下 API 进行排序和分页:
@NoRepositoryBean
public interface PagingAndSortingRepository < T, ID > extends CrudRepository < T, ID > {

    /**
     * Returns all entities sorted by the given options.
     *
     * @param sort
     * @return all entities sorted by the given options
     */
    Iterable < T > findAll(Sort sort);

    /**
     * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
     *
     * @param pageable
     * @return a page of entities
     */
    Page < T > findAll(Pageable pageable);
}

用户将能够通过单击表格的列标题对员工列表进行排序。 
首先,像这样创建一个 Sort 对象:
Sort sort = Sort.by(“fieldName”).ascending();

这将按 fieldName 升序对结果进行排序。 fieldName 必须与实体类中声明的字段名称匹配。 
我们还可以按多个字段排序,例如:
Sort sort = Sort.by("fieldName1").ascending().and(Sort.by("fieldName2").descending());

然后我们通过 Sort 对象来创建一个 Pageable ,如下所示:
Pageable pageable = PageRequest.of(pageNum - 1, pageSize, sort);

让我们在示例部分了解更多。

用于排序的后端更改

EmployeeService.java 接口更改

让我们在现有方法中添加两个字段:
Page findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);

完整代码:
package net.javaguides.springboot.service;

import java.util.List;

import org.springframework.data.domain.Page;

import net.javaguides.springboot.model.Employee;

public interface EmployeeService {
    List < Employee > getAllEmployees();
    void saveEmployee(Employee employee);
    Employee getEmployeeById(long id);
    void deleteEmployeeById(long id);
    Page < Employee > findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);
}

EmployeeServiceImpl.java 类更改

以下方法中实现的排序逻辑:
@Override
public Page findPaginated(int pageNo, int pageSize, String sortField, String sortDirection) {
    Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortField).ascending() :
     Sort.by(sortField).descending();
 
    Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
    return this.employeeRepository.findAll(pageable);
}

完整代码:
package net.javaguides.springboot.service;

import java.util.List;
import java.util.Optional;

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 net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;

@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Override
    public List < Employee > getAllEmployees() {
        return employeeRepository.findAll();
    }

    @Override
    public void saveEmployee(Employee employee) {
        this.employeeRepository.save(employee);
    }

    @Override
    public Employee getEmployeeById(long id) {
        Optional < Employee > optional = employeeRepository.findById(id);
        Employee employee = null;
        if (optional.isPresent()) {
            employee = optional.get();
        } else {
            throw new RuntimeException(" Employee not found for id :: " + id);
        }
        return employee;
    }

    @Override
    public void deleteEmployeeById(long id) {
        this.employeeRepository.deleteById(id);
    }

    @Override
    public Page < Employee > findPaginated(int pageNo, int pageSize, String sortField, String sortDirection) {
        Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortField).ascending() :
            Sort.by(sortField).descending();

        Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
        return this.employeeRepository.findAll(pageable);
    }
}

EmployeeController.java 更改

让我们更改现有方法以提供对排序的支持:
@GetMapping("/page/{pageNo}")
public String findPaginated(@PathVariable(value = "pageNo") int pageNo,
    @RequestParam("sortField") String sortField,
    @RequestParam("sortDir") String sortDir,
    Model model) {
    int pageSize = 5;

    Page < Employee > page = employeeService.findPaginated(pageNo, pageSize, sortField, sortDir);
    List < Employee > listEmployees = page.getContent();

    model.addAttribute("currentPage", pageNo);
    model.addAttribute("totalPages", page.getTotalPages());
    model.addAttribute("totalItems", page.getTotalElements());

    model.addAttribute("sortField", sortField);
    model.addAttribute("sortDir", sortDir);
    model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");

    model.addAttribute("listEmployees", listEmployees);
    return "index";
}

还为主页提供默认的排序字段和排序方向:
// display list of employees
    @GetMapping("/")
    public String viewHomePage(Model model) {
        return findPaginated(1, "firstName", "asc", model);
    }

完整代码:
package net.javaguides.springboot.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;

@Controller
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    // display list of employees
    @GetMapping("/")
    public String viewHomePage(Model model) {
        return findPaginated(1, "firstName", "asc", model);
    }

    @GetMapping("/showNewEmployeeForm")
    public String showNewEmployeeForm(Model model) {
        // create model attribute to bind form data
        Employee employee = new Employee();
        model.addAttribute("employee", employee);
        return "new_employee";
    }

    @PostMapping("/saveEmployee")
    public String saveEmployee(@ModelAttribute("employee") Employee employee) {
        // save employee to database
        employeeService.saveEmployee(employee);
        return "redirect:/";
    }

    @GetMapping("/showFormForUpdate/{id}")
    public String showFormForUpdate(@PathVariable(value = "id") long id, Model model) {

        // get employee from the service
        Employee employee = employeeService.getEmployeeById(id);

        // set employee as a model attribute to pre-populate the form
        model.addAttribute("employee", employee);
        return "update_employee";
    }

    @GetMapping("/deleteEmployee/{id}")
    public String deleteEmployee(@PathVariable(value = "id") long id) {

        // call delete employee method 
        this.employeeService.deleteEmployeeById(id);
        return "redirect:/";
    }


    @GetMapping("/page/{pageNo}")
    public String findPaginated(@PathVariable(value = "pageNo") int pageNo,
        @RequestParam("sortField") String sortField,
        @RequestParam("sortDir") String sortDir,
        Model model) {
        int pageSize = 5;

        Page < Employee > page = employeeService.findPaginated(pageNo, pageSize, sortField, sortDir);
        List < Employee > listEmployees = page.getContent();

        model.addAttribute("currentPage", pageNo);
        model.addAttribute("totalPages", page.getTotalPages());
        model.addAttribute("totalItems", page.getTotalElements());

        model.addAttribute("sortField", sortField);
        model.addAttribute("sortDir", sortDir);
        model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");

        model.addAttribute("listEmployees", listEmployees);
        return "index";
    }
}

排序的前端更改

索引.html

我们通过使用以下代码添加超链接来使表格的标题列可排序:
我们还需要更改分页部分以提供排序支持,例如:
Total Rows: [[${totalItems}]]
[[${i}]] [[${i}]]    
Next Next
Last Last

完整代码:




Employee Management System


 



 

Employees List

Add Employee
Employee First Name Employee Last Name Employee Email Actions
Update Delete
Total Rows: [[${totalItems}]]
[[${i}]] [[${i}]]    
Next Next
Last Last

GitHub 存储库链接

您可以从我的 GitHub 存储库下载/克隆本教程的源代码, 网址为 https://github.com/RameshMF/springboot-thymeleaf-crud-pagination-sorting-webapp.git

你可能感兴趣的:(mysql,spring,java)