以 [系统管理 -> 租户管理 -> 租户列表] 菜单为例子,讲解它的分页 + 搜索的实现。
1. 前端分页实现
1.1 Vue 界面
界面 tenant/index.vue
(opens new window) 相关的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| <template> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <el-form-item label="租户名" prop="name"> <el-input v-model="queryParams.name" placeholder="请输入租户名" clearable @keyup.enter.native="handleQuery"/> </el-form-item> <el-form-item label="联系人" prop="contactName"> <el-input v-model="queryParams.contactName" placeholder="请输入联系人" clearable @keyup.enter.native="handleQuery"/> </el-form-item> <el-form-item label="联系手机" prop="contactMobile"> <el-input v-model="queryParams.contactMobile" placeholder="请输入联系手机" clearable @keyup.enter.native="handleQuery"/> </el-form-item> <el-form-item label="租户状态" prop="status"> <el-select v-model="queryParams.status" placeholder="请选择租户状态" clearable> <el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :label="dict.label" :value="dict.value"/> </el-select> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button> </el-form-item> </el-form>
<el-table v-loading="loading" :data="list"> </el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" @pagination="getList"/>
</template>
<script> import { getTenantPage } from "@/api/system/tenant";
export default { name: "Tenant", components: {}, data() { return { loading: true, showSearch: true, total: 0, list: [], queryParams: { pageNo: 1, pageSize: 10, name: null, contactName: null, contactMobile: null, status: undefined, }, } }, created() { this.getList(); }, methods: { getList() { this.loading = true; let params = {...this.queryParams}; getTenantPage(params).then(response => { this.list = response.data.list; this.total = response.data.total; this.loading = false; }); }, handleQuery() { this.queryParams.pageNo = 1; this.getList(); }, resetQuery() { this.resetForm("queryForm"); this.handleQuery(); } } } </script>
|
1.2 API 请求
请求
system/tenant.js
(
opens new window) 相关的代码如下:
1 2 3 4 5 6 7 8 9 10
| import request from '@/utils/request'
export function getTenantPage(query) { return request({ url: '/system/tenant/page', method: 'get', params: query }) }
|
2.
后端分页实现
2.1
Controller 接口
在
TenantController (
opens new window) 类中,定义 /admin-api/system/tenant/page
接口。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Tag(name = "管理后台 - 租户") @RestController @RequestMapping("/system/tenant") public class TenantController {
@Resource private TenantService tenantService;
@GetMapping("/page") @Operation(summary = "获得租户分页") @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)); }
}
|
2.1.1 分页参数 PageParam
分页请求,需要继承 PageParam (opens new window) 类。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Schema(description="分页参数") @Data public class PageParam implements Serializable {
private static final Integer PAGE_NO = 1; private static final Integer PAGE_SIZE = 10;
@Schema(description = "页码,从 1 开始", required = true,example = "1") @NotNull(message = "页码不能为空") @Min(value = 1, message = "页码最小值为 1") private Integer pageNo = PAGE_NO;
@Schema(description = "每页条数,最大值为 100", required = true, example = "10") @NotNull(message = "每页条数不能为空") @Min(value = 1, message = "每页条数最小值为 1") @Max(value = 100, message = "每页条数最大值为 100") private Integer pageSize = PAGE_SIZE;
}
|
分页条件,在子类中进行定义。以 TenantPageReqVO 举例子,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Schema(description = "管理后台 - 租户分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) public class TenantPageReqVO extends PageParam {
@Schema(description = "租户名", example = "芋道") private String name;
@Schema(description = "联系人", example = "芋艿") private String contactName;
@Schema(description = "联系手机", example = "15601691300") private String contactMobile;
@Schema(description = "租户状态(0正常 1停用)", example = "1") private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @Schema(description = "创建时间") private LocalDateTime[] createTime;
}
|
分页结果
PageResult (
opens new window) 类,代码如下:
1 2 3 4 5 6 7 8 9 10 11
| @Schema(description = "分页结果") @Data public final class PageResult<T> implements Serializable {
@Schema(description = "数据", required = true) private List<T> list;
@Schema(description = "总量", required = true) private Long total;
}
|
分页结果的数据 list
的每一项,通过自定义 VO 类,例如说 TenantRespVO (opens new window) 类。
2.2 Mapper 查询
在 TenantMapper (opens new window) 类中,定义 selectPage 查询方法。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Mapper public interface TenantMapper extends BaseMapperX<TenantDO> {
default PageResult<TenantDO> selectPage(TenantPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX<TenantDO>() .likeIfPresent(TenantDO::getName, reqVO.getName()) .likeIfPresent(TenantDO::getContactName, reqVO.getContactName()) .likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile()) .eqIfPresent(TenantDO::getStatus, reqVO.getStatus()) .betweenIfPresent(TenantDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) .orderByDesc(TenantDO::getId)); }
}
|
针对 MyBatis Plus 分页查询的二次分装,在 BaseMapperX (opens new window) 中实现,主要是将 MyBatis 的分页结果 IPage,转换成项目的分页结果 PageResult。代码如下图: