• Spring Data JPA - Web 支持、排序和分页


    在前面的教程中,我们已经看到了如何使用 Spring Data 分页 Web 支持。在本教程中,我们将了解如何使用排序支持。

    在基于 Web 的应用程序中应用排序主要有两种方法:

    按可分页处理程序参数排序

    我们在前面的示例中使用过,但没有任何排序查询参数。除了分页信息外,还可以设置排序信息(查看这个和这个)。在这种情况下,我们必须使用类似于以下内容的查询字符串:PageablePageable

    ?page=1&size=10&sort=personName,desc
    

    相当于:

      PageRequest.of(1,10, Sort.by("personName").descending())
    

    按排序处理程序参数排序

    我们也可以用作控制器方法参数(查看我们的排序基本示例)。在这种情况下,我们需要创建类似于以下内容的查询字符串:Sort

    ?sort=personName,desc
    

    相当于:

      Sort.by("personName").descending()
    

    @SortDefault注释

    此批注定义将 Sort 实例注入控制器处理程序方法时要使用的默认排序选项。

    SortHandlerMethodArgumentResolver

    在上述两种情况下,用于从请求参数或 SortDefault 注释自动创建排序实例。当我们在配置类中使用时,此解析器处于活动状态。SortHandlerMethodArgumentResolver@EnableSpringDataWebSupport

    实体

    1. @Entity
    2. public class Employee {
    3. private @Id
    4. @GeneratedValue
    5. Long id;
    6. private String name;
    7. private String dept;
    8. private int salary;
    9. .............
    10. }

    存储 库

    1. public interface EmployeeRepository extends PagingAndSortingRepository {
    2. @Query("SELECT DISTINCT e.dept FROM Employee e")
    3. List findAllDepartments(Sort sort);
    4. }

    我们在上面的存储库 withparameter 中创建了一个自定义查询方法,以便我们可以在控制器中使用 Sort 参数,该参数只会为视图生成部门列表。Sort

    MVC 控制器

    在下面的控制器中,我们将使用两种处理程序方法,一种是使用可分页参数,另一种是使用 Sort 参数:

    1. @Controller
    2. public class EmployeeController {
    3. @Autowired
    4. private EmployeeRepository repository;
    5. @GetMapping("/employees")
    6. public String getEmployees(@PageableDefault(size = 10, sort = "id") Pageable pageable,
    7. Model model) {
    8. Page page = repository.findAll(pageable);
    9. List sortOrders = page.getSort().stream().collect(Collectors.toList());
    10. if (sortOrders.size() > 0) {
    11. Sort.Order order = sortOrders.get(0);
    12. model.addAttribute("sortProperty", order.getProperty());
    13. model.addAttribute("sortDesc", order.getDirection() == Sort.Direction.DESC);
    14. }
    15. model.addAttribute("page", page);
    16. return "employee-page";
    17. }
    18. @GetMapping("departments")
    19. public String getDepartments(@SortDefault(sort="dept",direction = Sort.Direction.ASC)
    20. Sort sort, Model model) {
    21. List depts = repository.findAllDepartments(sort);
    22. model.addAttribute("depts", depts);
    23. return "dept-page";
    24. }
    25. }

    Thymeleaf 视图

    跟随视图同时实现排序和分页。我们正在通过单击表标题进行单列排序。这类似于Java Swing JTable排序功能(在此处查看示例)。

    我们使用 JQuery 来处理表头单击和显示箭头;▾ 和 ▴ 分别在正确的位置进行降序和升序排序。

    src/main/webapp/WEB-INF/views/employee-page.html

    1. xmlns:th="http://www.thymeleaf.org">
    2. Employees

    3. IdNameDepartmentSalary
    4. [[${i}+1]]
  • 以下视图仅显示部门列表。相应的处理程序方法(如上所示)仅使用参数。Sort

    src/main/webapp/WEB-INF/views/dept-page.html

    1. xmlns:th="http://www.thymeleaf.org">
    2. Departments


    运行

    要尝试示例,请运行以下示例项目的嵌入式tomcat(在pom中配置.xml):

    mvn tomcat7:run-war
    

    输出

    localhost:8080/employees

    如上所示,默认情况下选择第一页,并按升序对“id”列进行排序。让我们点击“名称”列标题:

    查看上面地址栏中的查询字符串,其中存在所有必需的查询参数。单击“名称”标题上的更多时间将更改排序方向:

    单击分页按钮可保留上次排序的列。

    让我们通过本地主机访问部门页面localhost:8080/departments

    单击底部的“降序”链接将按降序显示部门:

    1. html>
    2. <html xmlns="http://www.w3.org/1999/xhtml"
    3. xmlns:th="http://www.thymeleaf.org">
    4. <head>
    5. <link rel="icon" th:href="@{/assets/img/favicon.png}" />
    6. <link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" />
    7. <link rel="stylesheet" type="text/css" th:href="@{/webjars/font-awesome/css/all.min.css}"/>
    8. <link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap-icons/font/bootstrap-icons.css}"/>
    9. <link rel="stylesheet" type="text/css" th:href="@{/assets/css/style.css}" />
    10. <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
    11. <script type="text/javascript" th:src="@{/webjars/jquery/jquery.min.js}">script>
    12. <script type="text/javascript" th:src="@{/webjars/bootstrap/js/bootstrap.bundle.min.js}">script>
    13. <script th:inline="javascript">
    14. //thymeleaf to javascript variables
    15. /*
    16. var sortProperty = /*[[${sortProperty}]]*/ null;
    17. var sortDesc = /*[[${sortDesc}]]*/ null;
    18. var currentPage = /*[[${page.number}]]*/ 0;
    19. var pageSize = /*[[${page.size}]]*/ 0;
    20. /*]]>*/
    21. $(document).ready(function () {
    22. //show up/down arrows
    23. $("table#emp-table thead th").each(function () {
    24. var head = $(this);
    25. if (head.attr('data-sort-prop') == sortProperty) {
    26. head.append(sortDesc ? '▾' : '▴');
    27. }
    28. });
    29. //set click action, reload page on clicking with all query params
    30. $("table#emp-table thead th").click(function () {
    31. var headerSortPropName = $(this).attr("data-sort-prop");
    32. if (headerSortPropName == sortProperty) {
    33. window.location.href = window.location.pathname +
    34. '?page=' + currentPage + '&size=' + pageSize + '&sort=' + headerSortPropName + ',' +
    35. (sortDesc ? 'asc' : 'desc');
    36. } else {
    37. window.location.href = window.location.pathname +
    38. '?page=' + currentPage + '&size=' + pageSize + '&sort=' + headerSortPropName + ',asc';
    39. }
    40. });
    41. });
    42. script>
    43. <style>
    44. table{
    45. width:100%;
    46. }
    47. table td, table th {
    48. border: 1px solid grey;
    49. }
    50. table th {
    51. user-select: none;
    52. background: #eee;
    53. }
    54. table tr th:first-child{
    55. width:100px;
    56. }
    57. table tr th:nth-child(3){
    58. width:150px;
    59. }
    60. table tr th:nth-child(4){
    61. width:150px;
    62. }
    63. .pagination-div{
    64. user-select: none;
    65. }
    66. .pagination-div span{
    67. border-radius:3px;
    68. border:1px solid #999;
    69. padding:5px;
    70. margin:10px 0px 0px 10px;
    71. display:inline-block
    72. }
    73. span.selected{
    74. background:#ccf;
    75. }
    76. style>
    77. head>
    78. <body>
    79. <h2>Employeesh2>
    80. <div class="my-3 ">
    81. <div class="row d-flex flex-row">
    82. <form th:action="@{/employees}" id="searchForm" >
    83. <div class="row">
    84. <div class="col-sm-8">
    85. <div class="col-md-12 mt-2">
    86. <div class="search">
    87. <i class="fa fa-search">i>
    88. <input id="keyword" type="search" name="keyword" th:value="${keyword}" required class="form-control"
    89. placeholder="Enter keyword">
    90. <button type="submit" class="btn btn-secondary">搜索button>
    91. div>
    92. div>
    93. div>
    94. <div class="col-sm-3">
    95. <div class="col-md-12 input-group mt-2">
    96. <div class="input-group-prepend">
    97. <label class="input-group-text" for="pageSize">每页显示行数:label>
    98. div>
    99. <select form="searchForm" name="size" th:value="${pageSize}" onchange="changePageSize()" class="size-select"
    100. id="pageSize">
    101. <option th:each="s : ${ {10, 25, 50} }" th:value="${s}" th:text="${s}" th:selected="${s == page.size}">option>
    102. select>
    103. div>
    104. div>
    105. <div class="col-sm-1">
    106. <div class="col-md-12 mt-2">
    107. <button id="btnClear" class="btn btn-info">重置button>
    108. div>
    109. div>
    110. div>
    111. form>
    112. div>
    113. div>
    114. <table id="emp-table">
    115. <thead>
    116. <tr>
    117. <th data-sort-prop="id">Idth>
    118. <th data-sort-prop="name">Nameth>
    119. <th data-sort-prop="dept">Departmentth>
    120. <th data-sort-prop="salary">Salaryth>
    121. tr>
    122. thead>
    123. <tr th:each="employee : ${page.content}">
    124. <td th:text="${employee.id}">td>
    125. <td th:text="${employee.name}">td>
    126. <td th:text="${employee.dept}">td>
    127. <td th:text="${employee.salary}">td>
    128. tr>
    129. table>
    130. <div class="pagination-div" th:with="sortParam=${sortProperty+','+(sortDesc?'desc':'asc')}">
    131. <span th:if="${page.hasPrevious()}">
    132. <a th:href="@{/employees(page=${page.number-1},size=${page.size},sort=${sortParam})}">Previousa>
    133. span>
    134. <th:block th:each="i: ${#numbers.sequence(0, page.totalPages - 1)}">
    135. <span th:if="${page.number == i}" class="selected">[[${i}+1]]span>
    136. <span th:unless="${page.number == i}">
    137. <a th:href="@{/employees(page=${i},size=${page.size},sort=${sortParam})}">[[${i}+1]]a>
    138. span>
    139. th:block>
    140. <span th:if="${page.hasNext()}">
    141. <a th:href="@{/employees(page=${page.number+1},size=${page.size},sort=${sortParam})}">Nexta>
    142. span>
    143. div>
    144. <div class="row">
    145. <div class="col-sm-6">
    146. <div th:if="${page.totalPages > 0}">
    147. 总计<span th:text="${page.totalElements}">99span>行,当前显示<span th:text="(${page.number} )*${page.size} +1">1span> -
    148. <span th:text="(${page.number} )*${page.size} +${page.numberOfElements}">5span>行   总计<span th:text="${page.totalPages}">99span>页
    149. div>
    150. div>
    151. <div class="col-sm-6" th:with="sortParam=${sortProperty+','+(sortDesc?'desc':'asc')}">
    152. <nav aria-label="Pagination" th:if="${page.totalPages > 0}">
    153. <ul class="pagination justify-content-center">
    154. <li class="page-item" th:classappend="${page.number == 0} ? 'disabled'">
    155. <a class="page-link"
    156. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' +'0'+ '&size=' + ${page.size}+'&sort='+${sortParam}}"
    157. title="First Page" rel="First Page">
    158. 最前页
    159. a>
    160. li>
    161. <li class="page-item font-weight-bold" th:classappend="${page.number == 0} ? 'disabled'">
    162. <a class="page-link"
    163. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${page.number - 1} + '&size=' + ${page.size}+'&sort='+${sortParam}}"
    164. title="Previous Page" rel="Previous Page">
    165. 前一页
    166. a>
    167. li>
    168. <li class="page-item disabled" th:if="${page.number - 2 > 0}">
    169. <a class="page-link" href="#">...a>
    170. li>
    171. <li
    172. th:each="i : ${#numbers.sequence(page.number > 2 ? page.number - 2 : 0, page.number + 2 < page.totalPages ? page.number + 2 : page.totalPages-1)}"
    173. class="page-item" th:classappend="${i == page.number} ? 'active'">
    174. <a class="page-link"
    175. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${i} + '&size=' + ${page.size}+'&sort='+${sortParam}}"
    176. th:title=${i+1} th:rel=${i+1}>
    177. [[${i+1} ]]
    178. a>
    179. li>
    180. <li class="page-item disabled" th:if="${page.number + 2 < page.totalPages}">
    181. <a class="page-link" href="#">...a>
    182. li>
    183. <li class="page-item font-weight-bold" th:classappend="${page.number == page.totalPages-1} ? 'disabled'">
    184. <a class="page-link"
    185. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${page.number + 1} + '&size=' + ${page.size}+'&sort='+${sortParam}}"
    186. title="Next Page" rel="Next Page">
    187. 后一页
    188. a>
    189. li>
    190. <li class="page-item" th:classappend="${page.number == page.totalPages-1} ? 'disabled'">
    191. <a class="page-link"
    192. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' +${page.totalPages-1}+ '&size=' + ${page.size}+'&sort='+${sortParam}}"
    193. title="Last Page" rel="Last Page">
    194. 最后页
    195. a>
    196. li>
    197. ul>
    198. nav>
    199. div>
    200. div>
    201. <a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i
    202. class="bi bi-arrow-up-short">i>a>
    203. <script type="text/javascript" th:src="@{/webjars/jquery/jquery.min.js}">script>
    204. <script type="text/javascript" th:src="@{/webjars/bootstrap/js/bootstrap.bundle.min.js}">script>
    205. <script type="text/javascript" th:src="@{/assets/js/main.js}" >script>
    206. <script type="text/javascript">
    207. $(document).ready(function () {
    208. $(".btn-delete").on("click", function (e) {
    209. e.preventDefault();
    210. link = $(this);
    211. tutorialTitle = link.attr("tutorialTitle");
    212. $("#yesBtn").attr("href", link.attr("href"));
    213. $("#confirmText").html("Do you want to delete the Tutorial \" + tutorialTitle + "\<\/strong\>?");
    214. var myModal = new bootstrap.Modal(document.getElementById('confirmModal'), {
    215. keyboard: false
    216. });
    217. myModal.toggle();
    218. });
    219. $("#btnClear").on("click", function (e) {
    220. e.preventDefault();
    221. $("#keyword").text("");
    222. window.location = "[[@{/employees}]]";
    223. });
    224. });
    225. function changePageSize() {
    226. $("#searchForm").submit();
    227. }
    228. script>
    229. body>
    230. html>

    添加搜索/过滤功能

    1. package com.example;
    2. import org.springframework.data.domain.Page;
    3. import org.springframework.data.domain.Pageable;
    4. import org.springframework.data.jpa.repository.JpaRepository;
    5. import org.springframework.data.jpa.repository.Query;
    6. public interface EmployeeRepository extends JpaRepository {
    7. @Query("SELECT e FROM Employee e WHERE CONCAT(e.name, ' ', e.dept) LIKE %?1%")
    8. public Page search(String keyword, Pageable pageable);
    9. }
    1. package com.example;
    2. import java.util.List;
    3. import java.util.stream.Collectors;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.data.domain.Page;
    6. import org.springframework.data.domain.Pageable;
    7. import org.springframework.data.domain.Sort;
    8. import org.springframework.data.repository.query.Param;
    9. import org.springframework.data.web.PageableDefault;
    10. import org.springframework.stereotype.Controller;
    11. import org.springframework.ui.Model;
    12. import org.springframework.web.bind.annotation.GetMapping;
    13. @Controller
    14. public class EmployeeController {
    15. @Autowired
    16. private EmployeeRepository repository;
    17. @GetMapping("/employees")
    18. public String getEmployees(@Param("keyword") String keyword, @PageableDefault(size = 10, sort = "id") Pageable pageable,
    19. Model model) {
    20. if (keyword == null) {
    21. Page page = repository.findAll(pageable);
    22. List sortOrders = page.getSort().stream().collect(Collectors.toList());
    23. if (sortOrders.size() > 0) {
    24. Sort.Order order = sortOrders.get(0);
    25. model.addAttribute("sortProperty", order.getProperty());
    26. model.addAttribute("sortDesc", order.getDirection() == Sort.Direction.DESC);
    27. }
    28. model.addAttribute("page", page);
    29. } else {
    30. Page page = repository.search(keyword, pageable);
    31. List sortOrders = page.getSort().stream().collect(Collectors.toList());
    32. if (sortOrders.size() > 0) {
    33. Sort.Order order = sortOrders.get(0);
    34. model.addAttribute("sortProperty", order.getProperty());
    35. model.addAttribute("sortDesc", order.getDirection() == Sort.Direction.DESC);
    36. }
    37. model.addAttribute("keyword", keyword);
    38. model.addAttribute("page", page);
    39. }
    40. return "employee-page";
    41. }
    42. }
    1. html>
    2. <html xmlns="http://www.w3.org/1999/xhtml"
    3. xmlns:th="http://www.thymeleaf.org">
    4. <head>
    5. <link rel="icon" th:href="@{/assets/img/favicon.png}" />
    6. <link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" />
    7. <link rel="stylesheet" type="text/css" th:href="@{/webjars/font-awesome/css/all.min.css}"/>
    8. <link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap-icons/font/bootstrap-icons.css}"/>
    9. <link rel="stylesheet" type="text/css" th:href="@{/assets/css/style.css}" />
    10. <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
    11. <script type="text/javascript" th:src="@{/webjars/jquery/jquery.min.js}">script>
    12. <script type="text/javascript" th:src="@{/webjars/bootstrap/js/bootstrap.bundle.min.js}">script>
    13. <script th:inline="javascript">
    14. //thymeleaf to javascript variables
    15. /*
    16. var sortProperty = /*[[${sortProperty}]]*/ null;
    17. var sortDesc = /*[[${sortDesc}]]*/ null;
    18. var currentPage = /*[[${page.number}]]*/ 0;
    19. var pageSize = /*[[${page.size}]]*/ 0;
    20. /*]]>*/
    21. $(document).ready(function () {
    22. //show up/down arrows
    23. $("table#emp-table thead th").each(function () {
    24. var head = $(this);
    25. if (head.attr('data-sort-prop') == sortProperty) {
    26. head.append(sortDesc ? '▾' : '▴');
    27. }
    28. });
    29. //set click action, reload page on clicking with all query params
    30. $("table#emp-table thead th").click(function () {
    31. var headerSortPropName = $(this).attr("data-sort-prop");
    32. if (headerSortPropName == sortProperty) {
    33. window.location.href = window.location.pathname +
    34. '?page=' + currentPage + '&size=' + pageSize + '&sort=' + headerSortPropName + ',' +
    35. (sortDesc ? 'asc' : 'desc');
    36. } else {
    37. window.location.href = window.location.pathname +
    38. '?page=' + currentPage + '&size=' + pageSize + '&sort=' + headerSortPropName + ',asc';
    39. }
    40. });
    41. });
    42. script>
    43. <style>
    44. table{
    45. width:100%;
    46. }
    47. table td, table th {
    48. border: 1px solid grey;
    49. }
    50. table th {
    51. user-select: none;
    52. background: #eee;
    53. }
    54. table tr th:first-child{
    55. width:100px;
    56. }
    57. table tr th:nth-child(3){
    58. width:150px;
    59. }
    60. table tr th:nth-child(4){
    61. width:150px;
    62. }
    63. .pagination-div{
    64. user-select: none;
    65. }
    66. .pagination-div span{
    67. border-radius:3px;
    68. border:1px solid #999;
    69. padding:5px;
    70. margin:10px 0px 0px 10px;
    71. display:inline-block
    72. }
    73. span.selected{
    74. background:#ccf;
    75. }
    76. style>
    77. head>
    78. <body>
    79. <h2>Employeesh2>
    80. <div class="my-3 ">
    81. <div class="row d-flex flex-row">
    82. <form th:action="@{/employees}" id="searchForm" >
    83. <div class="row">
    84. <div class="col-sm-8">
    85. <div class="col-md-12 mt-2">
    86. <div class="search">
    87. <i class="fa fa-search">i>
    88. <input id="keyword" type="search" name="keyword" th:value="${keyword}" required class="form-control"
    89. placeholder="Enter keyword">
    90. <button type="submit" class="btn btn-secondary">搜索button>
    91. div>
    92. div>
    93. div>
    94. <div class="col-sm-3">
    95. <div class="col-md-12 input-group mt-2">
    96. <div class="input-group-prepend">
    97. <label class="input-group-text" for="pageSize">每页显示行数:label>
    98. div>
    99. <select form="searchForm" name="size" th:value="${pageSize}" onchange="changePageSize()" class="size-select"
    100. id="pageSize">
    101. <option th:each="s : ${ {10, 25, 50} }" th:value="${s}" th:text="${s}" th:selected="${s == page.size}">option>
    102. select>
    103. div>
    104. div>
    105. <div class="col-sm-1">
    106. <div class="col-md-12 mt-2">
    107. <button id="btnClear" class="btn btn-info">重置button>
    108. div>
    109. div>
    110. div>
    111. form>
    112. div>
    113. div>
    114. <table id="emp-table">
    115. <thead>
    116. <tr>
    117. <th data-sort-prop="id">Idth>
    118. <th data-sort-prop="name">Nameth>
    119. <th data-sort-prop="dept">Departmentth>
    120. <th data-sort-prop="salary">Salaryth>
    121. tr>
    122. thead>
    123. <tr th:each="employee : ${page.content}">
    124. <td th:text="${employee.id}">td>
    125. <td th:text="${employee.name}">td>
    126. <td th:text="${employee.dept}">td>
    127. <td th:text="${employee.salary}">td>
    128. tr>
    129. table>
    130. <div class="row">
    131. <div class="col-sm-6">
    132. <div th:if="${page.totalPages > 0}">
    133. 总计<span th:text="${page.totalElements}">99span>行,当前显示<span th:text="(${page.number} )*${page.size} +1">1span> -
    134. <span th:text="(${page.number} )*${page.size} +${page.numberOfElements}">5span>行   总计<span th:text="${page.totalPages}">99span>页
    135. div>
    136. div>
    137. <div class="col-sm-6" th:with="sortParam=${sortProperty+','+(sortDesc?'desc':'asc')}">
    138. <nav aria-label="Pagination" th:if="${page.totalPages > 0}">
    139. <ul class="pagination justify-content-center">
    140. <li class="page-item" th:classappend="${page.number == 0} ? 'disabled'">
    141. <a class="page-link"
    142. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' +'0'+ '&size=' + ${page.size}+'&sort='+${sortParam}}"
    143. title="First Page" rel="First Page">
    144. 最前页
    145. a>
    146. li>
    147. <li class="page-item font-weight-bold" th:classappend="${page.number == 0} ? 'disabled'">
    148. <a class="page-link"
    149. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${page.number - 1} + '&size=' + ${page.size}+'&sort='+${sortParam}}"
    150. title="Previous Page" rel="Previous Page">
    151. 前一页
    152. a>
    153. li>
    154. <li class="page-item disabled" th:if="${page.number - 2 > 0}">
    155. <a class="page-link" href="#">...a>
    156. li>
    157. <li
    158. th:each="i : ${#numbers.sequence(page.number > 2 ? page.number - 2 : 0, page.number + 2 < page.totalPages ? page.number + 2 : page.totalPages-1)}"
    159. class="page-item" th:classappend="${i == page.number} ? 'active'">
    160. <a class="page-link"
    161. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${i} + '&size=' + ${page.size}+'&sort='+${sortParam}}"
    162. th:title=${i+1} th:rel=${i+1}>
    163. [[${i+1} ]]
    164. a>
    165. li>
    166. <li class="page-item disabled" th:if="${page.number + 2 < page.totalPages}">
    167. <a class="page-link" href="#">...a>
    168. li>
    169. <li class="page-item font-weight-bold" th:classappend="${page.number == page.totalPages-1} ? 'disabled'">
    170. <a class="page-link"
    171. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${page.number + 1} + '&size=' + ${page.size}+'&sort='+${sortParam}}"
    172. title="Next Page" rel="Next Page">
    173. 后一页
    174. a>
    175. li>
    176. <li class="page-item" th:classappend="${page.number == page.totalPages-1} ? 'disabled'">
    177. <a class="page-link"
    178. th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' +${page.totalPages-1}+ '&size=' + ${page.size}+'&sort='+${sortParam}}"
    179. title="Last Page" rel="Last Page">
    180. 最后页
    181. a>
    182. li>
    183. ul>
    184. nav>
    185. div>
    186. div>
    187. <a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i
    188. class="bi bi-arrow-up-short">i>a>
    189. <script type="text/javascript" th:src="@{/webjars/jquery/jquery.min.js}">script>
    190. <script type="text/javascript" th:src="@{/webjars/bootstrap/js/bootstrap.bundle.min.js}">script>
    191. <script type="text/javascript" th:src="@{/assets/js/main.js}" >script>
    192. <script type="text/javascript">
    193. $(document).ready(function () {
    194. $(".btn-delete").on("click", function (e) {
    195. e.preventDefault();
    196. link = $(this);
    197. tutorialTitle = link.attr("tutorialTitle");
    198. $("#yesBtn").attr("href", link.attr("href"));
    199. $("#confirmText").html("Do you want to delete the Tutorial \" + tutorialTitle + "\<\/strong\>?");
    200. var myModal = new bootstrap.Modal(document.getElementById('confirmModal'), {
    201. keyboard: false
    202. });
    203. myModal.toggle();
    204. });
    205. $("#btnClear").on("click", function (e) {
    206. e.preventDefault();
    207. $("#keyword").text("");
    208. window.location = "[[@{/employees}]]";
    209. });
    210. });
    211. function changePageSize() {
    212. $("#searchForm").submit();
    213. }
    214. script>
    215. body>
    216. html>

     

    示例项目

    https://www.logicbig.com/tutorials/spring-framework/spring-data/sorting-and-pagination/spring-data-jpa-sorting-and-pagination.zip

  • 相关阅读:
    Serverless Devs 进入 CNCF 沙箱,成首个入选的 Serverless 工具项目
    2022Vue经典面试题及答案汇总(持续更新)
    基本算法-插入排序
    [附源码]SSM计算机毕业设计基于的高校学生考勤管理系统JAVA
    【分享】“维格表“在集简云平台集成应用的常见问题与解决方案
    3.18 悟透了这三条,能让你的小红书运营能力更上一层楼【玩赚小红书】
    丰田工厂停产竟然因为磁盘...
    GIS工具maptalks开发手册(二)01-02之GeoJSON转化为Geometry——渲染点
    xml创建模型组合体
    3.Node-事件循环用法
  • 原文地址:https://blog.csdn.net/allway2/article/details/128153845