ai-engineering-init 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/skill-forced-eval.js +46 -62
- package/.claude/settings.json +10 -1
- package/.claude/skills/api-development/SKILL.md +179 -130
- package/.claude/skills/architecture-design/SKILL.md +102 -212
- package/.claude/skills/backend-annotations/SKILL.md +166 -220
- package/.claude/skills/bug-detective/SKILL.md +225 -186
- package/.claude/skills/code-patterns/SKILL.md +127 -244
- package/.claude/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.claude/skills/crud-development/SKILL.md +226 -307
- package/.claude/skills/data-permission/SKILL.md +131 -202
- package/.claude/skills/database-ops/SKILL.md +158 -355
- package/.claude/skills/error-handler/SKILL.md +224 -285
- package/.claude/skills/file-oss-management/SKILL.md +174 -169
- package/.claude/skills/git-workflow/SKILL.md +123 -341
- package/.claude/skills/json-serialization/SKILL.md +121 -137
- package/.claude/skills/performance-doctor/SKILL.md +83 -89
- package/.claude/skills/redis-cache/SKILL.md +134 -185
- package/.claude/skills/scheduled-jobs/SKILL.md +187 -224
- package/.claude/skills/security-guard/SKILL.md +168 -276
- package/.claude/skills/sms-mail/SKILL.md +266 -228
- package/.claude/skills/social-login/SKILL.md +257 -195
- package/.claude/skills/tenant-management/SKILL.md +172 -188
- package/.claude/skills/utils-toolkit/SKILL.md +214 -222
- package/.claude/skills/websocket-sse/SKILL.md +251 -172
- package/.claude/skills/workflow-engine/SKILL.md +178 -250
- package/.codex/skills/api-development/SKILL.md +179 -130
- package/.codex/skills/architecture-design/SKILL.md +102 -212
- package/.codex/skills/backend-annotations/SKILL.md +166 -220
- package/.codex/skills/bug-detective/SKILL.md +225 -186
- package/.codex/skills/code-patterns/SKILL.md +127 -244
- package/.codex/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.codex/skills/crud-development/SKILL.md +226 -307
- package/.codex/skills/data-permission/SKILL.md +131 -202
- package/.codex/skills/database-ops/SKILL.md +158 -355
- package/.codex/skills/error-handler/SKILL.md +224 -285
- package/.codex/skills/file-oss-management/SKILL.md +174 -169
- package/.codex/skills/git-workflow/SKILL.md +123 -341
- package/.codex/skills/json-serialization/SKILL.md +121 -137
- package/.codex/skills/performance-doctor/SKILL.md +83 -89
- package/.codex/skills/redis-cache/SKILL.md +134 -185
- package/.codex/skills/scheduled-jobs/SKILL.md +187 -224
- package/.codex/skills/security-guard/SKILL.md +168 -276
- package/.codex/skills/sms-mail/SKILL.md +266 -228
- package/.codex/skills/social-login/SKILL.md +257 -195
- package/.codex/skills/tenant-management/SKILL.md +172 -188
- package/.codex/skills/utils-toolkit/SKILL.md +214 -222
- package/.codex/skills/websocket-sse/SKILL.md +251 -172
- package/.codex/skills/workflow-engine/SKILL.md +178 -250
- package/.cursor/hooks/cursor-skill-eval.js +66 -6
- package/.cursor/skills/api-development/SKILL.md +179 -130
- package/.cursor/skills/architecture-design/SKILL.md +102 -212
- package/.cursor/skills/backend-annotations/SKILL.md +166 -220
- package/.cursor/skills/bug-detective/SKILL.md +225 -186
- package/.cursor/skills/code-patterns/SKILL.md +127 -244
- package/.cursor/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.cursor/skills/crud-development/SKILL.md +226 -307
- package/.cursor/skills/data-permission/SKILL.md +131 -202
- package/.cursor/skills/database-ops/SKILL.md +158 -355
- package/.cursor/skills/error-handler/SKILL.md +224 -285
- package/.cursor/skills/file-oss-management/SKILL.md +174 -169
- package/.cursor/skills/git-workflow/SKILL.md +123 -341
- package/.cursor/skills/json-serialization/SKILL.md +121 -137
- package/.cursor/skills/performance-doctor/SKILL.md +83 -89
- package/.cursor/skills/redis-cache/SKILL.md +134 -185
- package/.cursor/skills/scheduled-jobs/SKILL.md +187 -224
- package/.cursor/skills/security-guard/SKILL.md +168 -276
- package/.cursor/skills/sms-mail/SKILL.md +266 -228
- package/.cursor/skills/social-login/SKILL.md +257 -195
- package/.cursor/skills/tenant-management/SKILL.md +172 -188
- package/.cursor/skills/utils-toolkit/SKILL.md +214 -222
- package/.cursor/skills/websocket-sse/SKILL.md +251 -172
- package/.cursor/skills/workflow-engine/SKILL.md +178 -250
- package/AGENTS.md +49 -540
- package/CLAUDE.md +73 -119
- package/README.md +37 -6
- package/bin/index.js +5 -1
- package/package.json +1 -1
- package/src/skills/api-development/SKILL.md +179 -130
- package/src/skills/architecture-design/SKILL.md +102 -212
- package/src/skills/backend-annotations/SKILL.md +166 -220
- package/src/skills/bug-detective/SKILL.md +225 -186
- package/src/skills/code-patterns/SKILL.md +127 -244
- package/src/skills/collaborating-with-codex/SKILL.md +96 -113
- package/src/skills/crud-development/SKILL.md +226 -307
- package/src/skills/data-permission/SKILL.md +131 -202
- package/src/skills/database-ops/SKILL.md +158 -355
- package/src/skills/error-handler/SKILL.md +224 -285
- package/src/skills/file-oss-management/SKILL.md +174 -169
- package/src/skills/git-workflow/SKILL.md +123 -341
- package/src/skills/json-serialization/SKILL.md +121 -137
- package/src/skills/performance-doctor/SKILL.md +83 -89
- package/src/skills/redis-cache/SKILL.md +134 -185
- package/src/skills/scheduled-jobs/SKILL.md +187 -224
- package/src/skills/security-guard/SKILL.md +168 -276
- package/src/skills/sms-mail/SKILL.md +266 -228
- package/src/skills/social-login/SKILL.md +257 -195
- package/src/skills/tenant-management/SKILL.md +172 -188
- package/src/skills/utils-toolkit/SKILL.md +214 -222
- package/src/skills/websocket-sse/SKILL.md +251 -172
- package/src/skills/workflow-engine/SKILL.md +178 -250
- package/.claude/skills/skill-creator/LICENSE.txt +0 -202
- package/.claude/skills/skill-creator/SKILL.md +0 -479
- package/.claude/skills/skill-creator/agents/analyzer.md +0 -274
- package/.claude/skills/skill-creator/agents/comparator.md +0 -202
- package/.claude/skills/skill-creator/agents/grader.md +0 -223
- package/.claude/skills/skill-creator/assets/eval_review.html +0 -146
- package/.claude/skills/skill-creator/eval-viewer/generate_review.py +0 -471
- package/.claude/skills/skill-creator/eval-viewer/viewer.html +0 -1325
- package/.claude/skills/skill-creator/references/schemas.md +0 -430
- package/.claude/skills/skill-creator/scripts/__init__.py +0 -0
- package/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +0 -401
- package/.claude/skills/skill-creator/scripts/generate_report.py +0 -326
- package/.claude/skills/skill-creator/scripts/improve_description.py +0 -248
- package/.claude/skills/skill-creator/scripts/package_skill.py +0 -136
- package/.claude/skills/skill-creator/scripts/quick_validate.py +0 -103
- package/.claude/skills/skill-creator/scripts/run_eval.py +0 -310
- package/.claude/skills/skill-creator/scripts/run_loop.py +0 -332
- package/.claude/skills/skill-creator/scripts/utils.py +0 -47
|
@@ -1,328 +1,319 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: utils-toolkit
|
|
3
3
|
description: |
|
|
4
|
-
|
|
4
|
+
后端工具类使用指南。包含对象转换、字符串处理、集合操作、树结构构建、日期时间、JSON、参数校验等通用工具类选型与使用规范。
|
|
5
5
|
|
|
6
6
|
触发场景:
|
|
7
7
|
- 对象转换(BO/VO/Entity)
|
|
8
8
|
- 字符串处理、集合流操作
|
|
9
9
|
- 树结构构建
|
|
10
|
-
-
|
|
11
|
-
-
|
|
10
|
+
- JSON 序列化/反序列化
|
|
11
|
+
- 日期时间处理
|
|
12
|
+
- 参数校验
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
触发词:工具类、对象转换、BeanUtils、StringUtils、集合操作、树结构、DateUtils、JsonUtils、convert、字符串处理、日期时间
|
|
14
15
|
|
|
15
16
|
注意:
|
|
16
|
-
-
|
|
17
|
-
-
|
|
17
|
+
- 对象转换工具需要根据项目实际选型统一使用,禁止混用多种方案。
|
|
18
|
+
- 本指南为通用 Java 后端工具类指南,适配各类 Spring Boot 项目。
|
|
18
19
|
---
|
|
19
20
|
|
|
20
21
|
# 后端工具类大全
|
|
21
22
|
|
|
22
23
|
## 快速索引
|
|
23
24
|
|
|
24
|
-
| 功能 |
|
|
25
|
-
|
|
26
|
-
| **对象转换** | `
|
|
27
|
-
| 字符串 | `
|
|
28
|
-
| 集合/流 | `
|
|
29
|
-
| 树结构 | `
|
|
30
|
-
| 日期时间 | `
|
|
31
|
-
| 参数校验 |
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
| 业务异常 | `ServiceException` | `o.d.common.core.exception` | `throw new ServiceException()` |
|
|
37
|
-
| Spring容器 | `SpringUtils` | `o.d.common.core.utils` | `getBean()` |
|
|
38
|
-
|
|
39
|
-
> **包路径说明**: `o.d` = `org.dromara`
|
|
25
|
+
| 功能 | 推荐方案 | 备选方案 | 常用方法 |
|
|
26
|
+
|------|---------|---------|---------|
|
|
27
|
+
| **对象转换** | `[你的对象转换工具]` | MapStruct / BeanUtils / ModelMapper | `convert()` / `copyProperties()` |
|
|
28
|
+
| 字符串 | Hutool `StrUtil` | Apache Commons `StringUtils` / Guava `Strings` | `isBlank()`, `format()` |
|
|
29
|
+
| 集合/流 | Hutool `CollUtil` + Java Stream | Guava `Collections2` | `isEmpty()`, `filter()`, `toList()` |
|
|
30
|
+
| 树结构 | Hutool `TreeUtil` | 自定义递归构建 | `build()` |
|
|
31
|
+
| 日期时间 | `java.time` API | Hutool `DateUtil` | `LocalDateTime.now()`, `format()` |
|
|
32
|
+
| 参数校验 | Jakarta Validation | Hutool `Validator` | `@NotNull`, `@NotBlank` |
|
|
33
|
+
| JSON | Jackson `ObjectMapper` | Gson / Hutool `JSONUtil` | `toJsonString()`, `parseObject()` |
|
|
34
|
+
| 业务异常 | `[你的异常类]` | 自定义 RuntimeException | `throw new [YourException]()` |
|
|
35
|
+
| 登录用户 | `[你的用户上下文工具]` | SecurityContextHolder / 自定义 ThreadLocal | `getUserId()`, `getUsername()` |
|
|
36
|
+
| Spring容器 | `ApplicationContext` | 自定义 `SpringUtils` | `getBean()` |
|
|
40
37
|
|
|
41
38
|
---
|
|
42
39
|
|
|
43
|
-
## 1. 对象转换
|
|
40
|
+
## 1. 对象转换
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
### 选型对比
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
| 方案 | 性能 | 易用性 | 特点 |
|
|
45
|
+
|------|------|--------|------|
|
|
46
|
+
| **MapStruct** | 极高(编译期生成) | 中(需定义接口) | 类型安全、零反射 |
|
|
47
|
+
| **Hutool BeanUtil** | 中(反射) | 高(一行调用) | 简单场景首选 |
|
|
48
|
+
| **Spring BeanUtils** | 中(反射) | 高 | Spring 内置,无额外依赖 |
|
|
49
|
+
| **ModelMapper** | 低 | 高(约定优于配置) | 深度映射、复杂场景 |
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
XxxVo vo = MapstructUtils.convert(entity, XxxVo.class);
|
|
51
|
+
### 通用用法
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
```java
|
|
54
|
+
// 方案 A: Hutool BeanUtil(简单场景推荐)
|
|
55
|
+
import cn.hutool.core.bean.BeanUtil;
|
|
56
|
+
|
|
57
|
+
XxxVo vo = BeanUtil.copyProperties(entity, XxxVo.class);
|
|
58
|
+
List<XxxVo> voList = BeanUtil.copyToList(entityList, XxxVo.class);
|
|
59
|
+
|
|
60
|
+
// 方案 B: MapStruct(高性能场景推荐)
|
|
61
|
+
// 1. 定义 Mapper 接口
|
|
62
|
+
@Mapper(componentModel = "spring")
|
|
63
|
+
public interface XxxConverter {
|
|
64
|
+
XxxVo toVo(XxxEntity entity);
|
|
65
|
+
List<XxxVo> toVoList(List<XxxEntity> entities);
|
|
66
|
+
}
|
|
55
67
|
|
|
56
|
-
//
|
|
57
|
-
|
|
68
|
+
// 2. 注入使用
|
|
69
|
+
@Resource
|
|
70
|
+
private XxxConverter xxxConverter;
|
|
71
|
+
XxxVo vo = xxxConverter.toVo(entity);
|
|
58
72
|
```
|
|
59
73
|
|
|
60
|
-
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 2. 字符串操作
|
|
77
|
+
|
|
78
|
+
### Hutool StrUtil
|
|
61
79
|
|
|
62
80
|
```java
|
|
63
|
-
|
|
64
|
-
public class XxxBo extends BaseEntity { }
|
|
81
|
+
import cn.hutool.core.util.StrUtil;
|
|
65
82
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
// 判空
|
|
84
|
+
StrUtil.isBlank(str); // null / "" / " " -> true
|
|
85
|
+
StrUtil.isNotBlank(str);
|
|
69
86
|
|
|
70
|
-
|
|
87
|
+
// 格式化(占位符 {})
|
|
88
|
+
StrUtil.format("用户 {} 不存在", userId);
|
|
71
89
|
|
|
72
|
-
|
|
90
|
+
// 分割/拼接
|
|
91
|
+
List<String> list = StrUtil.split("1,2,3", ',');
|
|
92
|
+
String joined = String.join(",", list);
|
|
93
|
+
```
|
|
73
94
|
|
|
74
|
-
|
|
75
|
-
import org.dromara.common.core.utils.StringUtils;
|
|
95
|
+
### Apache Commons StringUtils
|
|
76
96
|
|
|
77
|
-
|
|
78
|
-
StringUtils
|
|
97
|
+
```java
|
|
98
|
+
import org.apache.commons.lang3.StringUtils;
|
|
79
99
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
100
|
+
StringUtils.isBlank(str);
|
|
101
|
+
StringUtils.substringBefore(str, "-");
|
|
102
|
+
StringUtils.leftPad("5", 3, '0'); // "005"
|
|
103
|
+
```
|
|
84
104
|
|
|
85
|
-
|
|
86
|
-
StringUtils.toCamelCase("user_name"); // "userName"
|
|
87
|
-
StringUtils.toUnderScoreCase("userName"); // "user_name"
|
|
105
|
+
### Guava Strings
|
|
88
106
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
StringUtils.matches("/api/user", Arrays.asList("/api/**", "/admin/**"));
|
|
107
|
+
```java
|
|
108
|
+
import com.google.common.base.Strings;
|
|
92
109
|
|
|
93
|
-
|
|
94
|
-
|
|
110
|
+
Strings.isNullOrEmpty(str);
|
|
111
|
+
Strings.padStart("5", 3, '0'); // "005"
|
|
95
112
|
```
|
|
96
113
|
|
|
97
114
|
---
|
|
98
115
|
|
|
99
|
-
## 3. 集合与流操作
|
|
116
|
+
## 3. 集合与流操作
|
|
117
|
+
|
|
118
|
+
### Hutool CollUtil
|
|
100
119
|
|
|
101
120
|
```java
|
|
102
|
-
import
|
|
121
|
+
import cn.hutool.core.collection.CollUtil;
|
|
103
122
|
|
|
104
|
-
//
|
|
105
|
-
|
|
123
|
+
CollUtil.isEmpty(list); // null 或空 -> true
|
|
124
|
+
CollUtil.isNotEmpty(list);
|
|
125
|
+
```
|
|
106
126
|
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
### Java Stream API
|
|
128
|
+
|
|
129
|
+
```java
|
|
130
|
+
// 过滤
|
|
131
|
+
List<User> active = users.stream()
|
|
132
|
+
.filter(u -> "1".equals(u.getStatus()))
|
|
133
|
+
.toList();
|
|
109
134
|
|
|
110
135
|
// 提取属性
|
|
111
|
-
List<Long> ids =
|
|
112
|
-
|
|
136
|
+
List<Long> ids = users.stream()
|
|
137
|
+
.map(User::getId)
|
|
138
|
+
.toList();
|
|
139
|
+
|
|
140
|
+
Set<Long> deptIds = users.stream()
|
|
141
|
+
.map(User::getDeptId)
|
|
142
|
+
.collect(Collectors.toSet());
|
|
113
143
|
|
|
114
144
|
// 转 Map
|
|
115
|
-
Map<Long, User> userMap =
|
|
116
|
-
|
|
145
|
+
Map<Long, User> userMap = users.stream()
|
|
146
|
+
.collect(Collectors.toMap(User::getId, Function.identity()));
|
|
147
|
+
|
|
148
|
+
Map<Long, String> nameMap = users.stream()
|
|
149
|
+
.collect(Collectors.toMap(User::getId, User::getName));
|
|
117
150
|
|
|
118
151
|
// 分组
|
|
119
|
-
Map<Long, List<User>> grouped =
|
|
152
|
+
Map<Long, List<User>> grouped = users.stream()
|
|
153
|
+
.collect(Collectors.groupingBy(User::getDeptId));
|
|
120
154
|
|
|
121
155
|
// 拼接字符串
|
|
122
|
-
String names =
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// 排序 / 合并 Map
|
|
126
|
-
List<User> sorted = StreamUtils.sorted(users, Comparator.comparing(User::getCreateTime));
|
|
127
|
-
Map<Long, String> merged = StreamUtils.merge(map1, map2, (v1, v2) -> v1 + v2);
|
|
156
|
+
String names = users.stream()
|
|
157
|
+
.map(User::getName)
|
|
158
|
+
.collect(Collectors.joining(","));
|
|
128
159
|
```
|
|
129
160
|
|
|
130
161
|
---
|
|
131
162
|
|
|
132
|
-
## 4. 树结构构建
|
|
163
|
+
## 4. 树结构构建
|
|
164
|
+
|
|
165
|
+
### Hutool TreeUtil
|
|
133
166
|
|
|
134
167
|
```java
|
|
135
|
-
import org.dromara.common.core.utils.TreeBuildUtils;
|
|
136
168
|
import cn.hutool.core.lang.tree.Tree;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
169
|
+
import cn.hutool.core.lang.tree.TreeUtil;
|
|
170
|
+
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
|
171
|
+
|
|
172
|
+
List<Tree<Long>> tree = TreeUtil.build(list, 0L, (item, treeNode) -> {
|
|
173
|
+
treeNode.setId(item.getId());
|
|
174
|
+
treeNode.setParentId(item.getParentId());
|
|
175
|
+
treeNode.setName(item.getName());
|
|
176
|
+
treeNode.setWeight(item.getOrderNum());
|
|
177
|
+
treeNode.putExtra("icon", item.getIcon());
|
|
144
178
|
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 自定义递归构建
|
|
145
182
|
|
|
146
|
-
|
|
147
|
-
List<
|
|
183
|
+
```java
|
|
184
|
+
public List<TreeNode> buildTree(List<TreeNode> nodes, Long parentId) {
|
|
185
|
+
return nodes.stream()
|
|
186
|
+
.filter(n -> Objects.equals(n.getParentId(), parentId))
|
|
187
|
+
.peek(n -> n.setChildren(buildTree(nodes, n.getId())))
|
|
188
|
+
.sorted(Comparator.comparingInt(TreeNode::getSort))
|
|
189
|
+
.toList();
|
|
190
|
+
}
|
|
148
191
|
```
|
|
149
192
|
|
|
150
193
|
---
|
|
151
194
|
|
|
152
|
-
## 5. 日期时间 -
|
|
195
|
+
## 5. 日期时间 - java.time API
|
|
153
196
|
|
|
154
197
|
```java
|
|
155
|
-
import
|
|
156
|
-
import
|
|
198
|
+
import java.time.LocalDateTime;
|
|
199
|
+
import java.time.LocalDate;
|
|
200
|
+
import java.time.format.DateTimeFormatter;
|
|
201
|
+
import java.time.Duration;
|
|
202
|
+
import java.time.temporal.ChronoUnit;
|
|
157
203
|
|
|
158
204
|
// 获取当前时间
|
|
159
|
-
|
|
160
|
-
|
|
205
|
+
LocalDateTime now = LocalDateTime.now();
|
|
206
|
+
LocalDate today = LocalDate.now();
|
|
161
207
|
|
|
162
|
-
// 格式化
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
Date date = DateUtils.parseDateTime(FormatsType.YYYY_MM_DD_HH_MM_SS, "2026-01-24 15:30:00");
|
|
208
|
+
// 格式化
|
|
209
|
+
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
210
|
+
String formatted = now.format(fmt);
|
|
166
211
|
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
String diff = DateUtils.getDatePoor(endDate, startDate); // "3天 2小时 30分钟"
|
|
170
|
-
|
|
171
|
-
// 日期范围校验
|
|
172
|
-
DateUtils.validateDateRange(startDate, endDate, 30, TimeUnit.DAYS);
|
|
212
|
+
// 解析
|
|
213
|
+
LocalDateTime parsed = LocalDateTime.parse("2026-01-24 15:30:00", fmt);
|
|
173
214
|
|
|
174
|
-
//
|
|
175
|
-
|
|
215
|
+
// 时间差
|
|
216
|
+
long days = ChronoUnit.DAYS.between(start, end);
|
|
217
|
+
Duration duration = Duration.between(start, end);
|
|
218
|
+
long hours = duration.toHours();
|
|
176
219
|
|
|
177
|
-
//
|
|
178
|
-
|
|
220
|
+
// 日期加减
|
|
221
|
+
LocalDateTime tomorrow = now.plusDays(1);
|
|
222
|
+
LocalDateTime lastMonth = now.minusMonths(1);
|
|
179
223
|
```
|
|
180
224
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## 6. 参数校验 - ValidatorUtils
|
|
225
|
+
### Hutool DateUtil(兼容旧 Date 类型)
|
|
186
226
|
|
|
187
227
|
```java
|
|
188
|
-
import
|
|
189
|
-
import org.dromara.common.core.validate.AddGroup;
|
|
190
|
-
import org.dromara.common.core.validate.EditGroup;
|
|
228
|
+
import cn.hutool.core.date.DateUtil;
|
|
191
229
|
|
|
192
|
-
//
|
|
193
|
-
|
|
230
|
+
// 自动识别多种格式
|
|
231
|
+
Date date = DateUtil.parse("2026-01-24 15:30:00");
|
|
232
|
+
String formatted = DateUtil.formatDateTime(date);
|
|
194
233
|
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
public R<Void> add(@Validated(AddGroup.class) @RequestBody XxxBo bo) { }
|
|
198
|
-
|
|
199
|
-
@PutMapping
|
|
200
|
-
public R<Void> edit(@Validated(EditGroup.class) @RequestBody XxxBo bo) { }
|
|
234
|
+
// 时间差
|
|
235
|
+
long between = DateUtil.between(start, end, DateUnit.DAY);
|
|
201
236
|
```
|
|
202
237
|
|
|
203
|
-
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 6. 参数校验
|
|
241
|
+
|
|
242
|
+
### Jakarta Validation(JDK 17+ 推荐)
|
|
204
243
|
|
|
205
244
|
```java
|
|
206
|
-
|
|
207
|
-
|
|
245
|
+
import jakarta.validation.constraints.*;
|
|
246
|
+
|
|
247
|
+
public class XxxDTO {
|
|
248
|
+
@NotNull(message = "ID不能为空", groups = {UpdateGroup.class})
|
|
208
249
|
private Long id;
|
|
209
250
|
|
|
210
|
-
@NotBlank(message = "名称不能为空", groups = {
|
|
251
|
+
@NotBlank(message = "名称不能为空", groups = {InsertGroup.class, UpdateGroup.class})
|
|
211
252
|
@Size(max = 100, message = "名称长度不能超过100个字符")
|
|
212
253
|
private String name;
|
|
254
|
+
|
|
255
|
+
@Min(value = 0, message = "数量不能为负数")
|
|
256
|
+
private Integer quantity;
|
|
213
257
|
}
|
|
214
258
|
```
|
|
215
259
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
## 7. Redis 缓存 - RedisUtils
|
|
219
|
-
|
|
220
|
-
> 详细 API 见 `references/redis-utils-api.md`
|
|
260
|
+
### Controller 层使用
|
|
221
261
|
|
|
222
262
|
```java
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
// 基本操作
|
|
226
|
-
RedisUtils.setCacheObject("key", value);
|
|
227
|
-
RedisUtils.setCacheObject("key", value, Duration.ofMinutes(30));
|
|
228
|
-
RedisUtils.getCacheObject("key");
|
|
229
|
-
RedisUtils.deleteObject("key");
|
|
230
|
-
RedisUtils.hasKey("key");
|
|
231
|
-
|
|
232
|
-
// 条件设置
|
|
233
|
-
RedisUtils.setObjectIfAbsent("key", value, Duration.ofMinutes(5));
|
|
234
|
-
|
|
235
|
-
// List / Set / Map 操作
|
|
236
|
-
RedisUtils.setCacheList("listKey", dataList);
|
|
237
|
-
RedisUtils.setCacheMap("mapKey", dataMap);
|
|
238
|
-
RedisUtils.setCacheMapValue("mapKey", "field", value);
|
|
239
|
-
|
|
240
|
-
// 原子操作
|
|
241
|
-
long val = RedisUtils.incrAtomicValue("counter");
|
|
263
|
+
@PostMapping("/add")
|
|
264
|
+
public void add(@Validated(InsertGroup.class) @RequestBody XxxDTO dto) { }
|
|
242
265
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
RedisUtils.subscribe("channel", Message.class, msg -> { });
|
|
246
|
-
|
|
247
|
-
// 限流
|
|
248
|
-
long remaining = RedisUtils.rateLimiter("api:user:list", RateType.OVERALL, 100, 60);
|
|
266
|
+
@PutMapping("/update")
|
|
267
|
+
public void edit(@Validated(UpdateGroup.class) @RequestBody XxxDTO dto) { }
|
|
249
268
|
```
|
|
250
269
|
|
|
251
270
|
---
|
|
252
271
|
|
|
253
|
-
##
|
|
254
|
-
|
|
255
|
-
```java
|
|
256
|
-
import org.dromara.common.satoken.utils.LoginHelper;
|
|
257
|
-
|
|
258
|
-
Long userId = LoginHelper.getUserId();
|
|
259
|
-
String username = LoginHelper.getUsername();
|
|
260
|
-
Long deptId = LoginHelper.getDeptId();
|
|
261
|
-
String tenantId = LoginHelper.getTenantId();
|
|
262
|
-
LoginUser loginUser = LoginHelper.getLoginUser();
|
|
263
|
-
boolean isLogin = LoginHelper.isLogin();
|
|
264
|
-
boolean isSuperAdmin = LoginHelper.isSuperAdmin();
|
|
265
|
-
boolean isTenantAdmin = LoginHelper.isTenantAdmin();
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
---
|
|
272
|
+
## 7. JSON 操作
|
|
269
273
|
|
|
270
|
-
|
|
274
|
+
### Jackson(Spring Boot 默认)
|
|
271
275
|
|
|
272
276
|
```java
|
|
273
|
-
import
|
|
274
|
-
|
|
275
|
-
throw new ServiceException("用户不存在");
|
|
276
|
-
throw new ServiceException("用户 {} 不存在", userId);
|
|
277
|
-
throw new ServiceException("用户不存在", 500); // 带错误码
|
|
278
|
-
```
|
|
277
|
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
279
278
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
// 推荐封装为项目统一的 JsonUtils
|
|
280
|
+
public class JsonUtils {
|
|
281
|
+
private static final ObjectMapper MAPPER = new ObjectMapper();
|
|
283
282
|
|
|
284
|
-
|
|
285
|
-
|
|
283
|
+
public static String toJsonString(Object obj) {
|
|
284
|
+
return MAPPER.writeValueAsString(obj);
|
|
285
|
+
}
|
|
286
286
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
List<XxxVo> list = xxxService.queryList(bo);
|
|
291
|
-
ExcelUtil.exportExcel(list, "数据导出", XxxVo.class, response);
|
|
292
|
-
}
|
|
287
|
+
public static <T> T parseObject(String json, Class<T> clazz) {
|
|
288
|
+
return MAPPER.readValue(json, clazz);
|
|
289
|
+
}
|
|
293
290
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
return R.ok();
|
|
291
|
+
public static <T> List<T> parseArray(String json, Class<T> clazz) {
|
|
292
|
+
return MAPPER.readValue(json,
|
|
293
|
+
MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
|
|
294
|
+
}
|
|
299
295
|
}
|
|
300
296
|
```
|
|
301
297
|
|
|
302
|
-
|
|
298
|
+
### Hutool JSONUtil
|
|
303
299
|
|
|
304
300
|
```java
|
|
305
|
-
|
|
306
|
-
@ExcelProperty(value = "ID")
|
|
307
|
-
private Long id;
|
|
301
|
+
import cn.hutool.json.JSONUtil;
|
|
308
302
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
private String status;
|
|
312
|
-
}
|
|
303
|
+
String json = JSONUtil.toJsonStr(obj);
|
|
304
|
+
User user = JSONUtil.toBean(json, User.class);
|
|
313
305
|
```
|
|
314
306
|
|
|
315
307
|
---
|
|
316
308
|
|
|
317
|
-
##
|
|
309
|
+
## 8. 对象判空
|
|
318
310
|
|
|
319
311
|
```java
|
|
320
|
-
import
|
|
312
|
+
import cn.hutool.core.util.ObjectUtil;
|
|
321
313
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
Map<String, Object> map = JsonUtils.parseMap(json);
|
|
314
|
+
ObjectUtil.isNull(obj); // null -> true
|
|
315
|
+
ObjectUtil.isNotNull(obj);
|
|
316
|
+
ObjectUtil.defaultIfNull(obj, defaultValue);
|
|
326
317
|
```
|
|
327
318
|
|
|
328
319
|
---
|
|
@@ -331,18 +322,17 @@ Map<String, Object> map = JsonUtils.parseMap(json);
|
|
|
331
322
|
|
|
332
323
|
| 需求 | 推荐工具 | 说明 |
|
|
333
324
|
|------|---------|------|
|
|
334
|
-
| BO/Entity/VO 转换 | `
|
|
335
|
-
| 字符串判空 | `
|
|
325
|
+
| BO/Entity/VO 转换 | `[你的对象转换工具]` | 项目统一选型 |
|
|
326
|
+
| 字符串判空 | `StrUtil.isBlank()` | Hutool |
|
|
336
327
|
| 集合判空 | `CollUtil.isEmpty()` | Hutool |
|
|
337
328
|
| 对象判空 | `ObjectUtil.isNull()` | Hutool |
|
|
338
|
-
| 提取集合属性 | `
|
|
339
|
-
| 集合转 Map | `
|
|
340
|
-
| 构建树 | `
|
|
341
|
-
| 日期格式化 | `
|
|
342
|
-
| 抛业务异常 | `throw new
|
|
343
|
-
| 获取登录用户 | `
|
|
344
|
-
|
|
|
345
|
-
| Excel 导出 | `ExcelUtil.exportExcel()` | 项目工具类 |
|
|
329
|
+
| 提取集合属性 | `Stream.map().toList()` | Java Stream |
|
|
330
|
+
| 集合转 Map | `Collectors.toMap()` | Java Stream |
|
|
331
|
+
| 构建树 | `TreeUtil.build()` | Hutool |
|
|
332
|
+
| 日期格式化 | `LocalDateTime.format()` | java.time |
|
|
333
|
+
| 抛业务异常 | `throw new [你的异常类]()` | 项目自定义 |
|
|
334
|
+
| 获取登录用户 | `[你的用户上下文工具]` | 项目自定义 |
|
|
335
|
+
| Excel 导出 | EasyExcel / Apache POI | 按需选型 |
|
|
346
336
|
| 生成 ID | `IdUtil.getSnowflakeNextId()` | Hutool |
|
|
347
337
|
|
|
348
338
|
---
|
|
@@ -350,13 +340,15 @@ Map<String, Object> map = JsonUtils.parseMap(json);
|
|
|
350
340
|
## 禁止事项
|
|
351
341
|
|
|
352
342
|
```java
|
|
353
|
-
// ❌ 禁止使用 BeanUtils
|
|
354
|
-
BeanUtils.copyProperties(source, target);
|
|
355
|
-
|
|
356
343
|
// ❌ 禁止使用 Map 传递业务数据
|
|
357
344
|
public Map<String, Object> getXxx() { ... }
|
|
345
|
+
// ✅ 正确:使用 VO/DTO
|
|
346
|
+
public XxxVO getXxx() { ... }
|
|
347
|
+
|
|
348
|
+
// ❌ 禁止频繁创建 ObjectMapper
|
|
349
|
+
ObjectMapper mapper = new ObjectMapper();
|
|
350
|
+
// ✅ 正确:使用单例或项目统一封装的 JsonUtils
|
|
358
351
|
|
|
359
|
-
// ❌
|
|
360
|
-
|
|
361
|
-
StreamUtils.toList(list, User::getId); // ✅ 推荐
|
|
352
|
+
// ❌ 禁止混用多种对象转换工具
|
|
353
|
+
// ✅ 正确:项目统一选型,保持一致
|
|
362
354
|
```
|