image.png分页实现

  • 前端:基于 Element UI 分页组件 Pagination
  • 后端:基于 MyBatis Plus 分页功能,二次封装

以 [系统管理 -> 租户管理 -> 租户列表] 菜单为例子,讲解它的分页 + 搜索的实现。

1. 前端分页实现

1.1 Vue 界面

界面 tenant/index.vue相关的代码如下:

  1. <template>
  2. <!-- 搜索工作栏 -->
  3. <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  4. <el-form-item label="租户名" prop="name">
  5. <el-input v-model="queryParams.name" placeholder="请输入租户名" clearable @keyup.enter.native="handleQuery"/>
  6. </el-form-item>
  7. <el-form-item label="联系人" prop="contactName">
  8. <el-input v-model="queryParams.contactName" placeholder="请输入联系人" clearable @keyup.enter.native="handleQuery"/>
  9. </el-form-item>
  10. <el-form-item label="联系手机" prop="contactMobile">
  11. <el-input v-model="queryParams.contactMobile" placeholder="请输入联系手机" clearable @keyup.enter.native="handleQuery"/>
  12. </el-form-item>
  13. <el-form-item label="租户状态" prop="status">
  14. <el-select v-model="queryParams.status" placeholder="请选择租户状态" clearable>
  15. <el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
  16. :key="dict.value" :label="dict.label" :value="dict.value"/>
  17. </el-select>
  18. </el-form-item>
  19. <el-form-item>
  20. <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  21. <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  22. </el-form-item>
  23. </el-form>
  24. <!-- 列表 -->
  25. <el-table v-loading="loading" :data="list">
  26. <!-- 省略每一列... -->
  27. </el-table>
  28. <!-- 分页组件 -->
  29. <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  30. @pagination="getList"/>
  31. </template>
  32. <script>
  33. import { getTenantPage } from "@/api/system/tenant";
  34. export default {
  35. name: "Tenant",
  36. components: {},
  37. data() {
  38. // 遮罩层
  39. return {
  40. // 遮罩层
  41. loading: true,
  42. // 显示搜索条件
  43. showSearch: true,
  44. // 总条数
  45. total: 0,
  46. // 租户列表
  47. list: [],
  48. // 查询参数
  49. queryParams: {
  50. pageNo: 1,
  51. pageSize: 10,
  52. // 搜索条件
  53. name: null,
  54. contactName: null,
  55. contactMobile: null,
  56. status: undefined,
  57. },
  58. }
  59. },
  60. created() {
  61. this.getList();
  62. },
  63. methods: {
  64. /** 查询列表 */
  65. getList() {
  66. this.loading = true;
  67. // 处理查询参数
  68. let params = {...this.queryParams};
  69. // 执行查询
  70. getTenantPage(params).then(response => {
  71. this.list = response.data.list;
  72. this.total = response.data.total;
  73. this.loading = false;
  74. });
  75. },
  76. /** 搜索按钮操作 */
  77. handleQuery() {
  78. this.queryParams.pageNo = 1;
  79. this.getList();
  80. },
  81. /** 重置按钮操作 */
  82. resetQuery() {
  83. this.resetForm("queryForm");
  84. this.handleQuery();
  85. }
  86. }
  87. }
  88. </script>

1.2 API 请求

请求 system/tenant.js相关的代码如下:

import request from '@/utils/request'

// 获得租户分页
export function getTenantPage(query) {
  return request({
    url: '/system/tenant/page',
    method: 'get',
    params: query
  })
}

2. 后端分页实现

2.1 Controller 接口

在 module/system/controller/admin/tenant/TenantController.java类中,定义 /admin-api/system/tenant/page 接口。代码如下:

@Api(tags = "管理后台 - 租户")
@RestController
@RequestMapping("/system/tenant")
public class TenantController {

    @Resource
    private TenantService tenantService;

    @GetMapping("/page")
    @ApiOperation("获得租户分页")
    @PreAuthorize("@ss.hasPermission('system:tenant:query')")
    public CommonResult<PageResult<TenantRespVO>> getTenantPage(@Valid TenantPageReqVO pageVO) {
        PageResult<TenantDO> pageResult = tenantService.getTenantPage(pageVO);
        return success(TenantConvert.INSTANCE.convertPage(pageResult));
    }

}
  • Request 分页请求,使用 TenantPageReqVO类,它继承 PageParam 类
  • Response 分页结果,使用 PageResult 类,每一项是 TenantRespVO类

    2.1.1 分页参数 PageParam

    分页请求,需要继承 PageParam类。代码如下: ```java @ApiModel(“分页参数”) @Data public class PageParam implements Serializable {

    private static final Integer PAGE_NO = 1; private static final Integer PAGE_SIZE = 10;

    @ApiModelProperty(value = “页码,从 1 开始”, required = true,example = “1”) @NotNull(message = “页码不能为空”) @Min(value = 1, message = “页码最小值为 1”) private Integer pageNo = PAGE_NO;

    @ApiModelProperty(value = “每页条数,最大值为 100”, required = true, example = “10”) @NotNull(message = “每页条数不能为空”) @Min(value = 1, message = “页码最小值为 1”) @Max(value = 100, message = “页码最大值为 100”) private Integer pageSize = PAGE_SIZE;

}

分页条件,在子类中进行定义。以 TenantPageReqVO 举例子,代码如下:
```java
@ApiModel("管理后台 - 租户分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TenantPageReqVO extends PageParam {

    @ApiModelProperty(value = "租户名", example = "芋道")
    private String name;

    @ApiModelProperty(value = "联系人", example = "芋艿")
    private String contactName;

    @ApiModelProperty(value = "联系手机", example = "15601691300")
    private String contactMobile;

    @ApiModelProperty(value = "租户状态(0正常 1停用)", example = "1")
    private Integer status;

    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    @ApiModelProperty(value = "开始创建时间")
    private Date beginCreateTime;

    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    @ApiModelProperty(value = "结束创建时间")
    private Date endCreateTime;

}

2.1.2 分页结果 PageResult

分页结果 PageResult类,代码如下:

@ApiModel("分页结果")
@Data
public final class PageResult<T> implements Serializable {

    @ApiModelProperty(value = "数据", required = true)
    private List<T> list;

    @ApiModelProperty(value = "总量", required = true)
    private Long total;

}

分页结果的数据 list 的每一项,通过自定义 VO 类,例如说 /module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java类。

2.2 Mapper 查询

在 TenantMapper类中,定义 selectPage 查询方法。代码如下:

@Mapper
public interface TenantMapper extends BaseMapperX<TenantDO> {

    default PageResult<TenantDO> selectPage(TenantPageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<TenantDO>()
                .likeIfPresent(TenantDO::getName, reqVO.getName()) // 如果 name 不为空,则进行 like 查询
                .likeIfPresent(TenantDO::getContactName, reqVO.getContactName())
                .likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile())
                .eqIfPresent(TenantDO::getStatus, reqVO.getStatus()) // 如果 status 不为空,则进行 = 查询
                .betweenIfPresent(TenantDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) // 如果 create 不为空,则进行 between 查询
                .orderByDesc(TenantDO::getId)); // 按照 id 倒序
    }

}

针对 MyBatis Plus 分页查询的二次分装,在 BaseMapperX中实现,主要是将 MyBatis 的分页结果 IPage,转换成项目的分页结果 PageResult。代码如下图:
image.png