优化代码规范

This commit is contained in:
2026-05-20 15:19:14 +08:00
parent 0de0d3a134
commit 3ad5a74b74
7 changed files with 448 additions and 45 deletions

286
rules/rules.md Normal file
View File

@@ -0,0 +1,286 @@
---
trigger: always_on
---
## XTools App Java后端规范
### 0. 概述
生成的代码仅需要关注api、biz、client三个模块。
### 1. 整体架构规范
- **JDK**: 25
- **技术栈**Spring Boot 4.x + Spring Cloud 2025.x + MyBatis Plus + Nacos + Spring Cloud LoadBalancer + MapStruct
- **父POM**`org.xujun:xtools-parent-cloud:5.0.0`
- **模块结构**多模块Maven项目支持微服务和单体部署
- **包结构**:统一以`xtools.app`开头,按模块分层组织
#### 1.1 项目模块划分
```
xtools-app/
├── xtools-app-common/ # 公共模块
│ ├── xtools-app-common-cache/ # 缓存(Redis)
│ ├── xtools-app-common-call/ # 远程调用
│ ├── xtools-app-common-config/ # 配置模块
│ ├── xtools-app-common-jar/ # JAR管理
│ ├── xtools-app-common-job/ # 定时任务(XXL-JOB)
│ ├── xtools-app-common-log/ # 日志模块
│ │ ├── xtools-app-common-log-bus/ # 日志总线
│ │ └── xtools-app-common-log-filter/ # 日志过滤器
│ ├── xtools-app-common-mq/ # 消息队列(RabbitMQ)
│ ├── xtools-app-common-sentinel/ # 限流(Sentinel)
│ └── xtools-app-common-task/ # 异步任务
├── xtools-app-monitor/ # 监控模块
│ ├── xtools-app-monitor-boot/ # 监控服务端
│ ├── xtools-app-monitor-client/ # 监控客户端
│ └── xtools-app-monitor-health/ # 健康检查
├── xtools-app-standalone/ # 单体部署启动模块
├── xtools-app-sys/ # 系统管理模块
│ ├── xtools-app-sys-api/ # API接口定义
│ ├── xtools-app-sys-auth/ # 认证授权(SM2/SM3加密)
│ ├── xtools-app-sys-biz/ # 业务逻辑实现
│ ├── xtools-app-sys-boot/ # 微服务启动
│ ├── xtools-app-sys-call/ # 远程调用
│ ├── xtools-app-sys-file/ # 文件管理
│ ├── xtools-app-sys-file-web/ # 文件Web服务
│ ├── xtools-app-sys-log-bus-elasticsearch/ # 日志ES存储
│ ├── xtools-app-sys-param/ # 系统参数
│ ├── xtools-app-sys-risk/ # 风控管理
│ └── xtools-app-sys-scheduled/ # 定时任务
├── xtools-app-gen/ # 代码生成模块
│ ├── xtools-app-gen-biz/ # 代码生成业务
│ └── xtools-app-gen-boot/ # 代码生成启动
└── pom.xml # 父POM
```
#### 1.2 biz模块内部结构
```
xtools-app-{module}-biz/
├── src/main/java/xtools/app/{module}/
│ ├── api/ # API接口实现
│ ├── auth/ # 认证授权
│ ├── config/ # 配置类
│ ├── consts/ # 常量定义
│ ├── controller/ # 控制器层
│ ├── convert/ # 对象转换器(MapStruct)
│ ├── es/ # Elasticsearch相关
│ ├── job/ # 定时任务
│ ├── mapper/ # MyBatis Mapper接口
│ ├── model/ # 模型对象
│ │ ├── entity/ # 实体类
│ │ └── dto/ # 数据传输对象
│ │ ├── req/ # 请求对象(AddReq, UpdateReq, PageReq)
│ │ ├── resp/ # 响应对象(Resp)
│ │ └── excel/ # Excel对象
│ ├── mq/ # 消息队列处理
│ ├── service/ # 服务接口及实现
│ │ ├── base/ # BaseService(继承ServiceImpl)
│ │ └── impl/ # ServiceImpl
│ └── utils/ # 工具类
├── src/main/resources/
│ └── mapper/ # MyBatis XML映射文件
└── ...
```
### 2. 命名规范体系
#### 2.1 包命名规范
- 所有包名统一以`xtools.app`开头
- 模块包名格式:`xtools.app.{module}`
- 分层包名格式:`xtools.app.{module}.{layer}`
- 模型子包格式:`xtools.app.{module}.model.{sub}`
#### 2.2 类命名规范
- 实体类:使用业务名词,如`SysUser`
- DTO类`Dto`结尾,如`SysBlacklistDto`
- 添加请求类:以`AddReq`结尾,如`SysUserAddReq`
- 更新请求类:以`UpdateReq`结尾,如`SysUserUpdateReq`
- 分页请求类:以`PageReq`结尾,如`SysUserPageReq`
- 响应类:以`Resp`结尾,如`SysUserResp`
- Excel导入导出类`Excel`结尾
- BaseService接口`BaseService`结尾,如`SysUserBaseService`
- Service接口`Service`结尾,如`SysUserService`
- Service实现类`ServiceImpl`结尾,如`SysUserServiceImpl`
- Controller类`Controller`结尾,如`SysUserController`
- Mapper接口`Mapper`结尾,如`SysUserMapper`
- 转换器接口:以`Convert`结尾,如`SysUserConvert`
#### 2.3 方法命名规范
- 分页查询:`page(PageReq<XxxPageReq> pageReq)`
- 单条查询:`getById(Long id)`
- 添加:`add(XxxAddReq req)`
- 更新:`update(XxxUpdateReq req)`
- 删除:`delById(List<Long> idList)`
- 批量查询:`getListByIds(IdListReq req)`
- 转换方法:`addReqToEntity()``updateReqToEntity()``entityToResp()``entityToRespList()`
### 3. 编码实现规范
#### 3.1 注解使用规范
- 控制器类使用`@RestController`注解
- 服务实现类使用`@Service``@Primary`注解
- BaseService类使用`@Component`注解
- Mapper接口使用`@Mapper`注解
- 转换器接口使用`@Mapper(componentModel = "spring")`注解MapStruct
- 控制器类添加`@Tag(name = "...")`注解OpenAPI 3.0文档)
- 控制器方法添加`@Operation(summary = "...")`注解
- DTO字段添加`@Schema(description = "...", example = "...")`注解
- 依赖注入统一使用`@RequiredArgsConstructor`构造器注入,不使用字段注入
- 写操作方法添加`@Transactional(rollbackFor = Exception.class)`注解
#### 3.2 继承关系规范
- BaseService类继承`ServiceImpl<Mapper, Entity>`MyBatis Plus使用`@Component`注解
- ServiceImpl类实现Service接口注入BaseService和Convert进行业务操作
- Controller类通过构造器注入Service接口
- API接口定义为Java interface方法返回`Result<T>`
- 实体类继承`BaseEntity`(来自`xtools.boot.api.model.entity.BaseEntity`
- 响应类继承`BaseEntity`(来自`xtools.boot.api.model.entity.BaseEntity`
#### 3.3 返回值规范
- 所有对外接口统一返回`Result<T>`封装对象
- 分页查询返回`Result<PageResp<T>>`封装对象
- 分页请求参数使用`PageReq<XxxPageReq>`封装
- 删除请求使用`IdListReq`封装ID集合
- 成功时使用`Result.ok(data)`方法封装数据
- 失败时抛出`BizError`(业务错误)或`BizWarning`(业务警告)
- 请求参数错误返回`Result.badRequest()`
#### 3.4 DTO使用规范
- API请求参数使用DTO对象封装实现`Serializable`接口
- 添加请求对象:`XxxAddReq`包含业务字段不包含ID
- 更新请求对象:`XxxUpdateReq`包含ID和业务字段
- 分页请求对象:`XxxPageReq`,包含查询条件和时间范围字段`gmtCreateRange`/`gmtModifiedRange``Instant[]`类型)
- 响应对象:`XxxResp`,继承`BaseEntity`,包含关联信息
- 敏感字段使用`@Mask`注解脱敏(如手机号、邮箱、密码)
- 实体类与DTO之间通过MapStruct转换器进行转换
- 不同业务场景使用不同的DTO对象避免复用
### 4. 数据访问规范
#### 4.1 表名规范
- 表名全部小写,单词间用下划线分隔,如`sys_user`
- 表名前缀与模块对应,如`sys_`前缀对应sys模块
#### 4.2 字段名规范
- 字段名全部小写,单词间用下划线分隔,如`dept_id`
- 主键字段统一命名为`id`,类型为`Long`
- 创建时间字段为`gmt_create`由BaseEntity提供
- 更新时间字段为`gmt_modified`由BaseEntity提供
- 创建人字段为`create_by`
- 更新人字段为`update_by`
#### 4.3 实体类规范
- 实体类继承`BaseEntity`基类
- 使用Lombok注解`@Data``@NoArgsConstructor``@AllArgsConstructor``@EqualsAndHashCode(callSuper = true)`
- 使用MyBatis Plus注解标注表名和字段
- `@TableName("表名")`标注表名
- `@TableId(value = "id", type = IdType.ASSIGN_ID)`标注主键
- `@TableField(value = "字段名")`标注字段映射
- 字段添加`@Schema(description = "...")`注解描述
- 主键策略统一使用`IdType.ASSIGN_ID`
#### 4.4 Mapper规范
- Mapper接口继承`BaseMapper<Entity>`MyBatis Plus
- 使用`@Mapper`注解
- 复杂查询使用MyBatis XML映射文件放置在`resources/mapper/`目录下
- XML中使用`LambdaQueryWrapper`或动态SQL`<where>``<if>``<foreach>`
- 使用`QueryUtils.getPage()``QueryUtils.addTimeRange()`工具方法处理分页和时间范围
#### 4.5 BaseService规范
- BaseService类继承`ServiceImpl<Mapper, Entity>`
- 使用`@Component`注解
- 用于封装通用数据访问方法和复杂查询逻辑
- 命名格式:`{业务名}BaseService`,如`SysUserBaseService`
### 5. 接口设计规范
#### 5.1 Controller规范
- 使用`@RestController``@RequestMapping("/模块/资源")`注解
- 使用`@Tag(name = "...")`描述模块功能
- 使用`@Operation(summary = "...")`描述每个接口
- 方法命名遵循RESTful风格`page``getById``add``update``delById`
- 分页接口:`@PostMapping("page")` + `@RequestBody @Valid PageReq<XxxPageReq>`
- 单条查询:`@GetMapping("base/{id}")` + `@PathVariable Long id`
- 添加:`@PostMapping("base")` + `@RequestBody @Valid XxxAddReq`
- 更新:`@PutMapping("base")` + `@RequestBody @Valid XxxUpdateReq`
- 删除:`@DeleteMapping("base")` + `@RequestBody @Valid IdListReq`
- 路径参数验证使用`@NotNull``@Min``@NotEmpty`等注解
- 请求体验证使用`@Valid`注解
#### 5.2 API接口定义
- 所有对外暴露的API接口定义在`api`模块中
- 接口定义为Java interface不包含具体实现
- 接口方法返回值统一使用`Result<T>`封装
- 参数验证注解直接标注在接口方法参数上
#### 5.3 Service规范
- Service接口定义业务方法签名
- ServiceImpl使用`@Service``@Primary`注解
- 通过`@RequiredArgsConstructor`注入依赖BaseService、Convert等
- 写操作添加`@Transactional(rollbackFor = Exception.class)`
- 查询条件使用`LambdaQueryWrapper`构建
- 分页查询使用`PageReq<XxxPageReq>`接收参数,`PageResp<XxxResp>`返回结果
### 6. 配置管理规范
#### 6.1 配置文件
- 使用YAML格式配置文件
- 主配置文件为`application.yml`
- 通过`spring.profiles.active`管理多环境配置(如`boot-base``boot-db``app-sys`等)
#### 6.2 启动类规范
- 单体部署启动类放在`xtools-app-standalone`模块中
- 微服务启动类放在`{module}-boot`模块中
- 启动类格式为`{Module}Application`
- 添加`@SpringBootApplication`注解
### 7. 文档规范
#### 7.1 JavaDoc规范
- 所有public类和方法都必须添加JavaDoc注释
- 类注释格式:
```java
/**
* <p>Title : 类名</p>
* <p>Description : 类描述</p>
* <p>Company : org.xujun</p>
*
* @author : 作者
* @version : 1.0.0
* @date : 日期
*/
```
- 方法注释包含功能说明、`@param`参数说明、`@return`返回值说明
#### 7.2 Swagger/OpenAPI注解规范
- 控制器类添加`@Tag(name = "模块描述")`注解
- 控制器方法添加`@Operation(summary = "接口描述")`注解
- DTO字段添加`@Schema(description = "字段描述", example = "示例值")`注解
- 路径参数添加`@Schema(description = "...", example = "...")`注解
### 8. 智能体工作流程
基于上述规范,代码生成智能体需要遵循以下工作流程:
#### 8.1 新增业务模块
1. **API定义**:在`api`模块中定义服务接口(`XxxApi`),方法返回`Result<T>`
2. **实体创建**:在`biz/model/entity/`中创建继承`BaseEntity`的实体类
3. **Mapper创建**:在`biz/mapper/`中创建继承`BaseMapper<Entity>`的Mapper接口
4. **BaseService创建**:在`biz/service/base/`中创建继承`ServiceImpl<Mapper, Entity>`的BaseService
5. **DTO设计**:创建`XxxAddReq``XxxUpdateReq``XxxPageReq``XxxResp`
6. **Convert实现**:在`biz/convert/`中使用MapStruct实现对象转换
7. **Service实现**:在`biz/service/`中定义接口,在`biz/service/impl/`中实现业务逻辑
8. **Controller实现**:在`biz/controller/`中实现控制器注入Service
#### 8.2 代码生成检查清单
- [ ] 实体类继承`BaseEntity`,使用`IdType.ASSIGN_ID`主键策略
- [ ] Mapper继承`BaseMapper<Entity>`,使用`@Mapper`注解
- [ ] BaseService继承`ServiceImpl<Mapper, Entity>`,使用`@Component`注解
- [ ] Service接口定义返回`Result<T>`的完整CRUD方法
- [ ] ServiceImpl使用`@Service``@Primary``@RequiredArgsConstructor`注解
- [ ] Convert使用`@Mapper(componentModel = "spring")`注解
- [ ] Controller使用`@RestController``@Tag``@Operation`注解
- [ ] 所有DTO字段添加`@Schema`注解
- [ ] 写操作方法添加`@Transactional(rollbackFor = Exception.class)`
- [ ] 请求参数使用`@Valid`验证
- [ ] 分页查询使用`PageReq<XxxPageReq>``PageResp<XxxResp>`
- [ ] 删除操作使用`IdListReq`封装ID集合
- [ ] JavaDoc注释完整

View File

@@ -58,12 +58,24 @@ public class GenTableController {
private final GenTableService genTableService;
/**
* 分页请求
*
* @param pageReq 分页参数
* @return 分页结果
*/
@Operation(summary = "分页请求")
@PostMapping("page")
public Result<PageResp<GenTableResp>> page(@RequestBody @Valid PageReq<GenTablePageReq> pageReq) {
return genTableService.page(pageReq);
}
/**
* 获取数据
*
* @param id ID
* @return 数据
*/
@Operation(summary = "获取数据")
@GetMapping("base/{id}")
public Result<GenTableResp> getById(
@@ -75,24 +87,48 @@ public class GenTableController {
return genTableService.getById(id);
}
/**
* 添加数据
*
* @param req 参数
* @return 结果
*/
@Operation(summary = "添加数据")
@PostMapping("base")
public Result<Boolean> add(@RequestBody @Valid GenTableAddReq req) {
return genTableService.add(req);
}
/**
* 更新数据
*
* @param req 参数
* @return 结果
*/
@Operation(summary = "更新数据")
@PutMapping("base")
public Result<Boolean> update(@RequestBody @Valid GenTableUpdateReq req) {
return genTableService.update(req);
}
/**
* 删除数据
*
* @param req 参数
* @return 结果
*/
@Operation(summary = "删除数据")
@DeleteMapping("base")
public Result<Boolean> delById(@RequestBody @Valid IdListReq req) {
return genTableService.delById(req.getIdList());
}
/**
* 根据数据源 ID 删除表信息
*
* @param id 数据源 ID
* @return 结果
*/
@Operation(summary = "根据数据源 ID 删除表信息")
@DeleteMapping("del-by-datasource-id/{id}")
public Result<Boolean> delByDatasourceId(
@@ -104,6 +140,12 @@ public class GenTableController {
return genService.delTableAndColumnByDatasourceId(id);
}
/**
* 同步数据库
*
* @param id 数据源 ID
* @return 结果
*/
@Operation(summary = "同步数据库")
@GetMapping("sync-db/{id}")
public Result<Boolean> syncDb(
@@ -115,6 +157,12 @@ public class GenTableController {
return genService.syncDb(id);
}
/**
* 同步字段
*
* @param id 表 ID
* @return 结果
*/
@Operation(summary = "同步字段")
@GetMapping("sync-column/{id}")
public Result<Boolean> syncColumn(
@@ -126,24 +174,47 @@ public class GenTableController {
return genService.syncColumn(id);
}
/**
* 获取表格信息
*
* @param req 表 ID 列表
* @return 结果
*/
@Operation(summary = "获取表格信息")
@PostMapping("get-table-list")
public Result<List<GenTableInfoResp>> getTableList(@RequestBody @Valid IdListReq req) {
return genService.getTableList(req.getIdList());
}
/**
* 保存表格信息
*
* @param req 参数
* @return 结果
*/
@Operation(summary = "保存表格信息")
@PostMapping("save-table-list")
public Result<Boolean> saveTableList(@RequestBody @Valid List<GenTableInfoReq> req) {
return genService.saveTableList(req);
}
/**
* 预览代码
*
* @param req 表 ID 列表
* @return 结果
*/
@Operation(summary = "预览代码")
@PostMapping("preview-code")
public Result<List<GenCodeDto>> previewCode(@RequestBody @Valid IdListReq req) {
return genService.previewCode(req.getIdList());
}
/**
* 下载代码
*
* @param req 表 ID 列表
*/
@Operation(summary = "下载代码")
@PostMapping("download-code")
public void downloadCode(HttpServletResponse response, @RequestBody @Valid IdListReq req) {

View File

@@ -1,5 +1,7 @@
package xtools.app.monitor.health.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xtools.boot.api.model.dto.Result;
@@ -15,6 +17,7 @@ import xtools.boot.api.model.dto.Result;
* @version : 1.0.0
* @date : 2026/5/12 16:23
*/
@Tag(name = "健康检查")
@RestController
public class HealthController {
@@ -23,6 +26,7 @@ public class HealthController {
*
* @return ok
*/
@Operation(summary = "健康检查")
@RequestMapping("/health")
public Result<Object> health() {
return Result.ok();

View File

@@ -1,45 +0,0 @@
//package xtools.app.sys.auth.holder;
//
//import xtools.app.sys.auth.model.dto.LoginUserDto;
//import xtools.boot.api.exection.UnauthorizedError;
//
/// **
// * <p>Title : LoginUserHolder</p>
// * <p>Description : LoginUserHolder</p>
// * <p>DevelopTools : Idea_x64_v2026.1</p>
// * <p>DevelopSystem : macOS Sequoia 15.7.5</p>
// * <p>Company : org.xujun</p>
// *
// * @author : XuJun
// * @version : 1.0.0
// * @date : 2026/1/31 21:20
// */
//public class AuthHolder {
//
// /**
// * 登录用户信息
// */
// private static final ScopedValue<LoginUserDto> LOGIN_USER_INFO = ScopedValue.newInstance();
//
// /**
// * 获取登录用户信息 Holder
// *
// * @return 登录用户信息
// */
// public static ScopedValue<LoginUserDto> getScoped() {
// return LOGIN_USER_INFO;
// }
//
// /**
// * 获取登录用户信息
// *
// * @return 登录用户信息
// */
// public static LoginUserDto get() {
// if (!LOGIN_USER_INFO.isBound()) {
// throw new UnauthorizedError();
// }
// return LOGIN_USER_INFO.get();
// }
//
//}

View File

@@ -64,12 +64,24 @@ public class SysBaseController {
return sysBaseService.getUserInfo();
}
/**
* 修改用户信息
*
* @param req 修改用户信息参数
* @return 修改结果
*/
@Operation(summary = "修改用户信息")
@PostMapping("/edit-user-info")
public Result<Boolean> saveUserInfo(@RequestBody @Valid UserInfoEditReq req) {
return sysBaseService.editUserInfo(req);
}
/**
* 修改密码
*
* @param req 修改密码参数
* @return 修改结果
*/
@Operation(summary = "修改密码")
@PostMapping("/edit-passwd")
public Result<Boolean> editPasswd(HttpServletRequest request, @RequestBody @Valid UserInfoPasswdEditReq req) {
@@ -81,12 +93,24 @@ public class SysBaseController {
return sysBaseService.editPasswd(req);
}
/**
* 是否忽略脱敏
*
* @return 是否忽略脱敏
*/
@Operation(summary = "是否忽略脱敏")
@GetMapping("/is-ignore-mask")
public Result<Boolean> isIgnoreMask() {
return Result.ok(AuthUtils.isIgnoreMask());
}
/**
* 忽略脱敏
*
* @param request 请求
* @param req 忽略脱敏参数
* @return 忽略结果
*/
@Operation(summary = "忽略脱敏")
@PostMapping("/ignore-mask")
public Result<Boolean> ignoreMask(HttpServletRequest request, @RequestBody @Valid IgnoreMaskReq req) {
@@ -98,12 +122,22 @@ public class SysBaseController {
return sysBaseService.ignoreMask(req);
}
/**
* 取消忽略脱敏
*
* @return 取消结果
*/
@Operation(summary = "取消忽略脱敏")
@GetMapping("/unignore-mask")
public Result<Boolean> unIgnoreMask() {
return sysBaseService.unIgnoreMask();
}
/**
* 退出登录
*
* @return 退出结果
*/
@Operation(summary = "退出登录")
@GetMapping("/logout")
public Result<Boolean> logout() {
@@ -112,12 +146,23 @@ public class SysBaseController {
return Result.ok(true);
}
/**
* 获取更新历史
*
* @return 更新历史
*/
@Operation(summary = "获取更新历史")
@GetMapping("/get-update-history")
public Result<List<SysUpdateHistoryResp>> getUpdateHistory() {
return sysUpdateHistoryService.getAll(0);
}
/**
* 查询ip对应的地址
*
* @param ip ip
* @return 地址
*/
@Operation(summary = "查询ip对应的地址")
@GetMapping("/get-ip-address/{ip}")
public Result<SysIpAddrResp> getIpAddress(

View File

@@ -54,6 +54,12 @@ public class SysDictController {
private final SysDictService sysDictService;
/**
* 分页请求
*
* @param pageReq 请求参数
* @return 分页结果
*/
@Operation(summary = "分页请求")
@PostMapping("page")
public Result<PageResp<SysDictResp>> page(@RequestBody @Valid PageReq<SysDictPageReq> pageReq) {

View File

@@ -44,12 +44,24 @@ public class SysUserController {
private final SysUserService sysUserService;
/**
* 分页请求
*
* @param pageReq 分页请求参数
* @return 分页响应
*/
@Operation(summary = "分页请求")
@PostMapping("page")
public Result<PageResp<SysUserResp>> page(@RequestBody @Valid PageReq<SysUserPageReq> pageReq) {
return sysUserService.page(pageReq);
}
/**
* 获取数据
*
* @param id ID
* @return 数据
*/
@Operation(summary = "获取数据")
@GetMapping("base/{id}")
public Result<SysUserResp> getById(
@@ -61,24 +73,48 @@ public class SysUserController {
return sysUserService.getById(id);
}
/**
* 添加数据
*
* @param req 添加数据参数
* @return 添加结果
*/
@Operation(summary = "添加数据")
@PostMapping("base")
public Result<Boolean> add(@RequestBody @Valid SysUserAddReq req) {
return sysUserService.add(req);
}
/**
* 更新数据
*
* @param req 更新数据参数
* @return 更新结果
*/
@Operation(summary = "更新数据")
@PutMapping("base")
public Result<Boolean> update(@RequestBody @Valid SysUserUpdateReq req) {
return sysUserService.update(req);
}
/**
* 删除数据
*
* @param req 删除数据参数
* @return 删除结果
*/
@Operation(summary = "删除数据")
@DeleteMapping("base")
public Result<Boolean> delById(@RequestBody @Valid IdListReq req) {
return sysUserService.delById(req.getIdList());
}
/**
* 根据 ID 集合查询
*
* @param req 查询参数
* @return 查询结果
*/
@Operation(summary = "根据 ID 集合查询")
@PostMapping("get-list-by-ids")
public Result<List<SysUserResp>> getListByIds(@RequestBody @Valid IdListReq req) {