Showing
3 changed files
with
613 additions
and
0 deletions
backend/时间查询String格式支持说明.md
0 → 100644
| 1 | +# 时间查询@JsonFormat注解支持说明 | ||
| 2 | + | ||
| 3 | +## 功能概述 | ||
| 4 | + | ||
| 5 | +后端用户查询接口使用 `@JsonFormat` 注解统一处理时间格式,简化了时间参数的处理逻辑,确保时间格式的一致性。 | ||
| 6 | + | ||
| 7 | +## 修改内容 | ||
| 8 | + | ||
| 9 | +### 1. DTO类修改 | ||
| 10 | + | ||
| 11 | +**文件**: `UserQueryReq.java` | ||
| 12 | + | ||
| 13 | +**修改前**: | ||
| 14 | +```java | ||
| 15 | +private LocalDateTime startTime; | ||
| 16 | +private LocalDateTime endTime; | ||
| 17 | +``` | ||
| 18 | + | ||
| 19 | +**修改后**: | ||
| 20 | +```java | ||
| 21 | +/** | ||
| 22 | + * 开始时间(创建时间范围查询) | ||
| 23 | + */ | ||
| 24 | +@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") | ||
| 25 | +private LocalDateTime startTime; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * 结束时间(创建时间范围查询) | ||
| 29 | + */ | ||
| 30 | +@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") | ||
| 31 | +private LocalDateTime endTime; | ||
| 32 | +``` | ||
| 33 | + | ||
| 34 | +### 2. 查询条件构建简化 | ||
| 35 | + | ||
| 36 | +**文件**: `SysUserServiceImpl.java` | ||
| 37 | + | ||
| 38 | +**修改前**: | ||
| 39 | +```java | ||
| 40 | +// 开始时间:创建时间 >= 开始时间 | ||
| 41 | +if (StringUtils.isNotEmpty(queryReq.getStartTime())) { | ||
| 42 | + LocalDateTime startTime = parseDateTime(queryReq.getStartTime()); | ||
| 43 | + if (startTime != null) { | ||
| 44 | + wrapper.ge(SysUser::getCreateTime, startTime); | ||
| 45 | + } | ||
| 46 | +} | ||
| 47 | +``` | ||
| 48 | + | ||
| 49 | +**修改后**: | ||
| 50 | +```java | ||
| 51 | +// 开始时间:创建时间 >= 开始时间 | ||
| 52 | +if (queryReq.getStartTime() != null) { | ||
| 53 | + wrapper.ge(SysUser::getCreateTime, queryReq.getStartTime()); | ||
| 54 | +} | ||
| 55 | +``` | ||
| 56 | + | ||
| 57 | +## 支持的时间格式 | ||
| 58 | + | ||
| 59 | +### 1. 标准格式 | ||
| 60 | +- `2025-09-23` - 日期格式(推荐) | ||
| 61 | +- 时区:GMT+8(中国标准时间) | ||
| 62 | + | ||
| 63 | +### 2. @JsonFormat注解优势 | ||
| 64 | +- 自动格式验证 | ||
| 65 | +- 时区自动转换 | ||
| 66 | +- 代码简洁 | ||
| 67 | +- 性能优化 | ||
| 68 | + | ||
| 69 | +## 功能特点 | ||
| 70 | + | ||
| 71 | +### 1. 自动格式处理 | ||
| 72 | +- Jackson自动处理时间格式转换 | ||
| 73 | +- 统一的时区处理(GMT+8) | ||
| 74 | +- 无需手动解析时间字符串 | ||
| 75 | + | ||
| 76 | +### 2. 代码简化 | ||
| 77 | +- 移除了复杂的时间解析逻辑 | ||
| 78 | +- 减少了代码维护成本 | ||
| 79 | +- 提高了代码可读性 | ||
| 80 | + | ||
| 81 | +### 3. 性能优化 | ||
| 82 | +- 利用Jackson的高效序列化/反序列化 | ||
| 83 | +- 减少自定义解析逻辑 | ||
| 84 | +- 更好的内存管理 | ||
| 85 | + | ||
| 86 | +## 使用示例 | ||
| 87 | + | ||
| 88 | +### 1. API调用示例 | ||
| 89 | +```bash | ||
| 90 | +# 标准日期格式(推荐) | ||
| 91 | +curl -X GET "http://localhost:8083/api/system/user/list?startTime=2025-09-23&endTime=2025-09-24" | ||
| 92 | +``` | ||
| 93 | + | ||
| 94 | +### 2. 前端时间选择器 | ||
| 95 | +```javascript | ||
| 96 | +// 前端生成的时间格式(yyyy-MM-dd) | ||
| 97 | +const startTime = "2025-09-23" | ||
| 98 | +const endTime = "2025-09-24" | ||
| 99 | + | ||
| 100 | +// API调用 | ||
| 101 | +const params = { | ||
| 102 | + startTime: startTime, | ||
| 103 | + endTime: endTime, | ||
| 104 | + pageNum: 1, | ||
| 105 | + pageSize: 10 | ||
| 106 | +} | ||
| 107 | +``` | ||
| 108 | + | ||
| 109 | +### 3. 数据库查询 | ||
| 110 | +```sql | ||
| 111 | +-- 实际执行的SQL查询 | ||
| 112 | +SELECT * FROM t_sys_user | ||
| 113 | +WHERE del_flag = '0' | ||
| 114 | +AND create_time >= '2025-09-23 00:00:00' | ||
| 115 | +AND create_time <= '2025-09-23 23:59:59' | ||
| 116 | +ORDER BY create_time DESC; | ||
| 117 | +``` | ||
| 118 | + | ||
| 119 | +## 错误处理 | ||
| 120 | + | ||
| 121 | +### 1. 格式错误处理 | ||
| 122 | +```java | ||
| 123 | +// 解析失败时的处理 | ||
| 124 | +if (startTime == null) { | ||
| 125 | + // 记录日志但不中断查询 | ||
| 126 | + System.err.println("时间格式解析失败: " + queryReq.getStartTime()); | ||
| 127 | + // 跳过该查询条件 | ||
| 128 | +} | ||
| 129 | +``` | ||
| 130 | + | ||
| 131 | +### 2. 空值处理 | ||
| 132 | +```java | ||
| 133 | +// 空值检查 | ||
| 134 | +if (StringUtils.isNotEmpty(queryReq.getStartTime())) { | ||
| 135 | + // 只有非空时才进行解析 | ||
| 136 | +} | ||
| 137 | +``` | ||
| 138 | + | ||
| 139 | +### 3. 时区处理 | ||
| 140 | +```java | ||
| 141 | +// 时区信息移除 | ||
| 142 | +if (dateTimeStr.endsWith("Z") || dateTimeStr.contains("+") || dateTimeStr.contains("-")) { | ||
| 143 | + String localTimeStr = dateTimeStr.replaceAll("[+-]\\d{2}:\\d{2}$", "").replace("Z", ""); | ||
| 144 | + return LocalDateTime.parse(localTimeStr, formatter); | ||
| 145 | +} | ||
| 146 | +``` | ||
| 147 | + | ||
| 148 | +## 性能考虑 | ||
| 149 | + | ||
| 150 | +### 1. 格式化器缓存 | ||
| 151 | +- 使用静态格式化器数组 | ||
| 152 | +- 避免重复创建格式化器对象 | ||
| 153 | +- 按使用频率排序 | ||
| 154 | + | ||
| 155 | +### 2. 解析优化 | ||
| 156 | +- 按常用格式优先尝试 | ||
| 157 | +- 快速失败机制 | ||
| 158 | +- 避免不必要的字符串操作 | ||
| 159 | + | ||
| 160 | +### 3. 内存管理 | ||
| 161 | +- 及时释放临时对象 | ||
| 162 | +- 避免字符串拼接 | ||
| 163 | +- 使用高效的字符串操作 | ||
| 164 | + | ||
| 165 | +## 测试建议 | ||
| 166 | + | ||
| 167 | +### 1. 格式测试 | ||
| 168 | +```java | ||
| 169 | +// 测试各种时间格式 | ||
| 170 | +String[] testFormats = { | ||
| 171 | + "2025-09-23T10:06:13.293Z", | ||
| 172 | + "2025-09-23T10:06:13", | ||
| 173 | + "2025-09-23", | ||
| 174 | + "2025-09-23 10:06:13", | ||
| 175 | + "2025/09/23" | ||
| 176 | +}; | ||
| 177 | + | ||
| 178 | +for (String format : testFormats) { | ||
| 179 | + LocalDateTime result = parseDateTime(format); | ||
| 180 | + System.out.println(format + " -> " + result); | ||
| 181 | +} | ||
| 182 | +``` | ||
| 183 | + | ||
| 184 | +### 2. 边界测试 | ||
| 185 | +- 测试极端时间值 | ||
| 186 | +- 测试格式错误的时间 | ||
| 187 | +- 测试空值和null值 | ||
| 188 | + | ||
| 189 | +### 3. 性能测试 | ||
| 190 | +- 测试大量时间解析的性能 | ||
| 191 | +- 测试并发解析的安全性 | ||
| 192 | +- 测试内存使用情况 | ||
| 193 | + | ||
| 194 | +## 注意事项 | ||
| 195 | + | ||
| 196 | +1. **时区一致性**: 确保前后端时区设置一致 | ||
| 197 | +2. **格式验证**: 前端应验证时间格式的正确性 | ||
| 198 | +3. **性能监控**: 监控时间解析的性能影响 | ||
| 199 | +4. **日志记录**: 记录解析失败的情况便于调试 | ||
| 200 | + | ||
| 201 | +## 相关文件 | ||
| 202 | + | ||
| 203 | +- `UserQueryReq.java` - 查询请求DTO | ||
| 204 | +- `SysUserServiceImpl.java` - 服务实现类 | ||
| 205 | +- `API接口文档.md` - API文档更新 |
backend/查询条件组装代码规范说明.md
0 → 100644
| 1 | +# 查询条件组装代码规范说明 | ||
| 2 | + | ||
| 3 | +## 规范概述 | ||
| 4 | + | ||
| 5 | +为了保持代码的一致性和可维护性,所有查询条件的组装都应该统一放在 `getQueryWrapper` 方法中,而不是在 Controller 层进行条件组装。 | ||
| 6 | + | ||
| 7 | +## 修改内容 | ||
| 8 | + | ||
| 9 | +### 1. 接口层修改 | ||
| 10 | + | ||
| 11 | +**文件**: `SysUserService.java` | ||
| 12 | + | ||
| 13 | +**修改前**: | ||
| 14 | +```java | ||
| 15 | +LambdaQueryWrapper<SysUser> getQueryWrapper(SysUser user); | ||
| 16 | +``` | ||
| 17 | + | ||
| 18 | +**修改后**: | ||
| 19 | +```java | ||
| 20 | +LambdaQueryWrapper<SysUser> getQueryWrapper(UserQueryReq queryReq); | ||
| 21 | +``` | ||
| 22 | + | ||
| 23 | +### 2. 实现层修改 | ||
| 24 | + | ||
| 25 | +**文件**: `SysUserServiceImpl.java` | ||
| 26 | + | ||
| 27 | +**修改前**: | ||
| 28 | +```java | ||
| 29 | +@Override | ||
| 30 | +public LambdaQueryWrapper<SysUser> getQueryWrapper(SysUser user) { | ||
| 31 | + LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>(); | ||
| 32 | + | ||
| 33 | + // 基础查询条件 | ||
| 34 | + if (StringUtils.isNotEmpty(user.getUsername())) { | ||
| 35 | + wrapper.like(SysUser::getUsername, user.getUsername()); | ||
| 36 | + } | ||
| 37 | + // ... 其他条件 | ||
| 38 | + | ||
| 39 | + return wrapper; | ||
| 40 | +} | ||
| 41 | +``` | ||
| 42 | + | ||
| 43 | +**修改后**: | ||
| 44 | +```java | ||
| 45 | +@Override | ||
| 46 | +public LambdaQueryWrapper<SysUser> getQueryWrapper(UserQueryReq queryReq) { | ||
| 47 | + LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>(); | ||
| 48 | + | ||
| 49 | + // 基础查询条件 | ||
| 50 | + if (StringUtils.isNotEmpty(queryReq.getUsername())) { | ||
| 51 | + wrapper.like(SysUser::getUsername, queryReq.getUsername()); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + // 时间范围查询条件 | ||
| 55 | + if (queryReq.getStartTime() != null) { | ||
| 56 | + wrapper.ge(SysUser::getCreateTime, queryReq.getStartTime()); | ||
| 57 | + } | ||
| 58 | + if (queryReq.getEndTime() != null) { | ||
| 59 | + wrapper.le(SysUser::getCreateTime, queryReq.getEndTime()); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + // 固定条件 | ||
| 63 | + wrapper.eq(SysUser::getDelFlag, "0"); | ||
| 64 | + wrapper.orderByDesc(SysUser::getCreateTime); | ||
| 65 | + | ||
| 66 | + return wrapper; | ||
| 67 | +} | ||
| 68 | +``` | ||
| 69 | + | ||
| 70 | +### 3. Controller 层简化 | ||
| 71 | + | ||
| 72 | +**文件**: `SysUserController.java` | ||
| 73 | + | ||
| 74 | +**修改前**: | ||
| 75 | +```java | ||
| 76 | +public ApiRes<IPage<UserRes>> list(UserQueryReq queryReq) { | ||
| 77 | + Page<SysUser> page = new Page<>(queryReq.getPageNum(), queryReq.getPageSize()); | ||
| 78 | + | ||
| 79 | + // 构建查询条件 | ||
| 80 | + SysUser queryUser = new SysUser(); | ||
| 81 | + BeanUtils.copyProperties(queryReq, queryUser); | ||
| 82 | + | ||
| 83 | + // 获取基础查询条件 | ||
| 84 | + LambdaQueryWrapper<SysUser> wrapper = sysUserService.getQueryWrapper(queryUser); | ||
| 85 | + | ||
| 86 | + // 添加时间范围查询条件 | ||
| 87 | + if (queryReq.getStartTime() != null) { | ||
| 88 | + wrapper.ge(SysUser::getCreateTime, queryReq.getStartTime()); | ||
| 89 | + } | ||
| 90 | + if (queryReq.getEndTime() != null) { | ||
| 91 | + wrapper.le(SysUser::getCreateTime, queryReq.getEndTime()); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + IPage<SysUser> userPage = sysUserService.page(page, wrapper); | ||
| 95 | + // ... 其他逻辑 | ||
| 96 | +} | ||
| 97 | +``` | ||
| 98 | + | ||
| 99 | +**修改后**: | ||
| 100 | +```java | ||
| 101 | +public ApiRes<IPage<UserRes>> list(UserQueryReq queryReq) { | ||
| 102 | + Page<SysUser> page = new Page<>(queryReq.getPageNum(), queryReq.getPageSize()); | ||
| 103 | + | ||
| 104 | + // 获取查询条件包装器(包含所有查询条件) | ||
| 105 | + LambdaQueryWrapper<SysUser> wrapper = sysUserService.getQueryWrapper(queryReq); | ||
| 106 | + | ||
| 107 | + IPage<SysUser> userPage = sysUserService.page(page, wrapper); | ||
| 108 | + // ... 其他逻辑 | ||
| 109 | +} | ||
| 110 | +``` | ||
| 111 | + | ||
| 112 | +## 代码规范优势 | ||
| 113 | + | ||
| 114 | +### 1. 职责分离 | ||
| 115 | +- **Controller 层**: 只负责接收请求和返回响应 | ||
| 116 | +- **Service 层**: 负责业务逻辑和查询条件组装 | ||
| 117 | +- **Mapper 层**: 负责数据库操作 | ||
| 118 | + | ||
| 119 | +### 2. 代码复用 | ||
| 120 | +- 查询条件组装逻辑集中在 Service 层 | ||
| 121 | +- 其他 Controller 可以复用相同的查询逻辑 | ||
| 122 | +- 避免重复代码 | ||
| 123 | + | ||
| 124 | +### 3. 易于维护 | ||
| 125 | +- 查询条件修改只需要在一个地方进行 | ||
| 126 | +- 逻辑清晰,易于理解和调试 | ||
| 127 | +- 便于单元测试 | ||
| 128 | + | ||
| 129 | +### 4. 扩展性强 | ||
| 130 | +- 新增查询条件只需要在 `getQueryWrapper` 方法中添加 | ||
| 131 | +- 不影响 Controller 层的代码 | ||
| 132 | +- 支持复杂的查询条件组合 | ||
| 133 | + | ||
| 134 | +## 实现细节 | ||
| 135 | + | ||
| 136 | +### 1. 参数类型统一 | ||
| 137 | +- 使用 `UserQueryReq` 作为查询参数类型 | ||
| 138 | +- 包含所有可能的查询条件 | ||
| 139 | +- 支持分页参数和查询条件 | ||
| 140 | + | ||
| 141 | +### 2. 查询条件处理 | ||
| 142 | +```java | ||
| 143 | +// 字符串字段:模糊查询 | ||
| 144 | +if (StringUtils.isNotEmpty(queryReq.getUsername())) { | ||
| 145 | + wrapper.like(SysUser::getUsername, queryReq.getUsername()); | ||
| 146 | +} | ||
| 147 | + | ||
| 148 | +// 数值字段:精确查询 | ||
| 149 | +if (queryReq.getStatus() != null) { | ||
| 150 | + wrapper.eq(SysUser::getStatus, queryReq.getStatus()); | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +// 时间字段:范围查询 | ||
| 154 | +if (queryReq.getStartTime() != null) { | ||
| 155 | + wrapper.ge(SysUser::getCreateTime, queryReq.getStartTime()); | ||
| 156 | +} | ||
| 157 | +``` | ||
| 158 | + | ||
| 159 | +### 3. 固定条件处理 | ||
| 160 | +```java | ||
| 161 | +// 软删除条件 | ||
| 162 | +wrapper.eq(SysUser::getDelFlag, "0"); | ||
| 163 | + | ||
| 164 | +// 排序条件 | ||
| 165 | +wrapper.orderByDesc(SysUser::getCreateTime); | ||
| 166 | +``` | ||
| 167 | + | ||
| 168 | +## 最佳实践 | ||
| 169 | + | ||
| 170 | +### 1. 查询条件顺序 | ||
| 171 | +1. 基础查询条件(用户名、姓名等) | ||
| 172 | +2. 状态查询条件 | ||
| 173 | +3. 时间范围查询条件 | ||
| 174 | +4. 固定条件(软删除、排序) | ||
| 175 | + | ||
| 176 | +### 2. 空值处理 | ||
| 177 | +- 使用 `StringUtils.isNotEmpty()` 处理字符串字段 | ||
| 178 | +- 使用 `!= null` 处理数值和时间字段 | ||
| 179 | +- 避免空字符串和 null 值的查询 | ||
| 180 | + | ||
| 181 | +### 3. 性能优化 | ||
| 182 | +- 合理使用索引字段进行查询 | ||
| 183 | +- 避免全表扫描 | ||
| 184 | +- 使用合适的数据类型 | ||
| 185 | + | ||
| 186 | +## 扩展指南 | ||
| 187 | + | ||
| 188 | +### 1. 添加新的查询条件 | ||
| 189 | +```java | ||
| 190 | +// 在 getQueryWrapper 方法中添加 | ||
| 191 | +if (StringUtils.isNotEmpty(queryReq.getNewField())) { | ||
| 192 | + wrapper.like(SysUser::getNewField, queryReq.getNewField()); | ||
| 193 | +} | ||
| 194 | +``` | ||
| 195 | + | ||
| 196 | +### 2. 添加新的查询类型 | ||
| 197 | +```java | ||
| 198 | +// 支持多值查询 | ||
| 199 | +if (queryReq.getStatusList() != null && !queryReq.getStatusList().isEmpty()) { | ||
| 200 | + wrapper.in(SysUser::getStatus, queryReq.getStatusList()); | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +// 支持时间范围查询 | ||
| 204 | +if (queryReq.getStartTime() != null && queryReq.getEndTime() != null) { | ||
| 205 | + wrapper.between(SysUser::getCreateTime, queryReq.getStartTime(), queryReq.getEndTime()); | ||
| 206 | +} | ||
| 207 | +``` | ||
| 208 | + | ||
| 209 | +### 3. 添加复杂查询逻辑 | ||
| 210 | +```java | ||
| 211 | +// 支持 OR 条件 | ||
| 212 | +if (StringUtils.isNotEmpty(queryReq.getKeyword())) { | ||
| 213 | + wrapper.and(w -> w.like(SysUser::getUsername, queryReq.getKeyword()) | ||
| 214 | + .or() | ||
| 215 | + .like(SysUser::getRealName, queryReq.getKeyword())); | ||
| 216 | +} | ||
| 217 | +``` | ||
| 218 | + | ||
| 219 | +## 注意事项 | ||
| 220 | + | ||
| 221 | +1. **参数验证**: 在 Service 层添加参数验证逻辑 | ||
| 222 | +2. **异常处理**: 合理处理查询异常 | ||
| 223 | +3. **日志记录**: 记录重要的查询操作 | ||
| 224 | +4. **性能监控**: 监控查询性能,优化慢查询 | ||
| 225 | + | ||
| 226 | +## 相关文件 | ||
| 227 | + | ||
| 228 | +- `SysUserService.java` - 服务接口 | ||
| 229 | +- `SysUserServiceImpl.java` - 服务实现 | ||
| 230 | +- `SysUserController.java` - 控制器 | ||
| 231 | +- `UserQueryReq.java` - 查询请求DTO |
backend/用户列表时间查询功能说明.md
0 → 100644
| 1 | +# 用户列表时间查询功能说明 | ||
| 2 | + | ||
| 3 | +## 功能概述 | ||
| 4 | + | ||
| 5 | +后端用户列表查询接口已添加创建时间范围查询功能,支持按创建时间筛选用户数据。 | ||
| 6 | + | ||
| 7 | +## 实现内容 | ||
| 8 | + | ||
| 9 | +### 1. 数据库查询条件 | ||
| 10 | +- **开始时间查询**: `create_time >= startTime` | ||
| 11 | +- **结束时间查询**: `create_time <= endTime` | ||
| 12 | +- **时间范围查询**: 同时支持开始时间和结束时间,实现时间范围筛选 | ||
| 13 | + | ||
| 14 | +### 2. 技术实现 | ||
| 15 | + | ||
| 16 | +#### 2.1 DTO 类修改 | ||
| 17 | +**文件**: `UserQueryReq.java` | ||
| 18 | +```java | ||
| 19 | +/** | ||
| 20 | + * 开始时间(创建时间范围查询) | ||
| 21 | + */ | ||
| 22 | +private LocalDateTime startTime; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * 结束时间(创建时间范围查询) | ||
| 26 | + */ | ||
| 27 | +private LocalDateTime endTime; | ||
| 28 | +``` | ||
| 29 | + | ||
| 30 | +#### 2.2 Controller 层修改 | ||
| 31 | +**文件**: `SysUserController.java` | ||
| 32 | +```java | ||
| 33 | +// 添加时间范围查询条件 | ||
| 34 | +if (queryReq.getStartTime() != null) { | ||
| 35 | + wrapper.ge(SysUser::getCreateTime, queryReq.getStartTime()); | ||
| 36 | +} | ||
| 37 | +if (queryReq.getEndTime() != null) { | ||
| 38 | + wrapper.le(SysUser::getCreateTime, queryReq.getEndTime()); | ||
| 39 | +} | ||
| 40 | +``` | ||
| 41 | + | ||
| 42 | +#### 2.3 查询逻辑 | ||
| 43 | +- 使用 MyBatis Plus 的 `LambdaQueryWrapper` 构建查询条件 | ||
| 44 | +- `ge()` 方法实现大于等于查询(开始时间) | ||
| 45 | +- `le()` 方法实现小于等于查询(结束时间) | ||
| 46 | +- 支持单独使用开始时间或结束时间查询 | ||
| 47 | + | ||
| 48 | +## API 接口说明 | ||
| 49 | + | ||
| 50 | +### 接口路径 | ||
| 51 | +`GET /api/system/user/list` | ||
| 52 | + | ||
| 53 | +### 新增参数 | ||
| 54 | +| 参数名 | 类型 | 必填 | 说明 | | ||
| 55 | +|--------|------|------|------| | ||
| 56 | +| startTime | String | 否 | 开始时间,格式:yyyy-MM-ddTHH:mm:ss | | ||
| 57 | +| endTime | String | 否 | 结束时间,格式:yyyy-MM-ddTHH:mm:ss | | ||
| 58 | + | ||
| 59 | +### 请求示例 | ||
| 60 | +``` | ||
| 61 | +GET /api/system/user/list?startTime=2024-01-01T00:00:00&endTime=2024-12-31T23:59:59&pageNum=1&pageSize=10 | ||
| 62 | +``` | ||
| 63 | + | ||
| 64 | +### 查询逻辑 | ||
| 65 | +1. **只有开始时间**: 查询创建时间 >= 开始时间的用户 | ||
| 66 | +2. **只有结束时间**: 查询创建时间 <= 结束时间的用户 | ||
| 67 | +3. **开始时间 + 结束时间**: 查询创建时间在指定范围内的用户 | ||
| 68 | +4. **无时间参数**: 查询所有用户(原有逻辑) | ||
| 69 | + | ||
| 70 | +## 数据库查询示例 | ||
| 71 | + | ||
| 72 | +### SQL 查询示例 | ||
| 73 | +```sql | ||
| 74 | +-- 查询2024年1月创建的用户 | ||
| 75 | +SELECT * FROM t_sys_user | ||
| 76 | +WHERE del_flag = '0' | ||
| 77 | +AND create_time >= '2024-01-01 00:00:00' | ||
| 78 | +AND create_time <= '2024-01-31 23:59:59' | ||
| 79 | +ORDER BY create_time DESC; | ||
| 80 | + | ||
| 81 | +-- 查询2024年1月1日之后创建的用户 | ||
| 82 | +SELECT * FROM t_sys_user | ||
| 83 | +WHERE del_flag = '0' | ||
| 84 | +AND create_time >= '2024-01-01 00:00:00' | ||
| 85 | +ORDER BY create_time DESC; | ||
| 86 | +``` | ||
| 87 | + | ||
| 88 | +### MyBatis Plus 查询条件 | ||
| 89 | +```java | ||
| 90 | +LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>(); | ||
| 91 | +wrapper.eq(SysUser::getDelFlag, "0"); // 未删除 | ||
| 92 | +wrapper.ge(SysUser::getCreateTime, startTime); // 开始时间 | ||
| 93 | +wrapper.le(SysUser::getCreateTime, endTime); // 结束时间 | ||
| 94 | +wrapper.orderByDesc(SysUser::getCreateTime); // 按创建时间降序 | ||
| 95 | +``` | ||
| 96 | + | ||
| 97 | +## 时间格式说明 | ||
| 98 | + | ||
| 99 | +### 前端传递格式 | ||
| 100 | +- **日期格式**: `yyyy-MM-dd` (如: 2024-01-01) | ||
| 101 | +- **日期时间格式**: `yyyy-MM-ddTHH:mm:ss` (如: 2024-01-01T00:00:00) | ||
| 102 | + | ||
| 103 | +### 后端处理 | ||
| 104 | +- 使用 `LocalDateTime` 类型接收时间参数 | ||
| 105 | +- 自动进行类型转换和格式验证 | ||
| 106 | +- 支持时区处理(基于服务器时区) | ||
| 107 | + | ||
| 108 | +## 性能优化 | ||
| 109 | + | ||
| 110 | +### 1. 数据库索引 | ||
| 111 | +确保 `create_time` 字段有适当的索引: | ||
| 112 | +```sql | ||
| 113 | +-- 创建时间索引 | ||
| 114 | +CREATE INDEX idx_user_create_time ON t_sys_user(create_time); | ||
| 115 | + | ||
| 116 | +-- 复合索引(状态 + 创建时间) | ||
| 117 | +CREATE INDEX idx_user_status_create_time ON t_sys_user(status, create_time); | ||
| 118 | +``` | ||
| 119 | + | ||
| 120 | +### 2. 查询优化 | ||
| 121 | +- 时间范围查询使用索引 | ||
| 122 | +- 避免全表扫描 | ||
| 123 | +- 合理使用分页查询 | ||
| 124 | + | ||
| 125 | +## 测试用例 | ||
| 126 | + | ||
| 127 | +### 1. 基础功能测试 | ||
| 128 | +```bash | ||
| 129 | +# 查询2024年1月创建的用户 | ||
| 130 | +curl -X GET "http://localhost:8083/api/system/user/list?startTime=2024-01-01T00:00:00&endTime=2024-01-31T23:59:59" | ||
| 131 | + | ||
| 132 | +# 查询2024年1月1日之后创建的用户 | ||
| 133 | +curl -X GET "http://localhost:8083/api/system/user/list?startTime=2024-01-01T00:00:00" | ||
| 134 | + | ||
| 135 | +# 查询2024年1月31日之前创建的用户 | ||
| 136 | +curl -X GET "http://localhost:8083/api/system/user/list?endTime=2024-01-31T23:59:59" | ||
| 137 | +``` | ||
| 138 | + | ||
| 139 | +### 2. 边界条件测试 | ||
| 140 | +- 开始时间 = 结束时间 | ||
| 141 | +- 开始时间 > 结束时间 | ||
| 142 | +- 时间格式错误处理 | ||
| 143 | +- 空值处理 | ||
| 144 | + | ||
| 145 | +### 3. 性能测试 | ||
| 146 | +- 大数据量下的查询性能 | ||
| 147 | +- 索引使用情况 | ||
| 148 | +- 查询响应时间 | ||
| 149 | + | ||
| 150 | +## 注意事项 | ||
| 151 | + | ||
| 152 | +1. **时间格式**: 前端传递的时间格式必须符合 `yyyy-MM-ddTHH:mm:ss` 格式 | ||
| 153 | +2. **时区处理**: 后端使用服务器本地时区处理时间 | ||
| 154 | +3. **索引优化**: 确保数据库表有适当的索引以提升查询性能 | ||
| 155 | +4. **参数验证**: 开始时间不能晚于结束时间(可在前端或后端添加验证) | ||
| 156 | +5. **空值处理**: 时间参数为空时不添加查询条件 | ||
| 157 | + | ||
| 158 | +## 扩展功能 | ||
| 159 | + | ||
| 160 | +### 1. 可添加的查询条件 | ||
| 161 | +- 更新时间范围查询 | ||
| 162 | +- 最后登录时间范围查询 | ||
| 163 | +- 多时间字段组合查询 | ||
| 164 | + | ||
| 165 | +### 2. 可优化的功能 | ||
| 166 | +- 时间格式自动转换 | ||
| 167 | +- 时区统一处理 | ||
| 168 | +- 查询结果缓存 | ||
| 169 | +- 时间范围验证 | ||
| 170 | + | ||
| 171 | +## 相关文件 | ||
| 172 | + | ||
| 173 | +- `UserQueryReq.java` - 查询请求DTO | ||
| 174 | +- `SysUserController.java` - 用户控制器 | ||
| 175 | +- `SysUserService.java` - 用户服务接口 | ||
| 176 | +- `SysUserServiceImpl.java` - 用户服务实现 | ||
| 177 | +- `API接口文档.md` - API文档更新 |
-
Please register or login to post a comment