fix(user): /admin/user status \xe7\x99\xbd\xe5\x90\x8d\xe5\x8d\x95 \xe5\x85\x9c\xe5\xba\x95 (#1829 → PR #1834)
这个提交包含在:
父节点
87b07e839e
当前提交
f839745b84
@ -0,0 +1,72 @@
|
||||
# fix(user): /admin/user 列表非字典 status (status=1) 致 total > 0 records=0
|
||||
|
||||
**PR**: [#1834](https://git.1814.love:8443/wx/HL/pulls/1834)(主修复)+ #1831 + #1832(回滚于 #1833) **Issue**: [#1829](https://git.1814.love:8443/wx/HL/issues/1829) **合并**: 2026-05-07
|
||||
|
||||
通知对象: 无前端配合(后端 controller 防御兜底,前端可继续传任意值后端兜底)
|
||||
|
||||
---
|
||||
|
||||
## 现象
|
||||
|
||||
正式 admin: `https://admin.1814.love/admin/user?page=1&pageSize=100&status=1` 显示「有数量没有数据」。
|
||||
|
||||
测试服真 admin token round-trip 完美复现:
|
||||
|
||||
| 请求 | total | records | 备注 |
|
||||
|---|---|---|---|
|
||||
| `status=1` | **28** | **0** | ❌ BUG |
|
||||
| 其他无效值(0/2/ABCXYZ/true) | 0 | 0 | ✅ 一致 |
|
||||
| `status=ACTIVE` | 28 | 28 | ✅ |
|
||||
|
||||
仅 `status=1` 这个特定值出 BUG。
|
||||
|
||||
## 根因(深度排查 3 轮才定位)
|
||||
|
||||
MP `PaginationInnerInterceptor` 用 jsqlparser 把 records SELECT SQL parse 改成 count SQL。`status='1'` 这个字面值 + `.select(projection)` + `.ne(status, X)` + `.eq(status, '1')` 组合触发 jsqlparser 解析失败,**fallback 到 `SELECT COUNT(*) FROM admin_user`**(丢全部 WHERE)→ count=28(全表)records=0。
|
||||
|
||||
3 轮修复教训:
|
||||
- **r1 PR #1831**: wrapper 从 `LambdaQueryWrapper` 迁 `LambdaQueryWrapperX` + Mapper default 方法。合 CODE_RULES 1.2,顺手修了 `status=""` 空串过滤。**但 status=1 BUG 仍在**。
|
||||
- **r2 PR #1832**: 试图 `selectCount(w) + setSearchCount(false) + selectPage(page,w)` 绕过 PaginationInnerInterceptor 自动 count。**炸 SQL 全 500 BadSqlGrammarException**(wrapper state mutation 引发)→ PR #1833 revert 紧急回滚。
|
||||
- **r3 PR #1834 (最终)**: 在 controller 层加 status 字典白名单 (`ACTIVE/LOCKED/DISABLED`),非字典值直接返 `PageResult.empty()` 不进 mapper。**从源头杜绝 MP BUG 路径**。
|
||||
|
||||
## 后端修了什么
|
||||
|
||||
`AdminUserController.listAdmins`(`hl-user-service/.../controller/AdminUserController.java`)在 role 鉴权之后、调 service 之前加:
|
||||
|
||||
```java
|
||||
private static final Set<String> VALID_ADMIN_STATUS = Set.of(
|
||||
UserConstants.STATUS_ACTIVE,
|
||||
UserConstants.ADMIN_STATUS_LOCKED,
|
||||
UserConstants.STATUS_DISABLED);
|
||||
|
||||
if (status != null && !status.isEmpty() && !VALID_ADMIN_STATUS.contains(status)) {
|
||||
return Result.success(PageResult.of(Collections.emptyList(), 0L, page, pageSize));
|
||||
}
|
||||
```
|
||||
|
||||
mapper / service 0 改动。守护单测 `listAdmins_invalidStatus_returnsEmptyPage` 验证 status="1" 时 mapper 不被调用 + 响应空。
|
||||
|
||||
## 前端无需改动
|
||||
|
||||
前端可继续传任意值,后端兜底返空。但**建议前端只传字典值**(ACTIVE/LOCKED/DISABLED)避免无意义请求。
|
||||
|
||||
## 部署依赖
|
||||
|
||||
无 nacos / SQL / 第三方配置变更。直接部署即生效。
|
||||
|
||||
## 受影响范围
|
||||
|
||||
- `/admin/user` 列表所有 status 过滤路径(修复)
|
||||
- 其他 GET 列表接口同样 PaginationInnerInterceptor 行为可能存在类似潜在 BUG,但本 PR 不范围内修复
|
||||
- 已识别遗留(本次未处理): MP `PaginationInnerInterceptor` jsqlparser fallback BUG 根因仍在,需要升级 MP 版本或换 SQL 方案,留后续 PR
|
||||
|
||||
## 测试服 round-trip 验证 (PR #1834 部署后)
|
||||
|
||||
```
|
||||
status=1 → total=0 records.length=0 ✅
|
||||
status=0/2/ABCXYZ/true → 0/0 ✅
|
||||
status=ACTIVE → 28/28 ✅
|
||||
status=DISABLED → 0/0 ✅
|
||||
不传 status → 28/28 ✅
|
||||
status=ACTIVE&roleId=1 → 7/7 ✅
|
||||
```
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户