Compare commits

...

218 Commits

Author SHA1 Message Date
oyo
e6be173673 更新 knowledge.md 2025-10-29 16:35:27 +08:00
oyo
510309832f 更新 knowledge.md 2025-10-29 16:16:04 +08:00
oyo
d15bb5e10f 更新 knowledge.md 2025-10-29 16:14:55 +08:00
oyo
06f315a654 更新 knowledge.md 2025-10-29 16:01:30 +08:00
oyo
245551961d 更新 knowledge.md 2025-10-29 15:51:16 +08:00
oyo
636ae4d415 更新 knowledge.md 2025-10-29 15:40:11 +08:00
oyo
3a2f856eff 更新 knowledge.md 2025-10-29 15:29:49 +08:00
oyo
eb5d055e14 更新 knowledge.md 2025-10-29 15:26:22 +08:00
oyo
5771ffe388 更新 knowledge.md 2025-10-29 15:15:09 +08:00
oyo
d59e59c17c 更新 knowledge.md 2025-10-29 13:54:23 +08:00
oyo
4b2bba2ae9 更新 knowledge.md 2025-10-27 17:01:19 +08:00
oyo
bebfcfa3f1 更新 knowledge.md 2025-10-27 15:20:12 +08:00
oyo
41489ba150 更新 knowledge.md 2025-10-27 15:16:49 +08:00
oyo
6c8032e25c 更新 knowledge.md 2025-10-27 15:03:37 +08:00
oyo
9edce3e80c 更新 knowledge.md 2025-10-27 14:58:00 +08:00
oyo
29570e7156 更新 knowledge.md 2025-10-27 11:04:22 +08:00
oyo
4be514aff0 更新 knowledge.md 2025-10-23 14:11:54 +08:00
oyo
bad7025b00 更新 knowledge.md 2025-10-22 19:27:53 +08:00
oyo
a3947239ad 更新 knowledge.md 2025-10-22 19:15:24 +08:00
oyo
f1ec30a7dd 更新 knowledge.md 2025-10-22 18:46:01 +08:00
oyo
3699f4833c 更新 knowledge.md 2025-10-22 17:21:58 +08:00
oyo
8ecdfbab6e 更新 knowledge.md
去掉 "可以作为静态自定义字段逻辑编写位置(复用性好,被其他convert方法调用,但处于底层,不建议在内部进行数据库查询等操作,只建议做静态计算)"
2025-10-22 15:44:56 +08:00
oyo
57c4fcc6bc 更新 knowledge.md
放开自定义字段的实现位置
2025-10-22 15:03:30 +08:00
oyo
a5e38099c6 更新 knowledge.md 2025-10-21 15:33:53 +08:00
oyo
854275fbda 更新 knowledge.md 2025-10-21 15:26:08 +08:00
oyo
2794f1e10e 更新 knowledge.md 2025-10-20 19:39:06 +08:00
oyo
50898d781e 更新 knowledge.md 2025-10-20 19:36:55 +08:00
oyo
19efc38e5a 更新 knowledge.md 2025-10-20 19:29:36 +08:00
oyo
9bc4cbf799 更新 knowledge.md 2025-10-20 19:29:27 +08:00
ycl
49a8165aff 更新 knowledge.md 2025-10-20 19:14:11 +08:00
oyo
ba9318c2ba 更新 knowledge.md 2025-10-20 14:01:45 +08:00
oyo
c50bb46f20 更新 knowledge.md 2025-10-19 17:57:24 +08:00
ycl
9042527142 更新 knowledge.md 2025-10-15 18:43:49 +08:00
ycl
1bf734f700 更新 knowledge.md 2025-10-15 18:20:07 +08:00
ycl
49ca7a2e72 更新 knowledge.md 2025-10-15 11:30:32 +08:00
ycl
44f7ffda1d 更新 knowledge.md 2025-10-15 11:22:54 +08:00
ycl
ec56219b83 更新 knowledge.md 2025-10-15 10:53:12 +08:00
ycl
4f3ca7936b 更新 knowledge.md 2025-10-14 11:21:48 +08:00
oyo
44cc048899 更新 knowledge.md 2025-10-13 11:13:35 +08:00
oyo
3c00525d67 更新 knowledge.md 2025-09-29 15:14:46 +08:00
ycl
e44351a362 更新 knowledge.md 2025-09-25 15:53:00 +08:00
ycl
51c2b14694 更新 knowledge.md 2025-09-25 15:07:49 +08:00
ycl
7eac1bbeb6 更新 knowledge.md 2025-09-25 15:05:19 +08:00
oyo
546e45aa97 更新 knowledge.md 2025-09-25 10:04:26 +08:00
oyo
7da8e3eb34 更新 knowledge.md 2025-09-23 10:59:37 +08:00
oyo
2384649928 更新 knowledge.md 2025-09-22 10:41:21 +08:00
oyo
2e2cb599cb 更新 knowledge.md 2025-09-19 18:10:12 +08:00
oyo
00cf12ea3c 删除 knowledge-design.md 2025-09-19 18:06:42 +08:00
oyo
b870568483 更新 knowledge.md 2025-09-18 11:52:37 +08:00
ycl
ce7c0ad997 更新 knowledge.md 2025-09-18 10:11:42 +08:00
oyo
7e07894422 更新 knowledge-brief.md 2025-09-12 17:04:24 +08:00
oyo
c3aaa9d2c0 更新 knowledge-brief.md 2025-09-12 16:26:00 +08:00
oyo
73c82a4f97 更新 knowledge.md 2025-09-10 15:37:08 +08:00
ycl
dcff8d4701 更新 knowledge-brief.md 2025-09-07 15:51:18 +08:00
ycl
040a1999e3 更新 knowledge.md 2025-09-07 14:33:01 +08:00
ycl
636cb8a226 更新 knowledge.md 2025-09-07 14:30:26 +08:00
ycl
b8255ca3a0 更新 knowledge.md 2025-09-04 16:43:02 +08:00
ycl
e839e1e8a0 更新 knowledge.md 2025-09-04 11:56:02 +08:00
ycl
5d89a2907b 更新 knowledge.md 2025-09-04 11:53:34 +08:00
ycl
db667aefda 更新 knowledge.md 2025-09-04 11:23:07 +08:00
ycl
25b04583e8 更新 knowledge.md 2025-09-04 11:19:26 +08:00
ycl
506b07d1ac 更新 knowledge-brief.md 2025-09-03 19:18:13 +08:00
ycl
555f1767a9 更新 knowledge.md 2025-09-03 19:16:54 +08:00
ycl
f8d5a68fbc 更新 knowledge.md 2025-09-03 19:02:14 +08:00
oyo
8dd43e784f 更新 knowledge.md 2025-09-03 18:50:12 +08:00
oyo
eb2bb0b62f 更新 knowledge.md 2025-09-03 10:07:07 +08:00
oyo
f945ec49bb 更新 knowledge.md 2025-09-01 20:09:51 +08:00
oyo
6026fa7774 更新 knowledge.md 2025-09-01 17:03:59 +08:00
oyo
b049e69454 更新 knowledge.md 2025-08-31 16:02:26 +08:00
oyo
e9a6bc4d7e 更新 knowledge-design.md 2025-08-28 15:22:43 +08:00
oyo
b54b3149a2 更新 knowledge.md 2025-08-27 15:57:52 +08:00
ycl
e448e3a9e1 更新 knowledge.md 2025-08-25 16:07:01 +08:00
dayjoy
f86f1b74e4 feat: 知识库前缀 2025-08-21 11:11:27 +08:00
oyo
23706f21b2 更新 knowledge.md 2025-08-21 10:18:10 +08:00
oyo
b4569dffb0 添加 knowledge-design.md 2025-08-20 13:57:42 +08:00
ycl
f2764cefc9 更新 knowledge.md 2025-08-20 11:57:23 +08:00
dayjoy
e4225795f9 fix: 项目结构 2025-08-20 11:46:16 +08:00
dayjoy
73803542ea fix: 代码格式问题 2025-08-20 11:37:57 +08:00
dayjoy
a3afd54f97 feat: 简化文字 2025-08-20 11:25:21 +08:00
dayjoy
8d028d116c feat: 简化技术描述语言(3~4) 2025-08-20 11:20:58 +08:00
dayjoy
47199b895c feat: 简化技术描述语言(2.12~2.16) 2025-08-20 11:18:10 +08:00
dayjoy
f253b4f628 feat: 简化技术描述语言(2.10~2.11) 2025-08-20 11:02:31 +08:00
dayjoy
1dcb2ce6a0 feat: 简化技术描述语言(2.9) 2025-08-20 10:44:36 +08:00
dayjoy
11eb3f3b37 feat: 简化技术描述语言(2.8) 2025-08-20 10:36:53 +08:00
dayjoy
9d0ccd1372 feat: 简化技术描述语言(2.7) 2025-08-20 10:28:34 +08:00
dayjoy
bd1cf2a5a4 feat: 简化技术描述语言(1~2.6) 2025-08-19 18:51:41 +08:00
dayjoy
10af7636a9 feat: 文件改名 2025-08-19 16:45:57 +08:00
dayjoy
ea16681047 feat: 文件改名 2025-08-19 16:44:22 +08:00
dayjoy
132e666a65 feat: 更新TOCO平台简介 2025-08-18 16:43:31 +08:00
dayjoy
5cb4d8c451 feat: 添加TOCO平台简介 2025-08-18 16:40:17 +08:00
oyo
0337f669ea 更新 llms-full.txt 2025-08-17 14:10:46 +08:00
ycl
191ef8c1eb 更新 llms-full.txt 2025-08-15 18:08:07 +08:00
ycl
341eae8c7b 更新 llms-full.txt 2025-08-15 18:03:21 +08:00
ycl
73ccf32447 更新 llms-full.txt 2025-08-14 11:07:23 +08:00
oyo
337ba0ea99 更新 llms-full.txt 2025-08-14 10:45:02 +08:00
ycl
66568700de 更新 llms-full.txt 2025-08-12 14:48:49 +08:00
oyo
de30f67e50 更新 llms-full.txt 2025-08-11 18:19:46 +08:00
oyo
8dddf1b5c0 更新 llms-full.txt 2025-08-11 17:41:13 +08:00
oyo
627fd79c46 更新 llms-full.txt 2025-08-11 12:13:28 +08:00
ycl
be247c12cf 更新 llms-full.txt 2025-08-10 16:34:51 +08:00
ycl
cae9ef9ca5 更新 llms-full.txt 2025-08-10 15:16:29 +08:00
ycl
02533b17e2 更新 llms-full.txt 2025-08-10 11:15:03 +08:00
oyo
d99985b72e 更新 llms-full.txt 2025-08-08 17:40:19 +08:00
oyo
d77d0366da 更新 llms-full.txt 2025-08-08 17:38:48 +08:00
oyo
4143c28560 更新 llms-full.txt 2025-08-08 12:10:23 +08:00
oyo
b72d9dd628 更新 llms-full.txt 2025-08-08 11:52:48 +08:00
oyo
aa8b21bb5f 更新 llms-full.txt 2025-08-08 11:48:34 +08:00
oyo
35fc099370 更新 llms-full.txt 2025-08-07 12:32:34 +08:00
oyo
b0d1c9e402 更新 llms-full.txt 2025-08-07 12:26:45 +08:00
ycl
3ab49979d3 更新 llms-full.txt 2025-08-07 12:16:49 +08:00
oyo
c6fd6daed5 更新 llms-full.txt 2025-08-07 12:05:30 +08:00
ycl
d59871ad21 更新 llms-full.txt 2025-08-07 11:29:28 +08:00
oyo
29666b7b9b 更新 llms-full.txt 2025-08-07 11:26:23 +08:00
oyo
979ee3a745 更新 llms-full.txt 2025-08-06 14:25:33 +08:00
oyo
207e18835a 更新 llms-full.txt 2025-08-06 11:28:03 +08:00
oyo
eac3a4fb93 更新 llms-full.txt 2025-08-05 14:56:51 +08:00
oyo
0cfeabcb16 更新 llms-full.txt 2025-08-05 14:37:26 +08:00
oyo
7ae8d80e31 更新 llms-full.txt 2025-08-05 14:05:45 +08:00
ycl
a139300b9e 更新 llms-full.txt 2025-08-05 12:05:20 +08:00
ycl
cdecfa028b 更新 llms-full.txt 2025-08-05 11:45:20 +08:00
oyo
3f81639b9b 更新 llms-full.txt 2025-08-05 10:11:04 +08:00
ycl
e36464eabc 更新 llms-full.txt 2025-08-01 18:30:31 +08:00
oyo
08760b6f57 更新 llms-full.txt 2025-08-01 16:53:33 +08:00
oyo
479548b334 更新 llms-full.txt 2025-07-31 10:22:29 +08:00
1b7022466d 更新 coding-llms-full.txt 2025-07-29 14:37:20 +08:00
oyo
9daa17519d 更新 llms-full.txt 2025-07-28 19:18:21 +08:00
oyo
5671a0d36e 更新 llms-full.txt 2025-07-28 19:17:52 +08:00
oyo
d025d0db49 更新 llms-full.txt 2025-07-28 18:26:03 +08:00
ycl
8916d2bdb0 更新 llms-full.txt 2025-07-28 14:51:41 +08:00
oyo
45ac3fd8ef 更新 llms-full.txt 2025-07-28 10:55:53 +08:00
oyo
5268e1f170 更新 llms-full.txt 2025-07-28 10:44:46 +08:00
oyo
ff58ff2fd7 更新 llms-full.txt 2025-07-27 16:00:14 +08:00
ycl
b75b4c9229 更新 llms-full.txt 2025-07-25 16:16:23 +08:00
ycl
120b7ee161 更新 llms-full.txt 2025-07-25 15:59:06 +08:00
ycl
2c18cb147c 更新 llms-full.txt 2025-07-25 10:16:43 +08:00
ycl
97083d3272 更新 llms-full.txt 2025-07-24 14:50:16 +08:00
ycl
b575f39854 更新 llms-full.txt 2025-07-23 10:52:03 +08:00
ycl
33662b2e33 更新 llms-full.txt 2025-07-23 10:17:23 +08:00
ycl
1246cf4ff7 更新 llms-full.txt 2025-07-23 10:14:12 +08:00
ycl
3569493428 更新 llms-full.txt 2025-07-23 09:58:30 +08:00
ycl
398ddd673f 更新 llms-full.txt 2025-07-22 16:54:24 +08:00
ycl
cff7c151d9 更新 llms-full.txt 2025-07-22 16:13:34 +08:00
ycl
0f9d1774e6 更新 llms-full.txt 2025-07-22 16:04:55 +08:00
ycl
2e396f0100 更新 llms-full.txt 2025-07-22 15:53:22 +08:00
ycl
8e6968c27c 更新 llms-full.txt 2025-07-22 15:24:02 +08:00
ycl
e90f882b9a 更新 llms-full.txt 2025-07-22 14:51:28 +08:00
c08274d900 Add coding-llms-full.txt 2025-07-22 13:48:08 +08:00
ycl
1dc3af15f4 更新 llms-full.txt 2025-07-21 10:15:27 +08:00
ycl
952c8d0b64 更新 llms-full.txt 2025-07-21 10:07:24 +08:00
oyo
34c1c48f14 更新 llms-full.txt 2025-07-20 15:53:28 +08:00
ycl
99581be3cb 更新 llms-full.txt 2025-07-17 14:07:21 +08:00
ycl
18f7ad590e 更新 llms-full.txt 2025-07-17 14:01:37 +08:00
ycl
59b601fede 更新 llms-full.txt 2025-07-17 12:18:12 +08:00
ycl
ded0c82d6f 更新 llms-full.txt 2025-07-17 11:00:51 +08:00
oyo
939726f0fd 更新 llms-full.txt 2025-07-16 19:11:31 +08:00
oyo
7c9168318f 更新 llms-full.txt 2025-07-16 19:08:36 +08:00
oyo
662ebf1215 更新 llms-full.txt 2025-07-14 19:28:47 +08:00
oyo
512df24380 更新 llms-full.txt 2025-07-14 19:27:15 +08:00
ycl
f23ecb3f2f 更新 llms-full.txt 2025-07-14 19:03:22 +08:00
oyo
a6e460a05c 更新 llms-full.txt 2025-07-14 17:14:47 +08:00
ycl
39de528ba1 更新 llms-full.txt 2025-07-13 17:39:43 +08:00
oyo
02b6befd21 更新 llms-full.txt 2025-07-11 11:33:22 +08:00
oyo
996d9cceb9 更新 llms-full.txt 2025-07-11 11:24:31 +08:00
oyo
b8a7593a6a 更新 llms-full.txt 2025-07-10 19:15:48 +08:00
ycl
69c7ab9f36 更新 llms-full.txt 2025-07-04 16:11:38 +08:00
oyo
4bc07060f2 更新 llms-full.txt 2025-07-04 15:56:22 +08:00
a29f87d0a3 强调IgnoredException的引用路径 2025-07-04 15:53:49 +08:00
oyo
810d43314c 更新 llms-full.txt 2025-07-04 15:51:32 +08:00
ycl
d61c04064c 更新 llms-full.txt 2025-07-04 14:25:48 +08:00
ycl
6fe83d6d11 更新 llms-full.txt 2025-07-04 13:58:02 +08:00
oyo
a6ae76b458 更新 llms-full.txt 2025-07-04 11:25:23 +08:00
oyo
891caae79c 更新 llms-full.txt 2025-07-03 15:22:29 +08:00
ycl
0ec32c2239 更新 llms-full.txt 2025-07-02 18:48:49 +08:00
ycl
d4705d7717 更新 llms-full.txt 2025-07-02 18:45:52 +08:00
ycl
fba0efd2dc 更新 llms-full.txt 2025-07-02 15:47:19 +08:00
oyo
8a2f4ccb41 更新 llms-full.txt 2025-07-02 15:33:14 +08:00
oyo
02c5047071 更新 llms-full.txt 2025-07-02 15:21:49 +08:00
ycl
31dc91447d 更新 llms-full.txt 2025-07-02 15:07:32 +08:00
ycl
b60d6eca30 更新 llms-full.txt 2025-07-02 15:03:36 +08:00
ycl
cd88bd34d2 更新 llms-full.txt 2025-06-30 11:26:24 +08:00
ycl
a093b0f5d3 更新 llms-full.txt 2025-06-30 10:39:33 +08:00
ycl
f39b0b2125 更新 llms-full.txt 2025-06-29 17:24:56 +08:00
oyo
599df72e5f Merge pull request 'main' (#1) from main into release
Reviewed-on: #1
2025-06-27 15:15:53 +08:00
oyo
bcdd30e75b 更新 llms-full.txt 2025-06-26 15:33:23 +08:00
oyo
e8586dc4c6 更新 llms-full.txt 2025-06-26 15:23:08 +08:00
oyo
9cb389af91 更新 llms-full.txt 2025-06-26 14:40:29 +08:00
oyo
629053a5ad 更新 llms-full.txt 2025-06-26 10:26:08 +08:00
oyo
f4619a4025 更新 llms-full.txt 2025-06-26 10:12:20 +08:00
oyo
146456dd24 更新 llms-full.txt 2025-06-25 17:29:57 +08:00
oyo
7029aec700 更新 llms-full.txt 2025-06-25 17:00:41 +08:00
oyo
e4acc2d409 更新 llms-full.txt 2025-06-25 16:40:30 +08:00
oyo
1699cc611f 更新 llms-full.txt 2025-06-25 15:23:05 +08:00
oyo
417abbbae5 更新 llms-full.txt 2025-06-24 19:15:04 +08:00
ycl
2b88e4505b 更新 llms-full.txt 2025-06-24 18:09:29 +08:00
ycl
2cef00c3e2 更新 llms-full.txt 2025-06-24 15:41:46 +08:00
ycl
a1b7012976 更新 llms-full.txt 2025-06-24 15:20:46 +08:00
ycl
b81838fcd1 更新 llms-full.txt 2025-06-24 15:14:51 +08:00
ycl
c49d8ea7e1 更新 llms-full.txt 2025-06-24 15:08:31 +08:00
ycl
fd6bac08eb 更新 llms-full.txt 2025-06-24 15:03:00 +08:00
ycl
f8002cc0ed 更新 llms-full.txt 2025-06-24 14:44:34 +08:00
ycl
06df42e6e8 更新 llms-full.txt 2025-06-24 14:31:06 +08:00
ycl
e1bdd7f299 更新 llms-full.txt 2025-06-24 14:29:45 +08:00
ycl
b06e4b234e 更新 llms-full.txt 2025-06-24 14:21:31 +08:00
ycl
fd9b90d20e 更新 llms-full.txt 2025-06-24 14:19:44 +08:00
ycl
8f07812308 更新 llms-full.txt 2025-06-24 14:18:58 +08:00
ycl
067e693c17 更新 llms-full.txt 2025-06-24 14:17:01 +08:00
ycl
1180789b48 更新 llms-full.txt 2025-06-23 19:53:00 +08:00
ycl
b53845a9fc 更新 llms-full.txt 2025-06-23 16:01:21 +08:00
ycl
8e8f1ff237 更新 llms-full.txt 2025-06-23 15:47:16 +08:00
ycl
e568fe6848 更新 llms-full.txt 2025-06-23 15:45:03 +08:00
ycl
4badfd198a 更新 llms-full.txt 2025-06-22 17:41:59 +08:00
ycl
33b9144c06 更新 llms-full.txt 2025-06-22 16:58:06 +08:00
ycl
3cdc037fd9 更新 llms-full.txt 2025-06-22 14:59:22 +08:00
ycl
2f1c1c2498 更新 llms-full.txt 2025-06-22 11:08:39 +08:00
ycl
ca83cf1acc 更新 llms-full.txt 2025-06-22 10:59:17 +08:00
oyo
771679d7bc 更新 llms-full.txt 2025-06-20 13:52:02 +08:00
oyo
210ad0faed 更新 llms-full.txt 2025-06-19 16:52:57 +08:00
ycl
57f92ebfe9 更新 llms-full.txt 2025-06-19 16:07:18 +08:00
5 changed files with 2055 additions and 882 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/.idea

0
code-guidelines.md Normal file
View File

226
knowledge-brief.md Normal file
View File

@@ -0,0 +1,226 @@
# TOCO平台简介
## 平台概述
TOCO是一个基于DDD、分层设计、CQRS等理论的专业研发平台主要目标是提供软件设计能力设计结果可直接转换为标准格式的代码。平台覆盖从数据库到API的全链路能够显著提升开发设计和编程效率。
## 核心设计理念
TOCO采用严格的分层架构
- **entrance层**API控制器层
- **service层**:服务层,处理业务逻辑
- **manager层**管理层处理DTO相关逻辑
- **persist层**:持久化层,处理数据访问
- **common层**:公共层,存放枚举、工具类等
技术栈Java + SpringBoot + MyBatis-plus+ Hibernate
##平台能力边界说明:
TOCO的设计模型旨在规范系统结构、统一数据契约与接口形态自动生成约80%的基础代码框架如控制器签名、DTO转换、读写方案执行器等
然而,业务行为逻辑(如条件判断、动态路由、状态流转、异常处理、多源聚合、性能优化路径等)无法由设计自动推导或生成,必须由人工编码实现。
因此:
设计元素仅表达“系统能做什么”(接口定义、数据结构、依赖关系);
**代码实现才是“系统正在做什么”**的唯一真实来源;
设计与代码之间存在不可逾越的行为鸿沟——设计不记录实现细节,代码不反馈回设计;
任何对系统行为的分析、影响评估或变更决策,都必须同时考察结构层面的设计信息与行为层面的代码实现,二者缺一不可。
## 重要设计元素详解
### 1. 模块Module
- **作用**系统领域的具体细分映射为Java工程中的module
- **命名规则**:小写英文字母+下划线,如`meeting``user_detail`,全局唯一
- **代码结构**每个Module生成独立的Java Module采用entrance、service、manager、persist、common分层
### 2. 枚举Enum
- **作用**:表达常量值集合,可被其他模块使用
- **命名规则**:以`_enum`结尾,全局唯一
- **生成位置**`**.common.enums`包路径下
- **修改建议**:不建议修改
### 3. 值对象EO
- **作用**POJO对象结构可被其他模块使用
- **命名规则**:以`_eo`结尾,全局唯一
- **字段限制**只能为基本类型、EO、Enum类型
- **生成位置**`**.persist.eo`包路径下
### 4. 实体关系Entity
- **作用**:对应数据库表,定义实体间的外键依赖关系
- **生成产物**
- 结构定义类:`**.persist.dos`
- Mapper类`**.persist.mapper.mybatis`
- Dao接口`**.persist.mapper`
- Dao实现`**.persist.mapper`
### 5. 聚合对象BO
- **核心概念**:封装一组密切关联的实体,以聚合根为起点,按层级关系组装其他实体
- **重要特性**
- 提供数据操作入口和内存一致性视图
- 只能在单一模块中组合
- 一个实体只能属于一个聚合对象
- **生成位置**`**.manager.bo`包路径下
- **修改建议**建议修改BO中的`validateAggregate``valid`方法进行业务不变性校验
### 6. 数据传输对象DTO
- **核心概念**以某个Entity为基础通过外键关系关联多个Entity的数据结构
- **分类**
- **BaseDTO**每个Entity自动生成一个包含Entity全部字段
- **普通DTO**派生自BaseDTO可增加扩展字段或自定义字段
- **字段扩展方式**
- **正向替换**将外键字段替换为对应Entity的DTO对象
- **反向注入**在当前Entity中注入其他Entity的DTO对象或列表
- **预定义方法**TOCO自动为每个DTO生成基于唯一索引的RPC方法
- **生成产物**
- 结构定义:`**.manager.dto`
- Manager`**.manager`
- Converter`**.manager.converter`
### 7. 视图对象VO
- **作用**用于视图层与前端数据传输作为HTTP API返回值
- **派生关系**通常派生自BaseDTO或其他DTO
- **分类**
- **根VO**需要创建有uuid标识
- **子VO**自动创建附属于根VO
- **与DTO区别**VO更接近UI展示可裁剪冗余字段DTO更接近数据模型复用性强
- **转换方法**
- 基础转换:`convertTo${VoName}`
- 带数据拼装:`convertAndAssembleData`
### 8. 查询对象WO
- **作用**表达以某Entity为基础通过外键关系关联多个Entity的查询结构
- **用途**作为ReadPlan的查询上下文使用
### 9. 读方案ReadPlan
- **作用**描述如何基于查询对象从数据库获取DTO/VO列表数据
- **核心能力**
- 复杂查询条件组合
- 数据拼装和过滤
- 分页和排序
- **能力边界**
- 支持等值、模糊、范围、包含查询
- 支持列表属性过滤
- 不支持复杂统计和聚合计算
- **使用原则**根据主键或唯一索引查询时优先使用DTO预定义方法其他复杂查询使用读方案
- **生成产物**自动生成RPC方法和对应的QTO
### 10. 写方案WritePlan
- **重要限制**:一个写方案只能操作一个聚合内的表,无法跨聚合操作
- **操作类型**
- `CREATE`:创建单个实体
- `UPDATE`:更新单个实体
- `DELETE`:删除单个实体
- `CREATE_ON_DUPLICATE_UPDATE`:创建或更新单个实体
- `FULL_MERGE`:批量更新列表数据(全量替换)
- `PARTIAL_MERGE`:批量更新列表数据(部分更新)
- **生成产物**自动生成RPC方法和对应的BTO
### 11. 查询传输对象QTO
- **作用**:读方案的查询参数结构
- **使用场景**作为API参数禁止用作写参数
### 12. 业务变更传输对象BTO
- **作用**:写方案的参数结构
- **特点**:树形结构,最外层为聚合根
- **使用场景**作为API参数禁止用作查询参数
### 13. 服务层方法RPC
- **分类**
- **公开RPC**:可被其他模块订阅调用
- **非公开RPC**:只能被当前模块调用
- **创建方式**
- DTO创建后自动生成
- 读方案自动生成
- 写方案自动生成
- 手动创建自定义RPC
- **参数限制**只能为QTO、BTO、Enum、基本类型
- **返回值限制**只能为DTO、Enum、基本类型
- **存储特点**: TOCO只存储RPC的方法签名不存储执行逻辑。了解API内部具体实现需阅读对应代码
### 14. 应用程序接口API
- **作用**定义对外暴露的HTTP接口
- **URI规范**:一般为`/api/${moduleName}/xxx`格式
- **参数限制**只能为QTO、BTO、EO、Enum、基本类型
- **返回值限制**只能为VO、Enum、基本类型
- **分页处理**框架自动包装返回值code、message、data
- **存储特点**: TOCO只存储API的URI和方法签名不存储执行逻辑。了解API内部具体实现需阅读对应代码
### 15. 流程服务FunctionFlow
- **使用场景**
- API/RPC涉及超过3个写服务时必须使用
- 用户明确要求时使用
- **节点类型**
- 顺序节点:封装业务逻辑
- 条件节点:封装判断逻辑
- 选择节点:封装分支选择逻辑
- 开始节点:流程起点
- **设计原则**:以数据内聚为首要考虑,每个节点围绕核心写服务
16. 领域消息 DomainMessage
可以监听聚合对象实体的创建、删除、更新事件;通过事件驱动的方式实现异步解耦;也是一种跨模块通信的方式;消息驱动的一种实现;
17. 普通消息 (CommonMessage)
自定义字段,自持事务、延时特性;是对领域消息的补充
## 数据获取流程
### DTO获取流程
1. **主键/唯一索引查询**:使用预定义方法
2. **复杂查询条件**:使用读方案
### VO获取流程
1. **主键/唯一索引查询**预定义方法获取DTO → convert方法转换为VO
2. **复杂查询有对应DTO读方案**读方案获取DTO → convert方法转换为VO
3. **复杂查询无对应DTO读方案**直接使用VO读方案
## 接口设计最佳实践
### 参数类型选择优先级
1. **读场景**优先使用QTO
2. **写场景**优先使用BTO
3. **补充参数**基本类型、Enum、EO
### 返回值类型选择
1. **RPC返回值**DTO、Enum、基本类型
2. **API返回值**VO、Enum、基本类型
### 绝对禁止的用法
- DTO、VO不能作为参数类型
- QTO、BTO不能作为返回值类型
- Service层不能返回VO
- VO不能作为RPC返回值
## 代码修改指南
### 推荐修改的位置
1. **BO类**`validateAggregate``valid`方法中添加业务校验
2. **Converter类**:自定义字段的数据获取逻辑
3. **Service类**:业务逻辑实现
4. **API Controller**:接口实现逻辑
### 禁止修改的内容
1. 带有`@AutoGenerated(locked=true)`的类和方法
2. DTO、VO的结构定义
3. Manager类的系统生成方法
4. Mapper类的结构定义
## 并发控制最佳实践
在处理先读后更新的场景时,为避免并发引起的数据脏写:
1. **写方案中使用incr字段**
2. **BoService中添加校验**:如`if(userBo.getBalance() >= 0)`
3. **聚合校验**在BO的业务不变性校验中添加约束条件
## 项目结构导航
标准查找流程:
- **API查找**`modules/{模块名}/entrance/web/controller/`
- **DTO查找**`modules/{模块名}/manager/dto/`
- **Service查找**`modules/{模块名}/service/`
- **数据层查找**`modules/{模块名}/persist/`
## 重要注意事项
1. **跨模块调用**必须通过订阅RPC使用RpcAdapter进行调用
2. **变量命名**RpcAdapter注入时变量名必须是类名首字母小写
3. **自定义字段逻辑**必须在BaseConverter的Map转换方法中实现
4. **读写分离**读操作使用MyBatis-plus写操作使用Hibernate
5. **严格分层**:各层职责明确,不能越层调用

1828
knowledge.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,882 +0,0 @@
## TOCO知识库
### **1. TOCO 平台概览:**
- **1.1 平台简介:** TOCO是一款重视软件设计及核心代码自动生成的专业研发平台。其基于DDD、分层设计、CQRS等经典研发理论从数据库到API全部覆盖可显著提升开发设计和编程效率帮助开发团队实现更高的质量和生产力
- **1.2 核心价值/目标用户:** 从软件工程理论出发,提供软件设计能力,设计结果可直接转换为标准格式的代码,提升编码一致性及效率
- **1.3 主要特性概览:** 可视化设计、模型关联、多人协作、代码生成器等
### **2. TOCO 设计元素:**
#### **2.1 模块 (Module)**
- **定义与用途:** 在TOCO中我们将系统领域细分为具体的模块映射为Java工程中的module。这些模块代表了系统的叶子子域每个模块负责特定的功能。模块划分有助于系统的可维护性和可扩展性并能提高开发效率和代码质量
- **关键配置:** 名称(小写英文字母+下划线如meeting,user_detail,禁止加任何固定后缀),描述
- **与其他元素关系:** 下面的每种设计元素都属于一个模块
#### **2.2 枚举 (Enum)**
- **定义与用途:** Enum用来表达一些常量值的集合可被其他模块使用可被用来做为字段的类型
- **关键属性/配置:** 名称(以_enum结尾),枚举值列表(全大写字母+下划线)
#### **2.3 值对象 (Eo)**
- **定义与用途:** EO为一种POJO对象结构可被其他模块使用可被用来做为实体字段的类型
- **关键属性/配置:** 名称(以_eo结尾)字段列表。EO的字段类型只能为基本类型含List、EO、Enum其他类型不允许
#### **2.4 实体关系 (ER / Entity)**
- **定义与用途:** 实体及其关系。一个实体一般对应一个数据库表,关系为实体间的外键依赖关系
- **关键属性/配置:** 实体中包含名称、字段、字段类型、主键、索引等关系分为1:1和1:N关系
- **与其他元素关系:** 实体关系是聚合的基础也是DTO和VO的派生基础
#### **2.5 聚合对象 (BO/业务对象)**
- **定义与用途:** 在TOCO中聚合对象是对一组密切关联的实体的封装。聚合对象从单一实体开始这个实体我们称为聚合根通过实体间关系不断的顺序将其他实体按层级关系组装进这个聚合对象。聚合对象可以按实体表达为树形结构。聚合对象提供了这组实体的内存一致性视图提供数据操作入口。由于写操作的内聚性聚合对象只能在单一模块中组合而且一个实体只能属于一个对象。同样如果有实体不在任何一个聚合对象中TOCO将无法提供与之相关的写方法。
- **包含元素:** 聚合对象包括聚合根及其聚合下的其他子实体对象例如商品聚合ProductBO中商品基本信息实体是ProductBO的聚合根商品SKU实体、商品库存实体是ProductBO的子聚合对象。
- **关键配置:** 名称(${EntityName驼峰}BO结尾如StaffBO),聚合根实体,聚合子对象实体。每个聚合必须包含一个聚合根
- **与其他元素关系:** 聚合是写方案的基础
#### **2.6 数据传输对象 (DTO)**
- **定义与用途:** 在TOCO中DTO表达某个Entity为基本通过外键关系不断关联多个Entity的数据结构。DTO还隐式表达了数据的取数拼装这种拼装符合外键关系。往往被当做RPC的返回值、或读方案的返回值使用不建议把DTO作为入参。注意DTO不能作为HTTP API的返回值。DTO分为BaseDTO和普通DTOBaseDTO派生自Entity包含Entity的所有字段每个Entity有且仅有一个BaseDTO普通DTO派生自BaseDTO包含BaseDTO的所有字段且可以增加扩展字段或自定义字段
- **如何创建/生成:** 对于每个EntityTOCO会自动生成一个BaseDTO命名为${Entity名字}BaseDto如UserBaseDto该BaseDTO包含了Entity的全部字段。除了BaseDTO其他的DTO均需要手动以BaseDTO为根来创建。在TOCO中必须要先判断需要的DTO是否为BaseDTO如果是BaseDTO则可通过Entity名称获取BaseDTO如果不是BaseDTO则需要通过DTO要表达的信息来创建DTO会议及其议程信息。
- **关键配置:** 名称(BaseDTO以BaseDto结尾其他DTO以Dto结尾)、根Entity、字段列表。DTO中的字段分为三种a.继承Entity或BaseDTO的字段和Entity及BaseDTO的字段类型一样b.扩展字段含正向替换和反向注入字段类型为DTO或List<DTO>;c.自定义字段类型为基本类型、Eo、Enum、DTO类型。BaseDTO中一般包含Entity的全部字段,DTO中一般包含BaseDTO中的全部字段不进行字段裁剪可以根据外键关系扩展其他Entity(详见**字段扩展方式**)在明确无法扩展外部Entity的情况下可增加对应的自定义字段。
- **字段扩展方式:**TOCO定义了一个DTO组装方法适用于DTO通过外键关系替换/注入对应Entity的信息对象化表达有外键关系的Entity信息。只要存在外键关系且满足以下条件即可扩展a.对于正向替换当前实体存在指向其他实体的外键字段b.对于反向注入:其他实体存在指向当前实体的外键字段。
例如有两个Entity
```
MeetingRoom{ //会议室
Long id;// 会议室id,主键
String name;// 会议室名称
}
Meeting { //会议
Long id;// 会议id,主键
Long roomid; //占用的会议室id到MeetingRoom的外键n:1关系
Long backupRoomid; //备用的会议室id到MeetingRoom的外键n:1关系
String title; //会议标题
DateTime startTime //会议开始时间
DateTime endTime //会议结束时间
}
```
其中Meeting和MeetingRoom是n:1关系。即多个会议室会占用同一个会议室。
当组装对象以某Entity为根时那么首先它将拥有和该Entity一样的数据结构并将通过下面的“正向替换”“反向注入”的行为递归的将多个互相之间有外键关系的Entity的信息组装到该组装对象中。
定义“正向替换”这个行为,选定一个表,这张表存在到另外一张表的一个或多个外键。选择和需求相关的具体的外键属性,将该外键属性替换为另一张表为根的组装对象。这样就可以获取基于某些外键且包含另一张表更详细的属性数据。
例如需要会议和其占用会议室时将Meeting表中的roomid外键替换为以MeetingRoom为根的组装对象而backupRoomid对应的候选会议室具体信息和本需求无关不做任何替换。如下
```
MeetingWithRoomDto {
Long id;// 会议id
MeetingRoomDto room { //正向替换该会议用的会议室信息,是一个以会议室为根的对象
Long id; //会议室ID
String name;// 会议室名称
}
Long backupRoomid; // 不做变化
String title; //会议标题
DateTime startTime //会议开始时间
DateTime endTime //会议结束时间
}
```
又例如需要会议和其候选会议室时将Meeting表中的backupRoomid进行正向替换。
又例如需要会议且即需要其占用会议室也需要候选会议室时将Meeting表中的roomidbackupRoomid都进行正向替换。
同时TOCO还定义了“反向注入”这个行为选定一个表如果有另外的表到前表有外键选择和需求相关的具体的外键属性在选定表中增加一个以另外表为根的组合对象(当外键关系是1:1时)或者组合对象的列表(当外键关系是n:1时)。需求是“获取会议室和占用它的会议信息”需要选定MeetingRoom那么基于另外的表Meeting中存在字段roomid为到MeetingRoom的n:1关系外键。可以将List<MeetingBaseDto>反向注入到MeetingRoom中最终生成一个以Meeting为根的组装对象生成
```
MeetingRoomWithMeetingDto {
Long id;// 会议室id
String name;// 会议室名称
List<MeetingBaseDto> meetingList { //反向注入的用该会议室的会议信息,是以会议为根的对象
Long id;// 会议id
String title; //会议标题
DateTime startTime //会议开始时间
DateTime endTime //会议结束时间
}
}
```
这种“正向替换”和“反向注入”可以按需递归调用去将多个互相之间有外键关系的对象组装成最终对象。例如还有另外一张表MeetingAgenda到Meeting有n:1的外键和另外一张表AgendaAttendance到MeetingAgenda有n:1外键。那么如果我要去组装以Meeting开始包含MeetingRoom, MeetingAgenda, AgendaAttendance的组装对象首先发现MeetingRoom是可以正向扩展到Meeting的反向注入MeetingAgenda而AgendaAttendance需要先反向注入到MeetingAgenda中。
- **TOCO中json结构描述:** 在TOCO中DTO使用一个json结构表示有时用户会在上下文中提供关于DTO的json描述所以你需要了解结构中一些关键字段便于你能够理解用户提供的DTOexpandList为正向替换reverseExpandList为反向注入customFieldList为自定义字段。expandListList中field为正向替换对应的本表外键字段的名字fieldName为正向替换之后给该字段的起的新名字reverseExpandList中field为反向注入对应的他表外键字段的名字fieldName为反向注入之后给该字段的起的新名字customFieldList中uuid为参数对应类结构的UUID当type为Enum、Eo时包含该字段innerType为List内部类型当type为List时包含该字段innerUuid为List内部类结构的UUID当type为List且innerType=Enum、Eo时包含该字段。
- **预定义方法:** 对于每一个DTOTOCO会自动其根Entity的唯一索引生成一些预定义的RPC方法及实现预定义方法不仅获取了根Entity的数据还通过RPC调用的方式**自动**获取了**所有扩展字段**的数据并对数据进行了拼装处理。如实体user有unique index(username)则会针对UserDto生成UserDto UserDtoService.getByUserName(String userName)和List<UserDto> UserDtoService.getByUserNames(List<String> userNames)。预定义方法内部根据外键关系自动生成了复杂DTO数据的递归、Join拼装的能力会直接返回DTO内部的所有继承字段和扩展字段的数据。注意自定义字段的数据获取不会自动生成需要在对应的convert方法中编写代码。
- **公开性:** DTO可以设置公开性如果DTO为公开则其生成的预定义RPC方法也为公开RPC可以被其他模块订阅并调用如果DTO为非公开则其生成的预定义RPC方法也为非公开RPC其他模块不可见
- **跨模块依赖:** 如果DTO内引用了其他模块的DTO则TOCO会自动订阅其他模块的RPC(getByIds,getBy${foreignKey}等)方法用来获取对应的DTO
- **复杂嵌套DTO获取流程:** 如果我们需要获取DTO通常有2种方式且两种方式都可以直接获取到复杂嵌套的DTO数据
- 第1种: 通过预定义方法获取DTO
- 第2种: 通过读方案获取DTO
在TOCO中通常使用以下步骤判断使用哪种方式
- a. 如果查询DTO的条件为主键或唯一索引的值或列表则直接使用第1种方式
- b. 如果通过其他复杂查询条件则可以采用第2种方式
注意判断使用哪种方式时,只能根据查询条件判断是否使用读方案,绝对禁止使用返回值是否需要数据拼装来判断!**如果现实中的代码和TOCO中的步骤有冲突时只能使用TOCO的定义**
#### **2.7 视图对象 (VO)**
- **定义与用途:** 在TOCO中VO表达某个BaseDTO(如果用户指明派生源也可使用其他DTO)为派生源通过外键关系不断关联多个BaseDTO的数据结构。VO用于在视图层与前端之间进行数据传输往往被当做HTTP API的返回值、或读方案的返回值使用由服务端返回至前端。注意VO不能作为RPC的返回值。
- **关键配置:** 名称(以Vo结尾)、根Entity、派生源、字段列表。VO中的字段分为三种a.继承DTO的字段和DTO的字段类型一样b.扩展字段含正向替换和反向注入字段类型为VO或List<VO>;c.自定义字段类型为基本类型或VO类型。VO中的字段来源于DTO可以根据页面需要进行裁剪可以根据外键关系扩展其他BaseDto(详见**字段扩展方式**)。如果在派生源中没有合适字段且明确无法通过外键扩展外部BaseDto的情况下可增加对应的自定义字段
- **与DTO的区别 (在TOCO语境下): **DTO用于服务层传输通常作为RPC的返回值与数据模型更近复用性较强VO用于视图层传输通常作为API的返回值与UI展示更为接近复用性较弱。
- **如何创建/生成:** VO通常由某个BaseDTO以及外键关系为基础派生也可以直接创建和DTO无关、内部全为自定义字段的VO尽量少用只为应对某些特殊页面需要组装一组完全无关的返回数据的场景
- **根VO和子VO:**TOCO中的VO分为两种1.根VO指最外层的VO结构需要经由TOCO创建2.子VO某个根VO的内部嵌套VO通过外键关系关联BaseDTO之后由TOCO自动创建。所以在TOCO中我们只需要描述VO要描述的字段、扩展关系并通过**创建根VO**的行为使TOCO**自动创建**其子VO即可完成一个复杂嵌套VO的创建过程无需单独创建子VO。
- **字段扩展方式:**同DTO的字段扩展方式可以通过任意**一个**派生源BaseDTO即可经过外键扩展成为复杂嵌套VO。只要存在外键关系且满足以下条件即可扩展对于正向替换当前实体存在指向其他实体的外键字段对于反向注入其他实体存在指向当前实体的外键字段。
例如有两个BaseDTO
```
MeetingRoomBaseDto{ //会议室
Long id;// 会议室id,主键
String name;// 会议室名称
}
MeetingBaseDto { //会议
Long id;// 会议id,主键
Long roomid; //占用的会议室id到MeetingRoom的外键n:1关系
Long backupRoomid; //备用的会议室id到MeetingRoom的外键n:1关系
String title; //会议标题
DateTime startTime //会议开始时间
DateTime endTime //会议结束时间
}
```
其中Meeting和MeetingRoom是n:1关系。即多个会议室会占用同一个会议室。
通过“正向替换”这个行为可以组装出如下VO
```
MeetingWithRoomVo { //根VO需要通过TOCO创建
Long id;// 会议id
MeetingRoomVo room { //正向替换该会议用的会议室信息TOCO自动生成的内部VO派生自MeetingRoomBaseDto
Long id; //会议室ID
String name;// 会议室名称
}
Long backupRoomid; // 不做变化
String title; //会议标题
DateTime startTime //会议开始时间
DateTime endTime //会议结束时间
}
```
通过“反向注入”这个行为,可以生成:
```
MeetingRoomWithMeetingVo{
Long id;// 会议室id
String name;// 会议室名称
List<MeetingVo> meetingList{ //反向注入的用该会议室的会议信息TOCO自动生成的内部VO派生自MeetingBaseDTo
Long id;// 会议id
String title; //会议标题
DateTime startTime //会议开始时间
DateTime endTime //会议结束时间
}
}
```
- **TOCO中json结构描述:** 在TOCO中VO使用一个json结构表示有时用户会在上下文中提供关于DTO的json描述所以你需要了解结构中一些关键字段便于你能够理解用户提供的VOexpandList为正向替换reverseExpandList为反向注入customFieldList为自定义字段。expandListList中field为正向替换对应的本表外键字段的名字fieldName为正向替换之后给该字段的起的新名字reverseExpandList中field为反向注入对应的他表外键字段的名字fieldName为反向注入之后给该字段的起的新名字customFieldList中uuid为参数对应类结构的UUID当type为Enum、Eo时会包含该字段innerType为List内部类型当type为List时会包含该字段innerUuid为List内部类结构的UUID当type为List且innerType=Enum、Eo时会包含该字段。
- **派生源默认使用BaseDTO:** 除非用户指定了VO的派生源DTO否则创建VO时只可以用**BaseDTO**为派生源。
- **与DTO的转换关系:** 在创建一个**有派生源的**VO后TOCO会在生成代码时自动生成2种convert方法1.基础convert方法从DTO转换为VO仅转换结构以及基本类型字段的get/set方法命名为convertTo${VoName}、convertTo${VoName}List、convertTo${VoName}Map其中**Map转换方法**为底层批量方法通常也是自定义字段逻辑编写的位置复用性好会被其他convert方法调用单个和列表convert方法都通过**调用Map方法**来实现;2.带数据拼装逻辑的convert方法内部会**自动**调用基础convert方法从DTO转换为VO并设置基本类型字段数据然后再根据外键**自动**获取**扩展字段**的数据以拼装最终数据方法命名为convertAndAssembleData、convertAndAssembleDataList也就是说这两个方法已经**自动**获取了所有**继承字段**和**扩展字段**的数据)。这2种方法对应的代码会生成在VO对应的Converter类中
- **字段数据获取:** 对于继承自DTO的字段、以及扩展字段TOCO会在convert方法中自动生成数据的获取代码无需手动实现这两种字段的获取和拼装逻辑。对于自定义字段则**必须**在最底层的convertTo${VoName}Map方法中实现对应的获取和拼装逻辑以便于其他convert方法都能够**复用**这段逻辑。**禁止**在其他convert方法中实现自定义字段逻辑因为这样会导致某些场景下数据拼装不完整。
- **跨模块依赖:** 如果VO内存在由其他模块DTO派生出的子VO则TOCO会自动订阅其他模块的RPC(getByIds,getBy${ForeignKey}s等)方法用来获取对应的DTO然后再转换为子VO无需手动订阅这些RPC
- **复杂嵌套VO获取流程:** 如果我们需要获取VO通常有3种方式且3种方式都可以直接获取到复杂嵌套的VO数据
- 第1种: 先通过预定义方法获取VO的派生源BaseDTO再通过convertAndAssembleData或convertAndAssembleDataList方法转换成VO
- 第2种: 先通过读方案获取VO的派生源BaseDTO再通过convertAndAssembleData或convertAndAssembleDataList方法转换成VO
- 第3种: 通过读方案直接获取VO
在TOCO中通常使用以下步骤判断使用哪种方式
- a. 如果查询VO的条件为主键或唯一索引的值或列表则直接使用第1种方式
- b. 如果通过其他复杂查询条件则可以采用第2种或第3种方式
- c. 如果用户上下文中有指定的返回DTO的读方案符合条件则使用第2种否则使用第3种
注意判断使用哪种方式时,只能根据查询条件判断是否使用读方案,绝对禁止使用返回值是否需要数据拼装来判断!**如果现实中的代码编写方式和TOCO中的步骤有冲突时只能使用TOCO的定义**
#### **2.8 读方案 (ReadPlan)**
- **定义与用途:** 在TOCO中读方案描述了一种数据库查询方案查询条件为一个面向对象的查询语句其中可以包含存在外键关系的多个实体的字段(如age=18 and name like #nameLike and school.name like #schoolNameLike其中以#开头的是自定义参数会自动生成一个QTO结构由查询调用方动态传入),结果为符合查询条件的**一种**DTO或VO列表。读方案内部会将该面向对象的查询条件转化为复杂的join sql语句来实现对数据库的查询以及返回的复杂DTO和VO数据的组装。读方案可以指定其分页方式不分页、页码分页、瀑布流分页以及是否生成计数方法(用于返回符合条件的记录数量)。
- **使用建议:** 如果查询条件只有主键则建议使用预定义的getBy${PrimaryKey}或getBy${PrimaryKey}s方法来获取DTO参照DTO的**预定义方法**或VO参照**复杂嵌套VO获取流程**),不建议使用读方案。非主键查询或多条件查询建议使用读方案。
- **关键配置:** 名称(小写字母+下划线不要以read_plan结尾)、返回结构(DTO/VO一个读方案**不能**同时返回多种DTO或VO)、查询条件的自然语言描述、是否生成计数方法、排序字段(如果选择不分页,则不需要)
- **与RPC、代码的关系:** 对于每一个返回DTO的读方案TOCO会为每种分页方式自动生成一个RPC方法其参数为对应的QTO返回值为DTO列表如果选择了生成计数方法则还会生成一个RPC参数为QTO返回值为符合条件的DTO数量。同样对于每一个返回VO的读方案TOCO会自动生成一个Java方法其参数为对应的QTO返回值为VO列表方法内部逻辑已经由TOCO完全实现;如果选择了生成计数方法则还会生成一个count方法参数为QTO返回值为符合条件的DTO数量方法内部逻辑已经由TOCO完全实现
- **如何创建/生成:** 在创建读方案时,必须先调用工具创建或选择现有的**一种**DTO或VO作为返回值类型然后再定义查询条件的自然语言描述根据用户姓名、年龄、学校名称查询用户列表分页方式、是否生成计数方法、排序字段等。
- 你需要提取需求中的查询部分信息,以输入的查询对象作为查询上下文件,构建一个查询语句
- 基本语法格式是 属性名 操作符 变量或常量,变量表示了这个数据是外部传入的,用 #变量名为格式;如果是枚举类型常量,需要使用'符号包起来,例如: 男性枚举类型 'MALE'
- 对于数值、时间类型属性有:!=, ==, >, <,<=,>=, in,notIn, isNullOrNot 这些操作符
- 对于文本类型属性有like, isNotNull, isNull,!=, ==, in,notIn, isNullOrNot 这些操作符
- 对于对象属性或者列表对象属性可以用isNull, isNotNull, isNullOrNot 这些操作符。注意本对象不能直接用这个操作符。
- 对于对象属性还可以对其子属性进行上述查询
- 查询变量不能作为条件属性
- 查询条件之间可以使用AND, OR 进行连接
- 可以插入括号()对条件进行分组
- 对于列表对象属性只能使用contains、isNull、isNotNull操作符如果是wo列表类型可以使用contains(子查询, 子查询的条件属性只能作用在对应的列表类型对象的属性上),表示了该列表属性中需要包含至少一个满足子查询条件的对象; 其他列表类型只能使用isNull或者isNotNull
- 把上述子查询通过and, or, not这三个连接符拼装在一起就可以完成一个查询。请不要使用没提示过的操作符号连接符。
- 查询条件中的入参可以在运行时传入或者不传入值如果不传入值表示该参数相关的条件不起作用基于这种查询语句实际运行时的动态效果多个条件联合查询的时候可以优先使用AND
- 使用点号(.)可以访问当前对象的单值对象类型的子属性, 可以多个点号的组合访问嵌套单值对象的属性
- 查询条件中的属性必须是当前查询对象的属性或单值对象属性或者单值对象的子属性
- 禁止使用filter语法
- 禁止使用has语法
- 语法定义:使用 lezer 定义了如下语法
```
@top Program { expression? }
@skip { spaces | newline | LineComment }
@precedence {
member,
and @left,
or @left
}
kw<term> { @specialize[@name={term}]<identifier, term> }
boolean { @specialize[@name=Boolean]<identifier, "true" | "false"> }
@skip {} {
String[isolate] {
'"' (stringContentDouble | Escape)* ('"' | "\n") |
"'" (stringContentSingle | Escape)* ("'" | "\n")
}
}
commaSep<content> {
content ("," content)*
}
List {
"[" commaSep<Value> ~destructure "]"
}
Value { String | Number | List | boolean }
Field { identifier ~arrow }
Member { Field !member "." (Member | Field) }
Input { "#" identifier ~arrow }
expression {
TupleExpression | BinaryExpression | NotExpression | ParenthesizedExpression | ListExpression
}
TupleExpression { TwoTupleExpression | ThreeTupleExpression }
TwoTupleExpression { (Field | Member) TwoOperator }
ThreeTupleExpression { (Field | Member) ThreeOperator (Input | Value) }
ListExpression { (Field | Member) ListOperator ParenthesizedExpression }
BinaryExpression {
expression !and (kw<'AND'> | kw<'and'>) expression |
expression !or (kw<'OR'> | kw<'or'>) expression
}
NotExpression { (kw<'NOT'> | kw<'not'>) ParenthesizedExpression }
ParenthesizedExpression { "(" expression ")" }
@tokens {
spaces[@export] { $[\u0009 \u000b\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]+ }
newline[@export] { $[\r\n\u2028\u2029] }
identifierChar { @asciiLetter | $[_$\u{a1}-\u{10ffff}] }
word { identifierChar (identifierChar | @digit)* }
identifier { word }
hex { @digit | $[a-fA-F] }
stringContentSingle { ![\\\n']+ }
stringContentDouble { ![\\\n"]+ }
@precedence { spaces, newline, identifier }
Escape {
"\\" ("x" hex hex | "u" ("{" hex+ "}" | hex hex hex hex) | ![xu])
}
Number {
(@digit ("_" | @digit)* ("." ("_" | @digit)*)? | "." @digit ("_" | @digit)*)
(("e" | "E") ("+" | "-")? ("_" | @digit)+)? |
@digit ("_" | @digit)* "n" |
"0x" (hex | "_")+ "n"? |
"0b" $[01_]+ "n"? |
"0o" $[0-7_]+ "n"?
}
@precedence { Number "." }
ThreeOperator { "in" | "notIn" | "!=" | "==" | ">" | ">=" | "<" | "<=" | "isNullOrNot" | "like" | "has" }
TwoOperator { "isNull" | "isNotNull" }
ListOperator { "contains" | "filter" }
LineComment[isolate] { "//" ![\n]* }
"(" ")"
"[" "]"
"."
}
@detectDelim
```
- **读方案设计元素的表达**
- 以json格式表达json schema 定义如下
```json
{
"type":"object",
"properties":{
"qto": {
"type":"object",
"properties":{
"name": {
"type":"string","description":"查询的名称表达了查询的意图长度限制在32个字符内"},
"description": {"type":"string","description":"查询需求的概括性描述长度限制在256个字符内"},
"generateCountApi": {"type":"boolean", "description":"需求是否需要生成计数接口"},
"supportPaginate": {"type":"boolean", "description":"需求是否需要分页"},
"supportUnPage":{"type":"boolean", "description":"如果不需要分页一次性返回部数据则返回true"},
"supportWaterfall":{"type":"boolean","description":"需求是否需要瀑布流"},
"query":{"type":"string","description":"需求的查询语句,符合前述语法定义"}
},
"required":["name","description","query"]
}
},
"required":["qto"]
}
```
- **举例**
- 上下文
```java
public class meeting_room {
storey storey; // 楼层id
List<image_storage_info_eo> picture; // 照片
String name; // 名称
room_type_enum room_type; // 会议室类型
List<equipment_enum> equipment; // 设备
Long id; // 主键
Long seat_number; // 座位数
String description; // 说明
Boolean enable_indicator; // 是否启用
String input_code; // 输入码
Date created_at; // 创建时间
Date updated_at; // 更新时间
Long storey_id; // 楼层id
Long lock_version; // 乐观锁字段
Long contact_staff_id; // 联系员工ID
List<meeting> meeting;
Long deleted_at; // 删除时间
class storey { // 建筑的楼层
location location; // 位置id
String name; // 楼层
Long id; // 主键
Long sort_number; // 排序号
Date created_at; // 创建时间
Date updated_at; // 更新时间
Long deleted_at; // 删除时间
Long location_id; // 位置id
}
class meeting {
Long id; // 主键
String title; // 标题
Date start_time; // 开始时间
Date end_time; // 结束时间
Long room_id; // 会议室id
String description; // 描述
Long create_user_id; // 创建人id
Date created_at; // 创建时间
Date updated_at; // 更新时间
Long deleted_at; // 删除时间
}
class location { // 位置信息,如楼栋
String name; // 名称
Long id; // 主键
String description; // 描述
Long sort_number; // 排序号
Date created_at; // 创建时间
Date updated_at; // 更新时间
Long deleted_at; // 删除时间
}
enum room_type_enum { //
SMALL, //小会议室
MEDIUM, //中会议室
LARGE
}
enum equipment_enum { //
TV, //电视
WHITEBOARD, //白板
PROJECTOR, //投影仪
VIDEO
}
}
```
- 用户需求
获取一段时间未被使用的会议室(包含当前会议已选择的会议室),分页返回
- 对应的读方案定义
```json
{
"qto": {
"name": "get_unused_meeting_room_list",
"description": "获取未使用的会议室(包含当前会议已选择的会议室)",
"generateCountApi": true,
"supportPaginate": true,
"supportUnPage": false,
"supportWaterfall": false,
"query": "enable_indicator == true AND ( id == #idIs OR meeting isNull OR NOT ( meeting contains ( start_time <= #meetingEndTime AND end_time >= #meetingStartTime ) ) )"
}
}
```
#### **2.9 查询传输对象(QTO)**
- **定义与用途:** 在TOCO中QTO为读方案的查询参数结构每个读方案会对应一个QTO写方案调用方按照QTO的结构向读方案生成的RPC方法传入需要查询的实体字段值完成对数据库的查询
- **如何创建/生成:** 在创建读方案后TOCO会自动生成QTO作为该读方案传入的查询参数结构无需单独创建
- **关键配置:** 名称(${ReadPlanNameQto},驼峰展示),查询字段列表(如idIsnameLike, schoolNameLike等)
- **与API的关系:** QTO通常可作为API的参数API接收到参数后可直接透传给内部的RPC进行调用
#### **2.10 写方案 (WritePlan)**
- **定义与用途:** TOCO针对写场景定义了一种写方案所有对数据库的写操作都只能通过写方案实现。写方案包含了对数据库表的写操作。每个写方案只能操作一个聚合内部的表同时对一个聚合内表的操作尽量合并至一个写方案中根据复用性、内聚性等方面具体情况具体分析。注意写方案可以一次操作聚合内的多张表如location和storey是同一个聚合并且location和storey是**1:N**关系location是父对象聚合根storey是子对象那么我们可以创建一个写方案同时更新单个聚合根location中的信息以及操作其下的子表storey**列表**信息如新增、删除、修改storey等也可以创建一个写方案单独更新单个子表storey对象信息。
- **关键配置:** 名称(小写字母+下划线不要以write_plan结尾)操作的聚合聚合内的实体和字段对每个实体的操作类型CREATE创建**单个**实体UPDATE(更新**单个**实体), DELETE(删除**单个**实体), CREATE_ON_DUPLICATE_UPDATE(创建或者更新**单个**实体),FULL_MERGE( 批量更新**列表**数据根据传入的列表数据一条一条执行CREATE_ON_DUPLICATE_UPDATE的操作并且删除掉老的列表中不在传入列表数据中的部分), PARTIAL_MERGE(批量更新**列表**数据,根据传入的列表数据,一条一条执行)
- **与RPC的关系:** 对于每一个写方案TOCO会自动生成一个RPC方法其参数为写方案对应的BTO返回值为本次操作的聚合根实体的主键值内部只实现了对当前聚合的数据库操作
- **与聚合的关系:** 每个聚合下可以定义多个写方案,但每个写方案只能操作一个聚合内的表,无法同时操作多个聚合内的表
- **如何创建/生成:** 创建写方案时需要先选定对应的聚合,以及要操作的聚合内部的实体,然后确定对每个实体的具体操作类型
- 提取需求中的更新部分需求,根据上下文信息构建出一个写更新方案
- 上下文中输入了备选聚合对象的的定义,每个聚合对象定义了多个实体的嵌套关系
- 根据需求提取出变更相关的名称
- 根需求提取出变更相关的描述
- 根据需求选择确定变更范围,选出一个最合适的聚合对象;注意: 最多只能选择一个聚合对象
- 根据需求在选定的聚合对象按照对象的粒度,选出所需变更对象
- 根据需求选定变更对象的字段;每个选定的对象至少需要选定一个字段,如果无法确定任何字段,默认选择全部字段, 字段必须明确指定名称,不能类似“所有字段”的模糊表达
- 每个对象上可以设置对应的一个操作操作包括CREATE创建UPDATE(更新), DELETE(删除), CREATE_ON_DUPLICATE_UPDATE(创建或者更新),FULL_MERGE( 批量更新列表数据根据传入的列表数据一条一条执行CREATE_ON_DUPLICATE_UPDATE的操作并且删除掉老的列表中不在传入列表数据中的部分), PARTIAL_MERGE(批量更新列表数据根据传入的列表数据一条一条执行CREATE_ON_DUPLICATE_UPDATE的操作)
- 批量更新列表数据(FULL_MERGE或者PARTIAL_MERGE),则操作方案需要包含它的父对象
- FULL_MERGE和PARTIAL_MERGE只能用在列表属性上, 单值属性请使用CREATE_ON_DUPLICATE_UPDATE
- 操作是 UPDATE、DELETE、CREATE_ON_DUPLICATE_UPDATE、FULL_MERGE、PARTIAL_MERGE的时候必须且只能指定一个唯一键(unique_key)(包括主键),用于确定对应的数据记录主键对应的字段也要包含在fields字段中;
- 选定的对象层级不能跳跃;如果发生不连续,去掉不连续的叶子对象
- 注意父对象和下一层子对象的操作类型有如下限制
- 如果父对象的操作是DELETE则下一层子对象不能选择也不能能设定任何操作
- 如果父对象是的操作是CREATE则下一层子对象只能选择CREATE
- 如果父对象是CREATE_ON_DUPLICATE_UPDATE子对象只能是CREATE或者CREATE_ON_DUPLICATE_UPDATE或者FULL_MERGE或者PARTIAL_MERGE
- 如果父对象是FULL_MERGE子对象只能是FULL_MERGE或者PARTIAL_MERGE或者是CREATE
- 对于选定的字段列表中的字段如果字段的类型是Long、BigDecimal、Float 则可以设置为增量更新字段, 把值设置在incrFields属性中和操作"UPDATE"、"CREATE_ON_DUPLICATE_UPDATE"、"PARTIAL_MERGE"或者"FULL_MERGE"搭配表示对该字段增量更新: 例如A实体的字段count类型是Long, 如果该字段被设置为增量跟新字段最终的效果是A.count = A.count + ? ; 对于减少字段的值也用该方法表示,可以通过传入负值的入参达到减值的效果
- **写方案设计元素的表达**:
以json格式表达json schema 定义如下:
```json
{
"type":"object",
"properties":{
"name":{"type":"string","description":"需求的意图描述长度限制在32个字符之内"},
"description":{"type":"string","description":"需求的概括性描述长度限制在256个字符内"},
"bo": {"type":"string","description":"聚合根的名称,确定了唯一聚合"},
"operations": {"type":"array","description":"描述了对各个Bo的操作",
"items":{
"type": "object",
"properties":{
"bo":{"type":"string","description":"具体操作的实体"},
"action":{"type":"string","description":"对前述实体的"},
"unique_key": {
"type":"array",
"description":"唯一键包含的字段列表",
"items":{
"type":"string",
"description":"字段名称,组成唯一键的字段"
}
},
"fields":{
"type":"array",
"items":{
"type":"string",
"description":"字段名称必须来自bo对象"
},
"description":"对选定的Bo的操作的字段列表"
},
"incrFields":{
"type":"array",
"items":{
"type":"string",
"description":"增量字段名称"
},
"description":"选定的字段中进行增量操作的字段列表"
},
"required":["bo","action","fields"]
},
"description":"定义了对某个实体的操作,包括操作类型和相关字段"
}
}
},
"required":["name","description","operations"],
"description":"描述了对一个聚合的变更操作"
}
```
- **例子**
- **上下文:**
```java
public class meeting {//会议聚合
//唯一键:(id)、(meeting_name)
Long id; //主键id
String meeting_name; //会议名称
Date start_time; //开始时间
Date end_time;//结束时间
List<meeting_agenda> meetingAgendaList;
class meeting_agenda {
Long id;//主键
Date start_time;//开始时间
Date end_time;//结束时间
String title;//议程名称
List<agenda_vs_user> agendaVsUserList;
}
class agenda_vs_user {
Long id; //主键
Long user_id; //用户id
Long agenda_id; //议程id
Date enroll_time; //注册时间
Long meeting_id;//会议id
}
}
public class user {//用户聚合
//唯一键:(id)、(name,gender)
Long id;//主键
String name;//名字
GenderEnum gender;//性别
String nickname;//昵称
Long friend_count;//好友数量
}
```
- **需求:** 创建会议
- 对应的写方案定义:
```json
{
"name": "create_meeting",
"description": "创建会议",
"bo": "meeting",
"operations": [
{
"bo": "meeting",
"action": "CREATE",
"fields": [
"meeting_name",
"start_time",
"end_time"
]
}
]
}
```
#### **2.11 业务变更传输对象(BTO)**
- **定义与用途:** 在TOCO中BTO为写方案自动生成的参数结构每个写方案会生成一个BTO。BTO为写方案选定的操作实体根据关系形成的树形集合最外层为聚合根。写方案调用方按照BTO的结构向写方案生成的RPC方法传入需要操作的实体字段值完成对数据库的写操作
- **如何创建/生成:** 在创建写方案后TOCO会自动生成一个BTO作为该写方案传入的参数结构无需通过TOCO创建。
- **关键配置:** 名称(${WritePlanName}Bto驼峰展示嵌套的树形实体和字段列表BTO内部的字段全部都来自Entity。以下为一个示例
```
class CreateUserBto { //对应实体user
Long id; //来自于user.id
String name; //来自于user.name
List<PictureBto> pictureList;
class PictureBto { //对应实体picture
String url; //来自于picture.url
}
}
```
- **与API的关系:** BTO通常可作为API的参数API接收到参数后可直接透传给内部的RPC进行调用
#### **2.12 服务层方法 (RPC)**
- **定义与用途:** 在TOCO中RPC为服务层的方法。RPC按照可见性可以分为两种一种是公开RPC可以被其他模块订阅订阅后可以通过RPC适配器进行调用另一种是非公开RPC只能被当前模块调用。非公开RPC可以被公开从而被其他模块订阅并调用
- **如何创建/生成:** RPC有4种创建方式a.DTO创建后会自动创建RPCRPC的公开性与DTO的公开性保持一致b.返回DTO的读方案会根据分页情况、以及是否生成计数函数的配置自动生成非公开的RPC c.写方案创建后会自动生成非公开的RPC d.如果上述三种RPC无法满足需求则可以通过TOCO创建自定义RPC完整指定功能需指定具体的参数和返回值以及公开性等。
- **优先复用:** 当用户需要创建一个RPC时如果用户有明确要求创建的方式则按照用户的要求来创建。如果没有明确要求则通常先判断是否可以通过创建读方案、写方案、DTO来使TOCO自动创建出对应的RPC最后再考虑通过TOCO创建自定义RPC
- **自定义RPC和代码中手写方法的关系** 二者都可以通过手动的方式实现一个服务层的方法应用场景的区别在于如果一个方法需要被其他模块订阅则通常使用自定义RPC如果一个方法只是某个API私有调用不需要给外部模块开放则可以使用代码手写方法
- **关键配置:** 类名(以Service结尾)、是否公开、方法名(小写字母+下划线)、请求参数、返回值
- **参数类型:** RPC的参数**只能**为QTO、BTO、Enum、基本类型可为单值或列表。注意如果是对象类型则优先使用QTO、BTO作为参数**禁止使用**VO、EO和自定义结构如Object
- **返回值类型:** RPC的返回值**只能**为DTO、Enum、基本类型,可为单值或列表,**禁止使用**VO、QTO、BTO、EO、自定义结构如Object作为返回值。注意如果是对象类型则优先使用DTO作为返回值
- **TOCO中json结构描述:** 在TOCO中DTO使用一个json结构表示示例如下
```json
{
"methodName": "saveUsers",
"className": "UserSaveService",
"requestParams":[
{
"name": "saveUserBtoList",
"description": "批量保存用户参数",
"type": "List",
"innerType": "Bto",
"innerUuid": "dbvvc4d4-0063-442f-abd7-vrfded656988"
}
],
"response": {
"type": "Boolean"
}
}
```
结构中一些关键字段描述如下:
requestParams为请求参数列表response为返回结构requestParams中每个参数和response的结构相同其中name为参数名;type为参数类型参数类型取值范围为Boolean,String,Integer,Long,Float,Double,BigDecimal,Date,ByteArray,Enum,Eo,List,Dto,Qto,Bto,Void其中参数不能为Void如果不需要返回值则type设置为Voiddescription为描述uuid为参数对应类结构的UUID当type为Enum、Eo、Dto、Qto、Bto时包含该字段innerType为List内部类型当type为List时包含该字段innerUuid为List内部类结构的UUID当type为List且innerType为Enum、Eo、Dto、Qto、Bto时包含该字段。
#### **2.13 应用程序接口 (API)**
- **定义与用途:** 在TOCO中API用于定义对外暴露的HTTP接口
- **如何创建/生成:** API一般为通过TOCO创建需指定具体的参数和返回值等
- **关键配置:** uri(加粗展示,一般为/api/${moduleName}/xxx如/api/user/create。如果用户有特殊命名规则的话以用户要求为准)、类名(以Controller结尾)、方法名、请求参数、返回值
- **参数类型:** API的参数**只能**为QTO、BTO、Enum、基本类型可为单值或列表。注意如果是对象类型则优先使用QTO、BTO作为参数。**禁止使用**DTO、EO和自定义结构如Object
- **返回值类型:** TOCO的API运行在自己的Java脚手架中脚手架会自动对API的返回值做一层对象包装code、message、data。所以在TOCO中API的返回值无需考虑返回码和错误信息只需考虑返回的数据本身。TOCO中API的返回值**只能**为VO、Enum、基本类型,可为单值或列表,**禁止使用**DTO、QTO、BTO、EO、自定义结构如Object作为返回值。注意如果是对象类型则优先使用VO作为返回值。
- **TOCO中json结构描述:** 在TOCO中API使用一个json结构表示示例如下
```json
{
"methodName": "getUserMeetingList",
"className": "MeetingQueryController",
"requestParams":[
{
"name": "getMeetingListByUserId74Qto",
"description": "查询参数",
"type": "Qto",
"uuid": "6351a4d4-0063-442f-abd7-a2df6d656988"
},
{
"name": "test",
"description": "是否为测试请求",
"type": "Boolean"
}
],
"response": {
"type": "List",
"innerType": "Vo",
"innerUuid": "1d58352b-5333-4509-aec2-1abc3fac9122"
}
}
```
结构中一些关键字段描述如下:
requestParams为请求参数列表response为返回结构requestParams中每个参数和response的结构相同其中name为参数名;type为参数类型参数类型取值范围为Boolean,String,Integer,Long,Float,Double,BigDecimal,Date,ByteArray,Enum,Eo,List,Vo,Qto,Bto,Void其中参数不能为Void如果不需要返回值则type设置为Voiddescription为描述uuid为参数对应类结构的UUID当type为Enum、Eo、Vo、Qto、Bto时包含该字段innerType为List内部类型当type为List时包含该字段innerUuid为List内部类结构的UUID当type为List且innerType为Enum、Eo、Vo、Qto、Bto时包含该字段。
#### **2.14 流程服务Function_Flow)**
- **定义与用途:** TOCO针对复杂业务拆解定义了流程服务把一个复杂的业务过程根据业务逻辑的内聚性合并逻辑功能把流程分解成流程节点最终构造出一个类似工作流的逻辑流程最终实现复杂业务流程分解提升代码的可维护性。TOCO内嵌了流程引擎在Function_Flow生成代码后可以在流程引擎中执行
- **何时使用:**
- 如果一个API/RPC中涉及的写服务超过3个则推荐使用流程服务
- 当用户要求使用流程服务
- **节点的封装:**
- 因为TOCO是一个面向数据处理的系统所以数据内聚为首要考虑因素一个节点通常围绕一个核心写服务包括取数的读服务为写服务的入参进行数据处理和转换以及该写服务完成后的一些附属功能, 除了条件节点,入参校验,最终数据返回节点,每个节点至少包括一个写服务。
- **关键配置:** 名称(小写字母+下划线),拆解复杂业务逻辑,如果业务流程比较简单,则不需要使用流程服务
- **如何创建/生成:**
- 流程不是逻辑的伪代码,不需要表达全部逻辑细节,相关有内聚性,相似性的功能逻辑需要被封装到一个流程节点内;例如用户注册:创建用户需要,需要创建账号信息,需要创建用户信息,并且发送一个通知消息,这几个功能都属于创建用户相关信息,而且没有逻辑分叉,因此可以内聚在一个逻辑节点内。
- 流程节点之间的参数和返回值的传递通过一个统一的上下文Context传递
- 定义了JSON结构用于表达逻辑流。流程节点分为 “顺序节点”、“条件节点”,“选择节点”,"开始节点“ ,节点之间通过有向边连接,表示逻辑的执行方向;从开始节点开始,可达各个节点。
- 节点的边的定义如下顺序节点可以有多条入边可以有多条出边一个出边表示下一个执行的节点多条出边表示几个分支并发执行条件节点可由多条入边可以有2条出边表示条件为True和False两种逻辑分支选择节点可以有多条入边可以有多条出边每条出边表示一种选择路径开始节点只能有一条出边不能有入边;
- ”条件节点“只封装条件判断逻辑返回TRUE或者FALSE”循环节点“只封装条件判断逻辑返回TRUE或者FALSE”选择节点“只封装分支选择逻辑返回下游分支节点的名称条件节点一般用于拆分大的业务分支
- 终止流程,比如返回错误可以直接抛出异常实现,不需要再流程里表达
- 一般校验逻辑放在一个“顺序节点"中,如果校验失败,以异常的方式抛出
- 节点可以复用,同样的功能可以抽取出来封装到一个节点中
- 流程的定义: 一个流程由节点、边组成,定义如下
- 节点的定义Json如下所示
```
{
"name": "create_user", // 节点名称,表达了流程节点封装的功能
"description": "创建用户, 如果用户不存在,则创建,否则更新用户信息"//描述具体封装的业务逻辑
"type": "PROCESS_NODE" //节点类型,可以是 "PROCESS_NODE"(顺序节点)、"SWITCH_NODE"(选择节点)、"CONDITION_NODE"(条件节点),"START_NODE"(开始节点)
}
```
- 边的定义Json如下所示
```
{
"fromNode": "start", //表示开始节点
"toNode":"create_user",//指向节点
"value": true // 可选作为条件节点的出边表示true分支作为循环节点的出边表示循环分支
}
```
- 一个逻辑流由节点和边构成其中当且仅当只有一个开始节点JSON定义如下
```
{
"moduleName":"user",//该流程所属的模块
"name":"user_register",//定义该流程的功能
"description":"注册用户",//描述该流程的详细功能
"nodes":[ // 定义该流程包含的节点
{
"name":"start",
"type":"START_NODE",
"description": "起始节点"
},
{
"name":"check_user_registed",
"type":"CONDITION_NODE",
"description":"校验入参合法性;判断昵称是否重名;判断用户是否已注册"
},
{
"name": "create_user",
"descripiton":"创建用户,发送'用户创建'消息, 给用户发送欢迎通知",
"type": "PROCESS_NODE"
},
{
"name":"return_user_info",
"descripiton":"返回用户信息,返回推荐给用户可能感兴趣的好友",
"type":"PROCESS_NODE"
}
],
"edges": [
{
"fromNode": "start",
"toNode":"check_user_registed"
},
{
"fromNode":"check_user_registed",
"toNode":"create_user",
"value":false
},
{
"fromNode":"check_user_registed"
"toNode":"return_user_info",
"value":true
},
{
"fromNode":"create_user",
"toNode":"return_user_info"
}
]
}
```
### **3. TOCO 代码生成说明**
#### **3.1 生成代码产物说明**
- **3.1.1 支持的语言/框架**
Java、SpringBoot、MyBatis-plus(读)、Hibernate(写)
- **3.1.2 特殊注解及含义**
TOC自动生成的类和方法会带有@AutoGenerated注解注解中有2个属性:locked为boolean类型如果locked=true则代表该文件或方法不建议修改;uuid为String类型表示该类或方法的唯一标识如果uuid中包含|字符则说明该uuid为特殊格式由不同类型的数据拼装而成(见**[3.2 设计元素到代码的映射规则及修改建议]**中每种设计元素的代码说明)。
#### **3.2 设计元素到代码的映射规则及修改建议**
##### 3.2.1 Module
- **生成代码:** 每个Module会单独生成一个Java Module项目路径/modules/模块名内部采用了entrance、service、manager、persist、common分层结构
##### 3.2.2 Enum
* **生成产物**在common模块中生成一个Java类
* **职责:** 表达Enum的数据结构
* **命名规则**类名以Enum结尾
* **类路径:** 位于 ```**.common.enums``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定 ,uuid规则: ${Enum在TOCO中的uuid}|ENUM|DEFINITION
- **生成代码:** Enum会在common层生成Enum文件如StatusEnum
- **修改建议:** 不建议修改
##### 3.2.3 EO
* **生成产物**在persist层生成结构定义类文如AddressEo
* **职责:** 表达POJO数据结构
* **命名规则**类名以Eo结尾
* **类路径:** 位于 ```**.persist.eo``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定 ,uuid规则: ${Eo在TOCO中的uuid}|EO|DEFINITION
- **修改建议:** 不建议修改
##### 3.2.4 Entity
- 结构定义
* **生成产物**Java类按照Mybatis-plus的要求生成
* **职责:** 按照Mybatis-plus的要求生成结构定义类文件
* **类路径:** 位于 ```**.persist.dos``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定 ,uuid规则: ${Entity在TOCO中的uuid}|ENTITY|DEFINITION
- Mapper
* **生成产物**在persist层生成Mybatis-plus的Mapper类
* **职责:** 提供Mapper给Mybatis-plus框架
* **命名规则**类名以Mapper结尾(${entityName}Mapper)
* **类路径:** 位于 ```**.persist.mapper.mybatis``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定 ,uuid规则: ${Eo在TOCO中的uuid}
- Dao接口
* **生成产物**在persist层生成Dao接口
* **职责:** 提供Entity数据的查询接口为service层提供数据访问入口
* **命名规则**类名以Dao结尾(${entityName}Dao)
* **类路径:** 位于 ```**.persist.mapper``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定 ,uuid规则: ${Entity在TOCO中的uuid}|ENTITY|IDAO
- Dao实现
* **生成产物**在persist层生成Dao接口的实现类文件
* **职责:** 通过调用Mapper实现实现Dao接口
* **命名规则**类名以DaoImpl结尾(${entityName}DaoImpl)
* **类路径:** 位于 ```**.persist.mapper``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定 ,uuid规则: ${Entity在TOCO中的uuid}|ENTITY|DAO
- **修改建议:** 不建议修改
##### 3.2.5 业务对象 (BO)
- 综述
- 业务对象包含多个Entity通过业务对象的嵌套组合表达了Entity之间的关系如果一个业务对象包含了子对象则会生成BO和BaseBO,BaseBO封装实体属性和关系子类留给业务扩展逻辑
如果是叶子节点不存在子对象的BO则直接生成BO类文件不生成BaseBO类文件
- BO
* **生成产物**在Manager层生成聚合对象类文件符合Hibernate的标准
* **职责:** 定义聚合对象,多个聚合对象组合成层级结构实现充血模型,支持写链路上的数据变更,监听数据变更,支持数据校验
* **命名规则**类名以BO结尾(${entityName}BO)
* **类路径:** 位于 ```**.manager.bo``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定 ,uuid规则: ${Entity在TOCO中的uuid}|BO|DEFINITION
- **修改建议:** 建议修改BO中的validateAggregate或valid方法。不建议修改检验方法以外的其他代码如果发现需求中有业务不变性校验**注意** 上述的校验方法,在写方案内部由框架触发调用,而不是业务代码显式调用
- BaseBO
* **生成产物**对于存在子BO的聚合对象封装不变的代码部分
* **职责:** 定义聚合对象,多个聚合对象组合成层级结构实现充血模型,支持写链路上的数据变更,监听数据变更,支持数据校验
* **命名规则**类名以BO结尾(${entityName}BO)
* **类路径:** 位于 ```**.manager.bo``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定 ,uuid规则: ${Entity在TOCO中的uuid}|BO|DEFINITION
- **修改建议:** 建议修改BO中的validateAggregate或valid方法如果发现需求中有业务不变性校验;不建议修改检验方法以外的其他代码
##### 3.2.6 数据传输对象 (DTO)
- 结构定义
* **生成产物**一个Java类
* **职责:** 表达DTO的数据结构
* **命名规则**类名以Dto结尾
* **类路径:** 位于 ```**.manager.dto``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${DTO在TOCO中的uuid}|DTO|DEFINITION
- **Manager**
* **生成产物:** Java接口以及实现类
* **命名规则:** 接口类名以Manager结尾、实现类名以ManagerImpl结尾(${DtoName}Manager)、基类以名ManagerBaseImpl结尾(${DtoName}ManagerImpl)
* **职责:** 提供了DTO数据的获取的接口包括根据id单个、id列表批量获取、以及根据DTO对应的实体的数据库索引获取
* **类路径:** 位于 ```**.manager``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${DTO在TOCO中的uuid}|DTO|MANAGER
- **Converter**
* **生成产物:** Java实现类以及基类
* **命名规则:** 实现类名以Converter结尾(${DtoName}Converter)、基类名以BaseConverter结尾(${DtoName}BaseConverter)
* **职责:** Entity转换到BaseDTO或则BaseDTO转化为普通DTO从Entity转为BaseDTO的方法命名为convert${EntityName}To${DtoName}从BaseDTO转换为DTO的方法命名为convert${BaseDtoName}To${DtoName}
* **类路径:** 位于 ```**.manager.converter``` 包路径下
* **唯一标识符位置:**
* 实现类Converter 其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${DTO在TOCO中的uuid}|DTO|CONVERTER
* 基类BaseConverter 其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${DTO在TOCO中的uuid}|DTO|BASE_CONVERTER
- **例子:**
* 如UserDto、UserDtoManager、UserDtoConverter extends UserDtoBaseConverter、UserDtoService或名称为${DtoName}Service内部包含getById,getByIds等方法。如果Dto为UserBaseDto则生成的类名为UserBaseDtoService
- **修改建议:**
- 建议在Service与BaseConverter中进行代码扩展不建议修改结构定义文件和Manager文件。其中DTO的**自定义字段**由于不直接派生自Entity所以一般会对应取数逻辑代码。通常如果涉及到数据获取、计算和拼装批量处理的性能最好所以代码位置**必须**放在BaseConverter中已经自动生成的**列表**转换方法中批量取数组装如UserBaseDtoBaseConverter.convertUserToUserBaseDto(List<User>)或UserDtoBaseConverter.convertUserBaseDtoToUserDto(List<UserBaseDto>)
##### 3.2.7 视图对象 (VO)
- **结构定义**
* **生成产物:** 在controller层生成一个Java类
* **命名规则:** 类名以Vo结尾
* **职责:** 表达VO的数据结构
* **类路径:** 位于 ```**.entrance.web.vo``` 包路径下
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${VO在TOCO中的uuid}|VO|DEFINITION
- **Converter**
* **生成产物:** 在controller层生成一个Java类(**有派生源**的VO才有Converter)和基类
* **命名规则:** 实现类名以Converter结尾(${VoName}Converter)基类名以BaseConverter结尾(${VoName}BaseConverter)
* **类路径:** 位于 ```**.entrance.web.converter``` 包路径下
* **职责:** 把DTO转换成VOConverter中包含2种convert方法1.基础convert方法从DTO转换为VO仅转换结构方法命名为convertTo${VoName}、convertTo${VoName}List、convertTo${VoName}Map其中**Map转换方法**为底层批量方法单个和列表convert方法都通过**调用Map方法**来实现;2.带数据拼装逻辑的convert方法内部会调用基础convert方法从DTO转换为VO然后再根据外键获取拼装最终数据方法命名为convertAndAssembleData、convertAndAssembleDataList)
* **唯一标识符位置:**
* 实现类Converter其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${VO在TOCO中的uuid}|VO|CONVERTER
* 基类BaseConverter其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${DTO在TOCO中的uuid}|DTO|BASE_CONVERTER
* **例子:**
* 如UserDetailVo、UserDetailVoConverter包含convertToUserDetailVo、convertToUserDetailVoList、convertToUserDetailVoMap、convertAndAssembleData、convertAndAssembleDataList方法
- **修改建议:**
- 建议在Converter中进行代码扩展不建议修改结构定义文件。其中VO的**自定义字段**由于不直接派生自DTO所以一般会对应取数逻辑代码。通常如果涉及到数据获取、计算和拼装批量处理的性能最好所以自定义字段对应的代码位置**必须**放在Converter的**Map**基础转换方法convertTo${VoName}Map中批量取数组装如UserVoConverter.convertToUserVoMap
##### 3.2.8 读方案 (ReadPlan)
- **Service**
* **生成产物:** 在Service层生成一个Java类
* **命名规则:** 类名以QtoService结尾(${ReadPlanName}QtoService)
* **类路径:** 位于 ```**.service.index.entity```包路径下
* **职责:** 提供查询入口返回符合查询条件的DTO或VO的id列表分页、全部、或则瀑布流,以及返回符合条件的总数。 在TOCO的读链路中数据查询分2步骤1. 获取符合查询条件的DTO或VO的id列表2. 根据id列表组装DTO或VO列表。
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定uuid规则: ${ReadPlan在TOCO中的uuid}|QTO|SERVICE
- **查询传输对象(QTO)**
* **生成产物:** 在Service层生成一个Java类
* **命名规则:** 类名以Qto结尾(${ReadPlanName}Qto)
* **类路径:** 位于 ```**.persist.qto```包路径下
* **职责:** 读方案的查询参数结构
* **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${ReadPlan在TOCO中的uuid}|QTO|DEFINITION
- **Dao**
- **生成产物:** 在Dao层生成一个Java类
- **命名规则:** 类名以Dao结尾(${ReadPlanName}Dao)
- **类路径:** 位于 ```**.persist.mapper```包路径下
- **职责:** 读方案对应的数据库查询方法
- **唯一标识符位置:** 其对应的唯一标志在类注解@AutoGenerated中指定,uuid规则: ${ReadPlan在TOCO中的uuid}|QTO|DAO
- **QueryExecutor**
- **生成产物** 对于返回**VO**的查询方案在controller层生成一个Java类
- **命名规则:** 类名以QueryExecutor结尾(${WritePlanName}QueryExecutor)
- **类路径:** 位于 ```**.entrance.web.query.executor```包路径下
- **职责:** 把QtoService返回的id数据转化成目标**VO**
- **QueryService**
- **生成产物** 对于返回**DTO**的查询方案在service层生成一个Java类
- **命名规则:** 类名以QueryService结尾(${WritePlanName}QueryService)
- **类路径:** 位于 ```**.service.index.entity```包路径下
- **职责:** 把QtoService返回的id数据转化成目标**DTO**
- **例子:**
* 根据用户名称查询用户列表返回UserDTO则生成UserNameQto、UserNameQtoService、UserNameQtoDao、UserNameQueryService; UserNameQueryService调用UserNameQtoServiceUserNameQtoService调用UserNameQtoDao
- **修改建议:**
- 如果有对结果的数据二次处理建议在QueryService和QueryExecutor中进行代码扩展不建议修改QTO文件
##### 3.2.9 写方案 (WritePlan)
- **Service:**
* **生成产物:** 在对应的聚合服务BoService里生成一个函数
* **函数命名规则:** 和写方案同名
* **职责:** 按需对入参进行转换调用BaseBOService里的函数完成对聚合对象的操作, 实现对数据库的写操作;
* **BoService的类路径:** ```**.service```
* **唯一标识符位置:** 其对应的标识符在函数的注解@AutoGenerated中指定, uuid规则: ${WritePlan在TOCO中的uuid}
- **BaseBoService**
- **生成产物:** 在对应的聚合的BaseBoService里生成一系列函数根据入参完成对聚合对象的变更
- **职责** 增对每个实体的生成增删改的函数,并且根据参数的结构以及聚合的结构,构建嵌套的调用逻辑,完成对一个聚合对象的变更,记录并且返回对应的变更情况
- **类路径:** ```**.service.base```
- **BTO (业务变更传输对象)**
* **生成产物:** 一个Java类以内部类的方式表示层级结构
* **命名规则:** 一个Bto结尾(${WritePlanName}Bto驼峰展示)
* **类路径:** 位于```**.service.bto```包路径下
* **职责:** 在**TOCO**中BTO为写方案的参数结构每个写方案会对应一个BTO写方案调用方按照BTO的结构向写方案生成的RPC方法传入需要查询的实体字段值完成对数据库的变更
* **唯一标识符位置:** 其对应的唯一标识符在类注解@AutoGenerated中指定, uuid规则: ${WritePlan在TOCO中的uuid}|BTO|DEFINITION
- **例子:**
- 创建用户以及用户设置的写方案create_user_and_setting生成CreateUserAndSettingBto, 在用户的聚合(UserBO)对应的UserBOService中生成函数createUserAndSetting该函数调用BaseUserBOService中生成的createUserAndSetting, 其中在BaseUserBOService中还生成了createUser和createSetting的函数, 一起完成了用户的创建和设置创建的逻辑。
- **修改建议:**
- 不能修改BaseBoService中的函数不建议修改BTO文件。建议在BOService中进行手动代码扩展处理可能被复用的修改前后的逻辑如修改数据库的前后值对比、或常被复用的校验逻辑业务不变性校验逻辑除外、需要经常在一个事务内执行的其他写操作等。
##### 3.2.10 RPC
- **生成代码:** RPC会在service层中生成类文件及实现函数包含DTO自动生成的RPC如UserDtoService.getById或UserBaseDtoService.getById、读写方案自动生成的RPC如UserDtoQueryService.queryByListQto、UserBOService.createUser、自定义RPC如UserCustomService.customMethod。特别注意公开的RPC才可被其他模块使用RPC被订阅后会生成RpcAdapter适配器其他模块通过RpcAdapter才可调用该方法。如Order模块订阅了User模块的UserDtoService.getById则会在Order模块中生成UserDtoServiceInOrderRpcAdapter.getById方法Order模块中的代码必须通过@Resource private UserDtoServiceInOrderRpcAdapter userDtoServiceInOrderRpcAdapter;注入适配器后才可进行方法调用
- **修改建议:** 建议修改RPC方法不建议修改RPC方法签名、适配器中的内容
##### 3.2.11 API
- **生成代码:** API会在entrance层生成Controller以及对应的API方法
- **修改建议:** 建议修改API方法的实现内容不建议修改API方法签名、URI
##### 3.2.12 流程服务(FunctionFlow)
- **FlowConfig**
* **生成产物:** 每个模块在service层的生成一个Java类负责注册模块下的所有流程到执行器
* **命名规则:** 类名为${moduleName}FlowConfig
* **职责:** 在应用启动的时候注册模块内的所有的流程服务到执行器
* **类路径:** ```**.service.flow```
- **Service**
* **生成产物:** 在service层的以模块名为类名前缀的${moduleName}FlowService中生成一个流程的入口函数
* **函数命名规则:** 流程名为方法名为后缀pubic void invoke${functionFlowName}(${functionFlowName}Context context)
* **职责:** 在代码逻辑中,使用该流程需要以该函数作为调用入口
* **类路径:** ```**.service```
* **唯一标识符位置:** 其对应的标识符在函数的注解@AutoGenerated中指定, uuid规则: ${FunctionFlow在TOCO中的uuid}|FLOW|METHOD
- **FlowNode**
* **生成产物:** 在service层生成一个Java类 **注意** 每个FunctionFlow的开始节点(StartNode)不生成
* **类命名规则:** ${nodeName}Node
* **入口函数命名:** pubic void process()
* **职责:** 用于封装内聚性的业务逻辑
* **类路径:** ```service.flow.node.${functionFlowName}```
- **FlowContext**
* **函数命名规则:** {nodeName}Node
* **职责:** 作为流程节点之间的参数传递(包括出参和入参),在实现业务逻辑的时候,按需在这个上下文类中添加所需的字段
* **类路径:** ```**.service.flow.context```
* **唯一标识符位置:** 其对应的标识符在类注解@AutoGenerated中指定, uuid规则: ${FunctionFlow在TOCO中的uuid}|FLOW|CONTEXT
- **例子:**
- 用户登录在UserFlowService中生成一个函数invokeLoginFlow该函数通过流程框架根据流程定义调用LoginNodeLoginNode中封装了用户登录的逻辑LoginFlowContext中封装了用户登录的参数和结果。
- **修改建议:** 不修改 service 中的函数, 不修改FlowConfig, 可以修改FlowContext, 添加/修改出入参数, 修改FlowNode中的具体业务逻辑。
### 4. TOCO 最佳实践
#### 4.1 设计分析结果应用(Design analysis results application):
在TOCO中设计分析(designAnalyze工具)的结果按照用户的要求或需求的复杂度分为2种你需要分辨流程分析的结果类型然后根据不同类型做出不同的后续工具调用规划:
- 1.**细节设计分析**:针对简单或短流程需求,会直接进行读写方案、接口等分析、代码编写等结果。此时需要根据工具规划后续的调用。
- 2.**流程拆解设计分析**:针对复杂需求,不会直接分析细节的设计元素,而是根据内聚、解耦、复用等原则,参考**流程服务Function_Flow)**对业务需求拆解为多个短流程并返回结果。后续需要针对整体的API的定义、流程服务定义、**所有**流程节点中涉及的**所有**DTO、VO、读写方案、RPC等来进行对应的工具调用。注意此时**必须**调用createFunctionFlow工具来创建流程服务。
#### 4.2 为所有的写场景都创建写方案(Create WritePlan For All Write Scenarios):
通常在分析业务需求时,需要分析出**所有**写数据的场景,并按照**聚合维度**进行分组,然后针对每个写场景**都需要**创建对应的写方案,不能有遗漏。写方案可以按需根据聚合进行合并。
#### 4.3 接口参数类型和返回值选择(Interface Parameter & Return Type Definition):
在做TOCO接口(API、RPC)设计时通常会先判断接口的主要功能是读数据库或写数据库并分析相关的读写方案以及对应的QTO和BTO。如果是读场景则参数会**优先使**用相关的QTO如果是写场景则参数会**优先**使用相关的BTO如果BTO和QTO无法满足要求则可以再增加基本类型或Enum、EO等类型参数。参数类型选择时必须遵循以下要求a.DTO、VO不能作为参数类型b.QTO、BTO不能作为返回值类型
### 5. 本地代码阅读和编写指南
#### 5.1 代码阅读
- 根据**设计元素到代码的映射规则及修改建议**在约读代码的时候你可以识别出对应的TOCO设计元素通过工具获取TOCO设计元素信息辅助理解代码语义特别是对于ReadPlanWritePlan的设计元素
- 读取类文件时应该同时读取继承的基类文件但注意不要去阅读BaseBOService里的代码
- 不要去读VoConverter、DtoConverter、 BaseDtoConverter、BaseVoConverter的代码
#### 5.2 代码编写
- 对于校验规则先判断是否为业务不变性规则如果是则将代码写在BO对象的聚合校验函数中即可实现校验功能不需要在Controller或Service中单独调用校验方法。聚合校验函数中适合做内存中数据的规则校验不适合做很重的外部存储数据的获取或RPC调用乐观锁字段由系统维护无需校验
- 需要着重考虑单一职责原则、复用性如Controller中更适合做参数校验及简单的不可复用的逻辑分支处理不适合实现复杂的或通用的业务逻辑
- 在循环中需要尽量避免执行调用数据库的操作,如查询数据库、写数据库等,尽量在循环外层先获取数据,在循环里面进行数据处理或读取
- 提高代码的可以读性复杂的业务逻辑需要拆解成多个函数一个函数的代码一般不要超过30行
- 如果代码中需要抛出异常则统一抛出IgnoredException(code, "message")异常如throw new IgnoredException(400, "xxx");code=400一般表示参数错误code=500一般表示处理出现错误。同时增加import com.vs.ox.common.exception.IgnoredException;
- 写代码时请注意BOService一般是用于写QueryService一般是用于读
- 输出代码前请仔细检查是否有错误的import如果有则将其修正
- 对于无法识别或直接生成的参数和逻辑,请增加一个相关的//TODO注释把从需求中解析到的可能的处理逻辑以java伪代码的形式写在注释中
- BoService 函数中的 boResult.getRootBo() 一定存在不要添加判断null的情况的代码; 不要添加调用rootBo.persist()的代码该方法的触发由生成的代码负责在BoService的函数中不要修改和注销系统生成的代码通过/** This block is generated by vs **/注释标注部分)
- 在函数中的不同片段逻辑,使用 {} 标注分块,附上注释,提升代码的可读性
- 以准确性作为第一优先级(不产生编译错误),不要直接生成不存在的函数、字段的调用; 如果逻辑上必须依赖,可以使用注释来表达
- 写代码时,如果发现有用户指定的上下文,则优先判断是否有可用的代码;如果用户有编写代码的特殊要求,则优先满足用户需求;如果前面已经有过规划信息,则尽量按照之前的规划来做,比如业务不变性的分析等
- 对于写服务的代码插入遵循如下规则: 1、 controller里插入入参的校验部分逻辑和参数重组逻辑 2、其他的逻辑在主BoService的主函数里为了增加代码可读性可以在BoService里新增函数
- 请在最后对所有你新增或修改的代码进行一次review重点关注是否存在编译错误代码可读性是否需要对大的函数进行拆分重构