ai-engineering-init 1.6.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/agents/code-reviewer.md +3 -130
- package/.claude/hooks/skill-forced-eval.js +46 -60
- package/.claude/hooks/stop.js +24 -1
- 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/codex-code-review/SKILL.md +327 -0
- 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/leniu-report-customization/SKILL.md +82 -2
- package/.claude/skills/leniu-report-standard-customization/SKILL.md +65 -2
- package/.claude/skills/loki-log-query/SKILL.md +400 -0
- package/.claude/skills/mysql-debug/SKILL.md +58 -22
- 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/sync-back-merge/SKILL.md +66 -0
- 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/.claude/skills/yunxiao-task-management/SKILL.md +489 -0
- 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/leniu-report-customization/SKILL.md +82 -2
- package/.codex/skills/leniu-report-standard-customization/SKILL.md +65 -2
- package/.codex/skills/loki-log-query/SKILL.md +400 -0
- package/.codex/skills/loki-log-query/environments.json +45 -0
- package/.codex/skills/mysql-debug/SKILL.md +58 -22
- 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/skill-creator/LICENSE.txt +202 -0
- package/.codex/skills/skill-creator/SKILL.md +479 -0
- package/.codex/skills/skill-creator/agents/analyzer.md +274 -0
- package/.codex/skills/skill-creator/agents/comparator.md +202 -0
- package/.codex/skills/skill-creator/agents/grader.md +223 -0
- package/.codex/skills/skill-creator/assets/eval_review.html +146 -0
- package/.codex/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.codex/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.codex/skills/skill-creator/references/schemas.md +430 -0
- package/.codex/skills/skill-creator/scripts/__init__.py +0 -0
- package/.codex/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.codex/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.codex/skills/skill-creator/scripts/improve_description.py +248 -0
- package/.codex/skills/skill-creator/scripts/package_skill.py +136 -0
- package/.codex/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/.codex/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.codex/skills/skill-creator/scripts/run_loop.py +332 -0
- package/.codex/skills/skill-creator/scripts/utils.py +47 -0
- package/.codex/skills/sms-mail/SKILL.md +266 -228
- package/.codex/skills/social-login/SKILL.md +257 -195
- package/.codex/skills/sync-back-merge/SKILL.md +66 -0
- 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/.codex/skills/yunxiao-task-management/SKILL.md +489 -0
- package/.cursor/hooks/cursor-skill-eval.js +66 -6
- package/.cursor/hooks/stop.js +23 -1
- 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/leniu-report-customization/SKILL.md +82 -2
- package/.cursor/skills/leniu-report-standard-customization/SKILL.md +65 -2
- package/.cursor/skills/loki-log-query/SKILL.md +400 -0
- package/.cursor/skills/loki-log-query/environments.json +45 -0
- package/.cursor/skills/mysql-debug/SKILL.md +58 -22
- 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/skill-creator/LICENSE.txt +202 -0
- package/.cursor/skills/skill-creator/SKILL.md +479 -0
- package/.cursor/skills/skill-creator/agents/analyzer.md +274 -0
- package/.cursor/skills/skill-creator/agents/comparator.md +202 -0
- package/.cursor/skills/skill-creator/agents/grader.md +223 -0
- package/.cursor/skills/skill-creator/assets/eval_review.html +146 -0
- package/.cursor/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.cursor/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.cursor/skills/skill-creator/references/schemas.md +430 -0
- package/.cursor/skills/skill-creator/scripts/__init__.py +0 -0
- package/.cursor/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.cursor/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.cursor/skills/skill-creator/scripts/improve_description.py +248 -0
- package/.cursor/skills/skill-creator/scripts/package_skill.py +136 -0
- package/.cursor/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/.cursor/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.cursor/skills/skill-creator/scripts/run_loop.py +332 -0
- package/.cursor/skills/skill-creator/scripts/utils.py +47 -0
- package/.cursor/skills/sms-mail/SKILL.md +266 -228
- package/.cursor/skills/social-login/SKILL.md +257 -195
- package/.cursor/skills/sync-back-merge/SKILL.md +66 -0
- 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/.cursor/skills/yunxiao-task-management/SKILL.md +489 -0
- package/AGENTS.md +49 -540
- package/CLAUDE.md +73 -119
- package/README.md +37 -6
- package/bin/index.js +611 -25
- package/package.json +1 -1
- package/src/platform-map.json +4 -0
- 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/codex-code-review/SKILL.md +261 -69
- 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/leniu-report-customization/SKILL.md +82 -2
- package/src/skills/leniu-report-standard-customization/SKILL.md +65 -2
- package/src/skills/loki-log-query/SKILL.md +400 -0
- package/src/skills/loki-log-query/environments.json +45 -0
- package/src/skills/mysql-debug/SKILL.md +58 -22
- 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/skill-creator/LICENSE.txt +202 -0
- package/src/skills/skill-creator/SKILL.md +479 -0
- package/src/skills/skill-creator/agents/analyzer.md +274 -0
- package/src/skills/skill-creator/agents/comparator.md +202 -0
- package/src/skills/skill-creator/agents/grader.md +223 -0
- package/src/skills/skill-creator/assets/eval_review.html +146 -0
- package/src/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/src/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/src/skills/skill-creator/references/schemas.md +430 -0
- package/src/skills/skill-creator/scripts/__init__.py +0 -0
- package/src/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/src/skills/skill-creator/scripts/generate_report.py +326 -0
- package/src/skills/skill-creator/scripts/improve_description.py +248 -0
- package/src/skills/skill-creator/scripts/package_skill.py +136 -0
- package/src/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/src/skills/skill-creator/scripts/run_eval.py +310 -0
- package/src/skills/skill-creator/scripts/run_loop.py +332 -0
- package/src/skills/skill-creator/scripts/utils.py +47 -0
- package/src/skills/sms-mail/SKILL.md +266 -228
- package/src/skills/social-login/SKILL.md +257 -195
- package/src/skills/sync-back-merge/SKILL.md +66 -0
- 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/src/skills/yunxiao-task-management/SKILL.md +489 -0
|
@@ -11,12 +11,12 @@ description: |
|
|
|
11
11
|
- JSON 格式验证
|
|
12
12
|
- 数据类型映射与转换
|
|
13
13
|
|
|
14
|
-
触发词:JSON、序列化、反序列化、JsonUtils、日期格式、精度、BigDecimal、Long、类型转换、JSON
|
|
14
|
+
触发词:JSON、序列化、反序列化、JsonUtils、日期格式、精度、BigDecimal、Long、类型转换、JSON验证、ObjectMapper、Jackson
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
# JSON 序列化与数据转换指南
|
|
18
18
|
|
|
19
|
-
>
|
|
19
|
+
> 基于 Jackson(Spring Boot 默认 JSON 处理库)
|
|
20
20
|
|
|
21
21
|
## 快速索引
|
|
22
22
|
|
|
@@ -25,46 +25,97 @@ description: |
|
|
|
25
25
|
| 对象转 JSON | `JsonUtils.toJsonString()` | null 返回 null |
|
|
26
26
|
| JSON 转对象 | `JsonUtils.parseObject()` | 空返回 null |
|
|
27
27
|
| JSON 转 List | `JsonUtils.parseArray()` | 空返回空 ArrayList |
|
|
28
|
-
| JSON 转
|
|
29
|
-
| JSON 数组转 Dict 列表 | `JsonUtils.parseArrayMap()` | 空返回 null |
|
|
28
|
+
| JSON 转 Map | `JsonUtils.parseMap()` | 非 JSON 返回 null |
|
|
30
29
|
| 复杂类型转换 | `JsonUtils.parseObject(text, TypeReference)` | 支持泛型 |
|
|
31
30
|
| JSON 验证 | `JsonUtils.isJson()` / `isJsonObject()` / `isJsonArray()` | |
|
|
32
|
-
| 字段校验注解 | `@JsonPattern` | 支持 OBJECT/ARRAY/ANY |
|
|
33
31
|
|
|
34
32
|
---
|
|
35
33
|
|
|
36
|
-
## 核心工具类 JsonUtils
|
|
34
|
+
## 核心工具类 JsonUtils(通用实现)
|
|
35
|
+
|
|
36
|
+
> 推荐封装一个项目级的 `JsonUtils`,内部使用 Jackson `ObjectMapper` 单例。
|
|
37
37
|
|
|
38
38
|
```java
|
|
39
|
-
import
|
|
40
|
-
|
|
39
|
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
40
|
+
import com.fasterxml.jackson.core.type.TypeReference;
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
public class JsonUtils {
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
//
|
|
46
|
-
|
|
44
|
+
private static final ObjectMapper MAPPER = SpringUtil.getBean(ObjectMapper.class);
|
|
45
|
+
// 或者:private static final ObjectMapper MAPPER = new ObjectMapper();
|
|
46
|
+
|
|
47
|
+
public static String toJsonString(Object obj) {
|
|
48
|
+
if (obj == null) return null;
|
|
49
|
+
try {
|
|
50
|
+
return MAPPER.writeValueAsString(obj);
|
|
51
|
+
} catch (Exception e) {
|
|
52
|
+
throw new RuntimeException("JSON序列化失败", e);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public static <T> T parseObject(String json, Class<T> clazz) {
|
|
57
|
+
if (json == null || json.isBlank()) return null;
|
|
58
|
+
try {
|
|
59
|
+
return MAPPER.readValue(json, clazz);
|
|
60
|
+
} catch (Exception e) {
|
|
61
|
+
throw new RuntimeException("JSON反序列化失败", e);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public static <T> T parseObject(String json, TypeReference<T> typeRef) {
|
|
66
|
+
if (json == null || json.isBlank()) return null;
|
|
67
|
+
try {
|
|
68
|
+
return MAPPER.readValue(json, typeRef);
|
|
69
|
+
} catch (Exception e) {
|
|
70
|
+
throw new RuntimeException("JSON反序列化失败", e);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public static <T> List<T> parseArray(String json, Class<T> clazz) {
|
|
75
|
+
if (json == null || json.isBlank()) return new ArrayList<>();
|
|
76
|
+
try {
|
|
77
|
+
return MAPPER.readValue(json,
|
|
78
|
+
MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, clazz));
|
|
79
|
+
} catch (Exception e) {
|
|
80
|
+
throw new RuntimeException("JSON反序列化失败", e);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public static boolean isJson(String str) {
|
|
85
|
+
return isJsonObject(str) || isJsonArray(str);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public static boolean isJsonObject(String str) {
|
|
89
|
+
if (str == null || str.isBlank()) return false;
|
|
90
|
+
return str.trim().startsWith("{") && str.trim().endsWith("}");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public static boolean isJsonArray(String str) {
|
|
94
|
+
if (str == null || str.isBlank()) return false;
|
|
95
|
+
return str.trim().startsWith("[") && str.trim().endsWith("]");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public static ObjectMapper getObjectMapper() {
|
|
99
|
+
return MAPPER;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
47
102
|
```
|
|
48
103
|
|
|
49
|
-
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 序列化与反序列化
|
|
107
|
+
|
|
108
|
+
### 基本用法
|
|
50
109
|
|
|
51
110
|
```java
|
|
52
|
-
// JSON
|
|
53
|
-
|
|
111
|
+
// 对象转 JSON 字符串
|
|
112
|
+
String json = JsonUtils.toJsonString(user);
|
|
54
113
|
|
|
55
|
-
//
|
|
56
|
-
User user = JsonUtils.parseObject(
|
|
114
|
+
// JSON 转简单对象
|
|
115
|
+
User user = JsonUtils.parseObject(json, User.class);
|
|
57
116
|
|
|
58
|
-
// JSON 数组转 List
|
|
117
|
+
// JSON 数组转 List
|
|
59
118
|
List<User> users = JsonUtils.parseArray(json, User.class);
|
|
60
|
-
|
|
61
|
-
// JSON 转 Dict(非 JSON 返回 null)
|
|
62
|
-
Dict dict = JsonUtils.parseMap(json);
|
|
63
|
-
String name = dict.getStr("name");
|
|
64
|
-
int age = dict.getInt("age");
|
|
65
|
-
|
|
66
|
-
// JSON 数组转 Dict 列表
|
|
67
|
-
List<Dict> dicts = JsonUtils.parseArrayMap(json);
|
|
68
119
|
```
|
|
69
120
|
|
|
70
121
|
### 复杂泛型类型
|
|
@@ -89,67 +140,46 @@ List<User> users = JsonUtils.parseObject(json, USER_LIST_TYPE);
|
|
|
89
140
|
### JSON 验证
|
|
90
141
|
|
|
91
142
|
```java
|
|
92
|
-
//
|
|
93
|
-
JsonUtils.isJson("
|
|
94
|
-
JsonUtils.isJson("
|
|
95
|
-
JsonUtils.isJson("not json"); // false
|
|
96
|
-
|
|
97
|
-
// 判断是否为 JSON 对象
|
|
98
|
-
JsonUtils.isJsonObject("{\"a\":1}"); // true
|
|
99
|
-
JsonUtils.isJsonObject("[1,2,3]"); // false
|
|
100
|
-
|
|
101
|
-
// 判断是否为 JSON 数组
|
|
102
|
-
JsonUtils.isJsonArray("[1,2,3]"); // true
|
|
103
|
-
JsonUtils.isJsonArray("{\"a\":1}"); // false
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### 获取 ObjectMapper
|
|
143
|
+
JsonUtils.isJson("{\"name\":\"test\"}"); // true
|
|
144
|
+
JsonUtils.isJson("[1,2,3]"); // true
|
|
145
|
+
JsonUtils.isJson("not json"); // false
|
|
107
146
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
JsonNode node = mapper.readTree(json);
|
|
147
|
+
JsonUtils.isJsonObject("{\"a\":1}"); // true
|
|
148
|
+
JsonUtils.isJsonArray("[1,2,3]"); // true
|
|
111
149
|
```
|
|
112
150
|
|
|
113
151
|
---
|
|
114
152
|
|
|
115
|
-
##
|
|
153
|
+
## Jackson 自动配置
|
|
116
154
|
|
|
117
|
-
|
|
155
|
+
### 推荐配置类
|
|
118
156
|
|
|
119
157
|
```java
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
158
|
+
@Configuration
|
|
159
|
+
public class JacksonConfig {
|
|
160
|
+
|
|
161
|
+
@Bean
|
|
162
|
+
public Jackson2ObjectMapperBuilderCustomizer customizer() {
|
|
163
|
+
return builder -> {
|
|
164
|
+
// LocalDateTime 格式化
|
|
165
|
+
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
166
|
+
builder.serializers(new LocalDateTimeSerializer(
|
|
167
|
+
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
|
168
|
+
builder.deserializers(new LocalDateTimeDeserializer(
|
|
169
|
+
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
|
170
|
+
|
|
171
|
+
// 大数字精度保护
|
|
172
|
+
SimpleModule module = new SimpleModule();
|
|
173
|
+
module.addSerializer(Long.class, new BigNumberSerializer());
|
|
174
|
+
module.addSerializer(Long.TYPE, new BigNumberSerializer());
|
|
175
|
+
module.addSerializer(BigInteger.class, new BigNumberSerializer());
|
|
176
|
+
module.addSerializer(BigDecimal.class, ToStringSerializer.instance);
|
|
177
|
+
builder.modules(module);
|
|
178
|
+
};
|
|
179
|
+
}
|
|
136
180
|
}
|
|
137
181
|
```
|
|
138
182
|
|
|
139
|
-
**JsonType 枚举**:
|
|
140
|
-
|
|
141
|
-
| 值 | 说明 | 示例 |
|
|
142
|
-
|----|------|------|
|
|
143
|
-
| `ANY` | 对象或数组都可以(默认) | `{}` 或 `[]` |
|
|
144
|
-
| `OBJECT` | 必须是 JSON 对象 | `{"a":1}` |
|
|
145
|
-
| `ARRAY` | 必须是 JSON 数组 | `[1,2,3]` |
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Jackson 自动配置
|
|
150
|
-
|
|
151
|
-
配置类:`org.dromara.common.json.config.JacksonConfig`
|
|
152
|
-
|
|
153
183
|
### 大数字处理(BigNumberSerializer)
|
|
154
184
|
|
|
155
185
|
**问题**:JavaScript 最大安全整数为 `2^53 - 1`(9007199254740991),超出范围会丢失精度。
|
|
@@ -157,11 +187,11 @@ public class ConfigBo {
|
|
|
157
187
|
**解决方案**:自动将超出 JS 安全范围的数字序列化为字符串。
|
|
158
188
|
|
|
159
189
|
```java
|
|
160
|
-
// 安全范围内
|
|
190
|
+
// 安全范围内 -> 保持数字
|
|
161
191
|
Long id = 123456L;
|
|
162
192
|
// 序列化结果:{"id": 123456}
|
|
163
193
|
|
|
164
|
-
// 超出安全范围
|
|
194
|
+
// 超出安全范围 -> 转为字符串
|
|
165
195
|
Long id = 9007199254740992L;
|
|
166
196
|
// 序列化结果:{"id": "9007199254740992"}
|
|
167
197
|
|
|
@@ -189,20 +219,6 @@ BigDecimal amount = new BigDecimal("123.45");
|
|
|
189
219
|
LocalDateTime now = LocalDateTime.now();
|
|
190
220
|
String json = JsonUtils.toJsonString(now);
|
|
191
221
|
// 输出:"2026-02-06 14:30:45"
|
|
192
|
-
|
|
193
|
-
LocalDateTime parsed = JsonUtils.parseObject("\"2026-02-06 14:30:45\"", LocalDateTime.class);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Date 自动解析(CustomDateDeserializer)
|
|
197
|
-
|
|
198
|
-
使用 Hutool 的 `DateUtil.parse()` 自动识别多种日期格式:
|
|
199
|
-
|
|
200
|
-
```java
|
|
201
|
-
// 支持的格式(自动识别)
|
|
202
|
-
Date d1 = JsonUtils.parseObject("\"2026-02-06 14:30:45\"", Date.class);
|
|
203
|
-
Date d2 = JsonUtils.parseObject("\"2026-02-06\"", Date.class);
|
|
204
|
-
Date d3 = JsonUtils.parseObject("\"2026/02/06 14:30:45\"", Date.class);
|
|
205
|
-
Date d4 = JsonUtils.parseObject("\"20260206143045\"", Date.class);
|
|
206
222
|
```
|
|
207
223
|
|
|
208
224
|
---
|
|
@@ -214,17 +230,17 @@ Date d4 = JsonUtils.parseObject("\"20260206143045\"", Date.class);
|
|
|
214
230
|
```java
|
|
215
231
|
@Service
|
|
216
232
|
@RequiredArgsConstructor
|
|
217
|
-
public class ConfigServiceImpl
|
|
233
|
+
public class ConfigServiceImpl {
|
|
218
234
|
|
|
219
|
-
private final ConfigMapper
|
|
235
|
+
private final ConfigMapper configMapper;
|
|
220
236
|
|
|
221
237
|
/**
|
|
222
238
|
* 获取配置为对象
|
|
223
239
|
*/
|
|
224
240
|
public <T> T getConfig(String configKey, Class<T> clazz) {
|
|
225
|
-
|
|
226
|
-
Wrappers.<
|
|
227
|
-
.eq(
|
|
241
|
+
Config config = configMapper.selectOne(
|
|
242
|
+
Wrappers.<Config>lambdaQuery()
|
|
243
|
+
.eq(Config::getConfigKey, configKey));
|
|
228
244
|
if (config == null) {
|
|
229
245
|
return null;
|
|
230
246
|
}
|
|
@@ -235,10 +251,10 @@ public class ConfigServiceImpl implements IConfigService {
|
|
|
235
251
|
* 保存配置
|
|
236
252
|
*/
|
|
237
253
|
public void saveConfig(String configKey, Object value) {
|
|
238
|
-
|
|
254
|
+
Config config = new Config();
|
|
239
255
|
config.setConfigKey(configKey);
|
|
240
256
|
config.setConfigValue(JsonUtils.toJsonString(value));
|
|
241
|
-
|
|
257
|
+
configMapper.insert(config);
|
|
242
258
|
}
|
|
243
259
|
|
|
244
260
|
/**
|
|
@@ -246,7 +262,7 @@ public class ConfigServiceImpl implements IConfigService {
|
|
|
246
262
|
*/
|
|
247
263
|
public void importData(String jsonData) {
|
|
248
264
|
if (!JsonUtils.isJsonArray(jsonData)) {
|
|
249
|
-
throw new
|
|
265
|
+
throw new [你的异常类]("数据格式不正确,应为 JSON 数组");
|
|
250
266
|
}
|
|
251
267
|
List<DataBo> list = JsonUtils.parseArray(jsonData, DataBo.class);
|
|
252
268
|
// 处理数据...
|
|
@@ -254,25 +270,6 @@ public class ConfigServiceImpl implements IConfigService {
|
|
|
254
270
|
}
|
|
255
271
|
```
|
|
256
272
|
|
|
257
|
-
### BO 中使用 JSON 校验
|
|
258
|
-
|
|
259
|
-
```java
|
|
260
|
-
@Data
|
|
261
|
-
@AutoMapper(target = SysConfig.class, reverseConvertGenerate = false)
|
|
262
|
-
public class SysConfigBo extends BaseEntity {
|
|
263
|
-
|
|
264
|
-
@NotNull(message = "ID不能为空", groups = EditGroup.class)
|
|
265
|
-
private Long id;
|
|
266
|
-
|
|
267
|
-
@NotBlank(message = "配置键不能为空")
|
|
268
|
-
private String configKey;
|
|
269
|
-
|
|
270
|
-
@NotBlank(message = "配置值不能为空")
|
|
271
|
-
@JsonPattern(type = JsonType.OBJECT, message = "配置值必须是有效的 JSON 对象")
|
|
272
|
-
private String configValue;
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
273
|
---
|
|
277
274
|
|
|
278
275
|
## 常见问题
|
|
@@ -280,12 +277,12 @@ public class SysConfigBo extends BaseEntity {
|
|
|
280
277
|
### 1. 什么时候用 parseObject vs parseArray?
|
|
281
278
|
|
|
282
279
|
```java
|
|
283
|
-
// JSON 对象
|
|
284
|
-
String json = "{\"name\":\"
|
|
280
|
+
// JSON 对象 -> parseObject
|
|
281
|
+
String json = "{\"name\":\"test\"}";
|
|
285
282
|
User user = JsonUtils.parseObject(json, User.class);
|
|
286
283
|
|
|
287
|
-
// JSON 数组
|
|
288
|
-
String json = "[{\"name\":\"
|
|
284
|
+
// JSON 数组 -> parseArray
|
|
285
|
+
String json = "[{\"name\":\"test1\"},{\"name\":\"test2\"}]";
|
|
289
286
|
List<User> users = JsonUtils.parseArray(json, User.class);
|
|
290
287
|
```
|
|
291
288
|
|
|
@@ -305,7 +302,6 @@ Map<String, User> map = JsonUtils.parseObject(json,
|
|
|
305
302
|
```java
|
|
306
303
|
// toJsonString
|
|
307
304
|
JsonUtils.toJsonString(null); // 返回 null
|
|
308
|
-
JsonUtils.toJsonString(user); // 返回 JSON 字符串
|
|
309
305
|
|
|
310
306
|
// parseObject
|
|
311
307
|
JsonUtils.parseObject(null, User.class); // 返回 null
|
|
@@ -316,18 +312,6 @@ JsonUtils.parseArray(null, User.class); // 返回空 ArrayList
|
|
|
316
312
|
JsonUtils.parseArray("", User.class); // 返回空 ArrayList
|
|
317
313
|
```
|
|
318
314
|
|
|
319
|
-
### 4. 如何在解析前验证 JSON?
|
|
320
|
-
|
|
321
|
-
```java
|
|
322
|
-
public void processData(String data) {
|
|
323
|
-
// 先验证再解析
|
|
324
|
-
if (!JsonUtils.isJsonArray(data)) {
|
|
325
|
-
throw new ServiceException("数据格式不正确");
|
|
326
|
-
}
|
|
327
|
-
List<User> users = JsonUtils.parseArray(data, User.class);
|
|
328
|
-
}
|
|
329
|
-
```
|
|
330
|
-
|
|
331
315
|
---
|
|
332
316
|
|
|
333
317
|
## 禁止事项
|
|
@@ -337,7 +321,7 @@ public void processData(String data) {
|
|
|
337
321
|
ObjectMapper mapper = new ObjectMapper();
|
|
338
322
|
String json = mapper.writeValueAsString(user);
|
|
339
323
|
|
|
340
|
-
// ✅
|
|
324
|
+
// ✅ 正确:使用项目统一的 JsonUtils
|
|
341
325
|
String json = JsonUtils.toJsonString(user);
|
|
342
326
|
|
|
343
327
|
// ❌ 禁止:不验证直接解析(可能报错)
|
|
@@ -291,7 +291,83 @@ GROUP BY d.wallet_id
|
|
|
291
291
|
|
|
292
292
|
---
|
|
293
293
|
|
|
294
|
-
##
|
|
294
|
+
## 九、MySQL only_full_group_by 规范(必须遵守)
|
|
295
|
+
|
|
296
|
+
> 生产环境 MySQL 开启了 `sql_mode=only_full_group_by`,所有报表 SQL 必须满足此规则,否则报 `BadSqlGrammarException`。
|
|
297
|
+
|
|
298
|
+
### 核心规则
|
|
299
|
+
|
|
300
|
+
**SELECT 中所有非聚合字段,必须出现在 GROUP BY 中,且表达式必须完全一致。**
|
|
301
|
+
|
|
302
|
+
### 常见错误:GROUP BY 表达式与 SELECT 不一致
|
|
303
|
+
|
|
304
|
+
```sql
|
|
305
|
+
-- ❌ 错误:SELECT 用 DATE_FORMAT,GROUP BY 用 DATE
|
|
306
|
+
SELECT
|
|
307
|
+
DATE_FORMAT(atr.trade_time, '%Y-%m-%d') AS statisticDate,
|
|
308
|
+
SUM(atr.amount) AS totalAmount
|
|
309
|
+
FROM acc_trade atr
|
|
310
|
+
GROUP BY DATE(atr.trade_time) -- ❌ 表达式不同,触发 only_full_group_by 报错
|
|
311
|
+
ORDER BY DATE(atr.trade_time) ASC
|
|
312
|
+
|
|
313
|
+
-- ✅ 正确:GROUP BY 与 SELECT 使用完全相同的表达式
|
|
314
|
+
SELECT
|
|
315
|
+
DATE_FORMAT(atr.trade_time, '%Y-%m-%d') AS statisticDate,
|
|
316
|
+
SUM(atr.amount) AS totalAmount
|
|
317
|
+
FROM acc_trade atr
|
|
318
|
+
GROUP BY DATE_FORMAT(atr.trade_time, '%Y-%m-%d') -- ✅ 与 SELECT 一致
|
|
319
|
+
ORDER BY DATE_FORMAT(atr.trade_time, '%Y-%m-%d') ASC
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 常见错误:SELECT 包含非聚合字段未加入 GROUP BY
|
|
323
|
+
|
|
324
|
+
```sql
|
|
325
|
+
-- ❌ 错误:canteen_name 未在 GROUP BY 中
|
|
326
|
+
SELECT
|
|
327
|
+
DATE(pay_time) AS orderDate,
|
|
328
|
+
canteen_name, -- ❌ 非聚合字段,未在 GROUP BY
|
|
329
|
+
SUM(real_amount) AS netAmount
|
|
330
|
+
FROM report_order_info
|
|
331
|
+
GROUP BY DATE(pay_time), canteen_id
|
|
332
|
+
|
|
333
|
+
-- ✅ 正确:所有非聚合字段都加入 GROUP BY
|
|
334
|
+
SELECT
|
|
335
|
+
DATE(pay_time) AS orderDate,
|
|
336
|
+
canteen_name,
|
|
337
|
+
SUM(real_amount) AS netAmount
|
|
338
|
+
FROM report_order_info
|
|
339
|
+
GROUP BY DATE(pay_time), canteen_id, canteen_name -- ✅ 包含 canteen_name
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### fix SQL 中的正确写法
|
|
343
|
+
|
|
344
|
+
```xml
|
|
345
|
+
<insert id="initFix">
|
|
346
|
+
INSERT INTO report_sum_xxx (id, statistic_date, canteen_id, canteen_name,
|
|
347
|
+
order_count, consume_amount, net_amount)
|
|
348
|
+
SELECT
|
|
349
|
+
#{id},
|
|
350
|
+
DATE(pay_time), -- SELECT 用 DATE(pay_time)
|
|
351
|
+
canteen_id,
|
|
352
|
+
canteen_name,
|
|
353
|
+
COUNT(*),
|
|
354
|
+
SUM(CASE WHEN consume_type = 1 THEN real_amount ELSE 0 END),
|
|
355
|
+
SUM(real_amount)
|
|
356
|
+
FROM report_order_info
|
|
357
|
+
WHERE pay_time BETWEEN #{startTime} AND #{endTime}
|
|
358
|
+
GROUP BY DATE(pay_time), canteen_id, canteen_name -- ✅ 与 SELECT 完全一致
|
|
359
|
+
</insert>
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### 开发检查项
|
|
363
|
+
|
|
364
|
+
- [ ] SELECT 每个非聚合字段,在 GROUP BY 中都有对应
|
|
365
|
+
- [ ] GROUP BY 的表达式与 SELECT 中的**完全一致**(`DATE_FORMAT(x, 'Y-m-d')` ≠ `DATE(x)`)
|
|
366
|
+
- [ ] ORDER BY 也使用相同表达式(保持一致)
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## 十、开发检查清单
|
|
295
371
|
|
|
296
372
|
### 建表
|
|
297
373
|
- [ ] 分组维度字段 + 金额汇总字段 + 审计字段(crby/crtime/upby/uptime/del_flag),无 tenant_id
|
|
@@ -308,9 +384,13 @@ GROUP BY d.wallet_id
|
|
|
308
384
|
### 查询接口
|
|
309
385
|
- [ ] 分页 + 合计行(PageVO + TotalVO)+ 三并行 CompletableFuture
|
|
310
386
|
|
|
387
|
+
### SQL 合规(only_full_group_by)
|
|
388
|
+
- [ ] SELECT 非聚合字段全部在 GROUP BY 中
|
|
389
|
+
- [ ] GROUP BY 表达式与 SELECT 完全一致
|
|
390
|
+
|
|
311
391
|
---
|
|
312
392
|
|
|
313
|
-
##
|
|
393
|
+
## 十一、关键代码位置
|
|
314
394
|
|
|
315
395
|
| 类型 | 路径 |
|
|
316
396
|
|------|------|
|
|
@@ -286,7 +286,69 @@ public ReportBaseTotalVO<XxxVO> pageSummary(XxxParam param) {
|
|
|
286
286
|
|
|
287
287
|
---
|
|
288
288
|
|
|
289
|
-
##
|
|
289
|
+
## 九、MySQL only_full_group_by 规范(必须遵守)
|
|
290
|
+
|
|
291
|
+
> MySQL 默认开启 `sql_mode=ONLY_FULL_GROUP_BY`,SELECT 中所有非聚合列必须出现在 GROUP BY 中,且 GROUP BY 表达式必须与 SELECT 表达式**完全一致**。
|
|
292
|
+
|
|
293
|
+
### 核心规则
|
|
294
|
+
|
|
295
|
+
**SELECT 的表达式 == GROUP BY 的表达式**(字符级别完全一致)
|
|
296
|
+
|
|
297
|
+
### ❌ 错误示例(GROUP BY 与 SELECT 不一致)
|
|
298
|
+
|
|
299
|
+
```xml
|
|
300
|
+
<!-- 报错:Expression #1 of SELECT list is not in GROUP BY clause -->
|
|
301
|
+
SELECT
|
|
302
|
+
DATE_FORMAT(roi.consume_time, '%Y-%m-%d') AS statisticDate,
|
|
303
|
+
SUM(roi.real_amount) AS totalAmount
|
|
304
|
+
FROM report_order_info roi
|
|
305
|
+
GROUP BY DATE(roi.consume_time) <!-- ❌ DATE() ≠ DATE_FORMAT(..., '%Y-%m-%d') -->
|
|
306
|
+
ORDER BY DATE(roi.consume_time)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### ✅ 正确示例(GROUP BY 与 SELECT 完全一致)
|
|
310
|
+
|
|
311
|
+
```xml
|
|
312
|
+
SELECT
|
|
313
|
+
DATE_FORMAT(roi.consume_time, '%Y-%m-%d') AS statisticDate,
|
|
314
|
+
SUM(roi.real_amount) AS totalAmount
|
|
315
|
+
FROM report_order_info roi
|
|
316
|
+
GROUP BY DATE_FORMAT(roi.consume_time, '%Y-%m-%d') <!-- ✅ 与 SELECT 完全一致 -->
|
|
317
|
+
ORDER BY DATE_FORMAT(roi.consume_time, '%Y-%m-%d') <!-- ✅ ORDER BY 也保持一致 -->
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### ❌ 错误示例(SELECT 含非聚合列未加入 GROUP BY)
|
|
321
|
+
|
|
322
|
+
```xml
|
|
323
|
+
SELECT
|
|
324
|
+
roi.canteen_id,
|
|
325
|
+
roi.canteen_name, <!-- ❌ 非聚合列未在 GROUP BY 中 -->
|
|
326
|
+
SUM(roi.real_amount) AS totalAmount
|
|
327
|
+
FROM report_order_info roi
|
|
328
|
+
GROUP BY roi.canteen_id
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### ✅ 正确示例(所有非聚合列都在 GROUP BY 中)
|
|
332
|
+
|
|
333
|
+
```xml
|
|
334
|
+
SELECT
|
|
335
|
+
roi.canteen_id,
|
|
336
|
+
roi.canteen_name,
|
|
337
|
+
SUM(roi.real_amount) AS totalAmount
|
|
338
|
+
FROM report_order_info roi
|
|
339
|
+
GROUP BY roi.canteen_id, roi.canteen_name <!-- ✅ 所有非聚合列都在 GROUP BY -->
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 检查清单
|
|
343
|
+
|
|
344
|
+
- [ ] SELECT 中按日期分组时使用 `DATE_FORMAT(col, '%Y-%m-%d')`,**不要用 `DATE()`**
|
|
345
|
+
- [ ] GROUP BY 表达式与 SELECT 中对应列**逐字相同**(复制粘贴而非重写)
|
|
346
|
+
- [ ] ORDER BY 中同样使用与 GROUP BY 一致的表达式
|
|
347
|
+
- [ ] SELECT 中所有非聚合列(无 SUM/COUNT/AVG/MAX/MIN 包裹)都出现在 GROUP BY 中
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 十、开发检查清单
|
|
290
352
|
|
|
291
353
|
### 建表
|
|
292
354
|
- [ ] 分组维度 + 金额汇总 + 审计字段(crby/crtime/upby/uptime/del_flag),无 tenant_id
|
|
@@ -302,10 +364,11 @@ public ReportBaseTotalVO<XxxVO> pageSummary(XxxParam param) {
|
|
|
302
364
|
|
|
303
365
|
### 查询
|
|
304
366
|
- [ ] ReportBaseTotalVO + CompletableFuture 并行 + MgrUserAuthPO 权限
|
|
367
|
+
- [ ] GROUP BY / ORDER BY 表达式与 SELECT 完全一致(only_full_group_by)
|
|
305
368
|
|
|
306
369
|
---
|
|
307
370
|
|
|
308
|
-
##
|
|
371
|
+
## 十一、关键代码位置
|
|
309
372
|
|
|
310
373
|
> 路径前缀均为 `core-report/.../statistics/`
|
|
311
374
|
|