kcode-pi 0.1.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/README.md +358 -0
- package/dist/cli/kcode.d.ts +15 -0
- package/dist/cli/kcode.js +153 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +7 -0
- package/docs/KCODE_DISTRIBUTION.md +91 -0
- package/extensions/kingdee-harness.ts +180 -0
- package/extensions/kingdee-header.ts +122 -0
- package/extensions/kingdee-tools.ts +379 -0
- package/knowledge/.backup/v1.0.0/version.json +10 -0
- package/knowledge/cangqiong/product-notes.md +15 -0
- package/knowledge/common/business-flows.md +115 -0
- package/knowledge/common/config-guides.md +110 -0
- package/knowledge/common/error-patterns.md +170 -0
- package/knowledge/common/implementation.md +144 -0
- package/knowledge/cosmic/hard-constraints.md +38 -0
- package/knowledge/cosmic/ksql-datafix.md +34 -0
- package/knowledge/cosmic/platform-baseline.md +32 -0
- package/knowledge/cosmic/plugin-decision-matrix.md +40 -0
- package/knowledge/cosmic/review-checklist.md +40 -0
- package/knowledge/cosmic/unittest.md +35 -0
- package/knowledge/enterprise/api-reference.md +186 -0
- package/knowledge/enterprise/code-patterns.md +217 -0
- package/knowledge/enterprise/plugin-lifecycle.md +188 -0
- package/knowledge/enterprise/tables.json +159 -0
- package/knowledge/flagship/api-reference.md +237 -0
- package/knowledge/flagship/code-patterns.md +246 -0
- package/knowledge/flagship/cosmic-platform-note.md +15 -0
- package/knowledge/flagship/plugin-lifecycle.md +248 -0
- package/knowledge/flagship/tables.json +159 -0
- package/knowledge/version.json +10 -0
- package/knowledge/xinghan/product-notes.md +15 -0
- package/package.json +71 -0
- package/prompts/kd-discuss.md +11 -0
- package/prompts/kd-execute.md +12 -0
- package/prompts/kd-plan.md +12 -0
- package/prompts/kd-ship.md +12 -0
- package/prompts/kd-spec.md +12 -0
- package/prompts/kd-verify.md +12 -0
- package/skills/kd-check/SKILL.md +26 -0
- package/skills/kd-cosmic-dev/SKILL.md +82 -0
- package/skills/kd-cosmic-review/SKILL.md +90 -0
- package/skills/kd-cosmic-unittest/SKILL.md +92 -0
- package/skills/kd-debug/SKILL.md +30 -0
- package/skills/kd-discuss/SKILL.md +24 -0
- package/skills/kd-execute/SKILL.md +22 -0
- package/skills/kd-gen/SKILL.md +34 -0
- package/skills/kd-ksql/SKILL.md +86 -0
- package/skills/kd-plan/SKILL.md +24 -0
- package/skills/kd-ship/SKILL.md +22 -0
- package/skills/kd-spec/SKILL.md +24 -0
- package/skills/kd-verify/SKILL.md +22 -0
- package/themes/kcode-dark.json +81 -0
- package/vendor/kingdee-skills/cosmic-unittest/SKILL.md +788 -0
- package/vendor/kingdee-skills/cosmic-unittest/author-cache.json +5 -0
- package/vendor/kingdee-skills/cosmic-unittest/cosmic-unittest-skill-overview.html +746 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/business-test.md +205 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/common-test.md +257 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/formplugin-test.md +560 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/op-plugin-test.md +231 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/validator-test.md +232 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/business-helper.md +184 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/common-module.md +355 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/convert-plugin.md +130 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/formplugin.md +235 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/op-plugin.md +226 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/validator.md +206 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +674 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/advanced-scenario-checklist.md +307 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/algox-performance-checklist.md +129 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/coding-standard-checklist.md +491 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/cosmic-api-checklist.md +285 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-access-checklist.md +261 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-transaction-checklist.md +390 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/domain-logic-checklist.md +295 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/form-plugin-checklist.md +508 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/infra-checklist.md +254 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ksql-checklist.md +305 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/lifecycle-checklist.md +298 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/operation-plugin-checklist.md +442 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/test-mock-checklist.md +120 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ui-performance-checklist.md +320 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +336 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +121 -0
- package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +295 -0
- package/vendor/kingdee-skills/ok-cosmic/README.md +460 -0
- package/vendor/kingdee-skills/ok-cosmic/SKILL.md +287 -0
- package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +17 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BatchImportPluginTemplate.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BillPlugInTemplate.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ConvertPlugInTemplate.java +255 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/FormPluginTemplate.java +597 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/IWorkflowPluginTemplate.java +91 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ListPluginTemplate.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpPluginTemplate.java +201 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpenApiControllerTemplate.java +103 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/PrintPluginTemplate.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportFormPluginTemplate.java +257 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportListDataPluginTemplate.java +70 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/StandardTreeListPluginTemplate.java +130 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TaskTemplate.java +80 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TreeListPluginTemplate.java +152 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/WriteBackPlugInTemplate.java +286 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/attachment/AttachmentUploadBindSample.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/BotpTracePushSample.java +168 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/SampleConvertPlugin.java +223 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/cache/SampleCacheUsage.java +218 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/concurrent/SampleThreadPoolBatch.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectCrudSample.java +205 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectOpsSample.java +100 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/BeforeOperationConfirmSample.java +217 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ConfirmDialogSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/EntryRowCalculateSample.java +116 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/F7FilterSample.java +134 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/GetAndSetValueSample.java +176 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/HyperlinkJumpSample.java +124 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/OpenBillModalSample.java +253 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ReturnParentDataSample.java +295 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/TreeControlSample.java +140 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ViewControlOpsSample.java +132 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPluginBasicSample.java +170 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPreOpenFilterSample.java +68 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/message/MessageNotifySample.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/SampleMQConsumer.java +198 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/sample_mq.xml +15 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OpAddValidatorsSample.java +137 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OperationOptionBridgeSample.java +228 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/package-info.java +19 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BaseDataQuerySample.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BatchQuerySample.java +368 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/DataSetQueryStatSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportFormPlugin.java +179 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportListDataPlugin.java +616 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/snippets-guide.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/task/ScheduleTaskSample.java +160 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/workflow/SampleWorkflowPlugin.java +302 -0
- package/vendor/kingdee-skills/ok-cosmic/manifest.json +78 -0
- package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +903 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/attachment-api.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/botp-convert.md +98 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/dynamic-object.md +113 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/entity-metadata.md +123 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/event-lifecycle.md +184 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/flex-prop.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/form-utils.md +133 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/operate-chain.md +159 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/plugin-base.md +218 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/query-dataset.md +149 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/request-context.md +88 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/view-handler.md +157 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-bill.md +76 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-botp.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-form.md +165 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-import.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-list.md +227 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-openapi.md +112 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-operation.md +135 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-print.md +65 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-data.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-form.md +90 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-task.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-tree-list.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-workflow.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-writeback.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-algo.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-cache.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-model-svc.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-object.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-entity-model.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-exception.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-file.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-id.md +47 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-lock.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-log.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-network-control.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-orm-access.md +78 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-request-context.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-threadpool.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-tx.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-utils.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/requirements.txt +2 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +24 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +48 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/cheat-sheet.md +256 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +140 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +222 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +94 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/platform-baseline.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +109 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +204 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +910 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +359 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +181 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +389 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +856 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +262 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +293 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +2 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +393 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +176 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +375 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +434 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +36 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +186 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +40 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +142 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-commons.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-features.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic-docs.db +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic.json +13 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +18 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +53 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
- package/vendor/kingdee-skills/ok-ksql/SKILL.md +81 -0
- package/vendor/kingdee-skills/ok-ksql/agents/openai.yaml +7 -0
- package/vendor/kingdee-skills/ok-ksql/manifest.json +14 -0
- package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +452 -0
- package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +363 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# 内存计算框架 (DataSet / Algo)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:`DataSet` 内存计算、过滤、聚合、Join 和流式处理。
|
|
5
|
+
- 先抓:`DataSet` 是流式资源,做完 `select/filter/groupBy` 后记得关闭。
|
|
6
|
+
- 跳转:如果只是简单 ORM 取数,先读 `sdk-orm-access.md` 或 `adv/query-dataset.md`。
|
|
7
|
+
- 继续读全文:当你要写聚合、HashJoin 或高性能数据转换时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
Algo 是苍穹平台的内存计算引擎,遵循 SQL-92 标准,提供类 SQL 的数据处理能力。`DataSet` 是其核心数据结构,采用流式处理(Pipeline),具备严格的内存控制和磁盘交换机制,能有效防止大数据量处理时的 OOM。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.algo.DataSet`**: 核心结果集接口,支持转换(Transform)和动作(Action)。
|
|
14
|
+
- **`kd.bos.algo.Row`**: 行数据访问器(注意:Row 是虚对象,不可缓存)。
|
|
15
|
+
- **`kd.bos.algo.Algo`**: 算法引擎入口。
|
|
16
|
+
- **`kd.bos.algo.GroupbyDataSet`**: 分组聚合构造器。
|
|
17
|
+
- **`kd.bos.algo.JoinDataSet`**: 数据连接构造器。
|
|
18
|
+
- **`kd.bos.algo.HashTable`**: 内存哈希表,用于高性能 HashJoin。
|
|
19
|
+
|
|
20
|
+
## 常用 API 方法
|
|
21
|
+
### 1. 转换 (Transform) - 返回新 DataSet
|
|
22
|
+
- `select(String fields)`: 选择或重命名字段。
|
|
23
|
+
- `addField(String expression, String alias)`: 增加计算字段。
|
|
24
|
+
- `where(String filter)`: SQL 风格过滤。
|
|
25
|
+
- `groupBy(String[] fields)`: 分组,后接聚合操作。
|
|
26
|
+
- `orderBy(String orderBys)`: 排序。
|
|
27
|
+
- `union(DataSet other)`: 合并数据集。
|
|
28
|
+
- `copy()`: 复制数据集(支持多次遍历)。
|
|
29
|
+
|
|
30
|
+
### 2. 动作 (Action) - 消费并关闭 DataSet
|
|
31
|
+
- `count()`: 获取总行数。
|
|
32
|
+
- `cache(CacheHint hint)`: 缓存到 Redis,支持分页读取。
|
|
33
|
+
- `toCollection()`: 转为 `DynamicObjectCollection` (慎用)。
|
|
34
|
+
|
|
35
|
+
## 示例代码
|
|
36
|
+
### 1. 基础转换与聚合
|
|
37
|
+
```java
|
|
38
|
+
try (DataSet ds = QueryServiceHelper.queryDataSet("key", "entity", "id, qty, price", null, null)) {
|
|
39
|
+
DataSet result = ds.addField("qty * price", "amount")
|
|
40
|
+
.where("amount > 1000")
|
|
41
|
+
.groupBy(new String[]{"id"})
|
|
42
|
+
.sum("amount", "total")
|
|
43
|
+
.finish();
|
|
44
|
+
while (result.hasNext()) {
|
|
45
|
+
Row row = result.next();
|
|
46
|
+
// 处理结果...
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. 高性能 HashJoin
|
|
52
|
+
```java
|
|
53
|
+
HashTable detailTable = dsDetail.toHashTable("order_id");
|
|
54
|
+
DataSet joined = dsHeader.hashJoin(detailTable, "id", new String[]{"qty", "price"}, true);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 实践建议
|
|
58
|
+
1. **优先使用 DataSet**:在处理报表、大批量计算或跨库关联时,应彻底弃用 `DynamicObject`,转为 `DataSet` 编程。
|
|
59
|
+
2. **资源释放**:必须使用 `try-with-resources` 或 `AlgoContext` 确保 `DataSet` 及时关闭。
|
|
60
|
+
3. **及早过滤**:在 `join` 或 `groupBy` 之前先 `where`,减少中间数据集规模。
|
|
61
|
+
4. **大表驱动小表**:在使用普通 `join` 时,尽量将较小的表放在右侧(右侧优先物化并判断规模)。
|
|
62
|
+
|
|
63
|
+
## 常见坑位
|
|
64
|
+
1. **流式单次遍历**:`DataSet` 默认只能遍历一遍,若需二次遍历,必须先调用 `copy()` 或 `cache()`。
|
|
65
|
+
2. **跨线程禁止**:`DataSet` 绑定了创建线程的资源,严禁跨线程传递和使用。
|
|
66
|
+
3. **字段引用**:在 `join` 后的 `select` 中,若两表有同名列,必须带上表别名,如 `orders.billno`。
|
|
67
|
+
4. **Row 缓存**:严禁将 `ds.next()` 返回的 `Row` 对象存入外部 List 中,因为它只是一个指向当前行数据的游标。
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# 缓存服务 (Cache Service)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:页面缓存和应用缓存,解决跨操作临时数据与应用级共享数据。
|
|
5
|
+
- 先抓:表单内优先 `IPageCache`,跨页面/应用再用 `AppCache`。
|
|
6
|
+
- 跳转:并发互斥不是缓存,去锁或网控文档;持久化数据也不是本页。
|
|
7
|
+
- 继续读全文:当你要确认作用域、有效期、示例和常见误用时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
金蝶云苍穹提供了分布式缓存服务,支持跨微服务节点的数据共享。根据数据的生命周期和隔离级别,主要分为**页面缓存**(随表单关闭而销毁)和**应用缓存**(按应用隔离,支持自定义有效期)。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.form.IPageCache`**: 页面级缓存接口,仅限表单插件使用。
|
|
14
|
+
- **`kd.bos.entity.cache.AppCache`**: 获取应用级缓存的工具类。
|
|
15
|
+
- **`kd.bos.entity.cache.IAppCache`**: 应用级缓存接口。
|
|
16
|
+
|
|
17
|
+
## 常用 API 方法
|
|
18
|
+
### 页面缓存 (this.getPageCache())
|
|
19
|
+
- `put(String key, String value)`: 存入单条数据。
|
|
20
|
+
- `put(Map<String, String> values)`: 批量存入。
|
|
21
|
+
- `get(String key)`: 读取数据。
|
|
22
|
+
|
|
23
|
+
### 应用缓存 (AppCache.get("appId"))
|
|
24
|
+
- `put(String key, Object value)`: 存入数据,默认 1 小时过期。
|
|
25
|
+
- `put(String key, Object value, int seconds)`: 存入带自定义过期时间的数据。
|
|
26
|
+
- `get(String key, Class<T> clazz)`: 类型安全地读取数据。
|
|
27
|
+
- `remove(String key)`: 显式移除缓存。
|
|
28
|
+
|
|
29
|
+
## 示例代码
|
|
30
|
+
```java
|
|
31
|
+
// 1. 页面缓存示例(在表单插件中)
|
|
32
|
+
public class MyFormPlugin extends AbstractFormPlugin {
|
|
33
|
+
public void cacheTempData() {
|
|
34
|
+
this.getPageCache().put("temp_token", "ABC-123");
|
|
35
|
+
String token = this.getPageCache().get("temp_token");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 2. 应用缓存示例(通用场景)
|
|
40
|
+
import kd.bos.entity.cache.AppCache;
|
|
41
|
+
import kd.bos.entity.cache.IAppCache;
|
|
42
|
+
|
|
43
|
+
public class CacheDemo {
|
|
44
|
+
public void handleAppCache() {
|
|
45
|
+
IAppCache cache = AppCache.get("my_app_id");
|
|
46
|
+
// 存入缓存,有效期 10 分钟
|
|
47
|
+
cache.put("user_config", configObj, 600);
|
|
48
|
+
|
|
49
|
+
// 读取缓存
|
|
50
|
+
MyConfig config = cache.get("user_config", MyConfig.class);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 实践建议
|
|
56
|
+
1. **优先批量操作**:缓存访问虽然快,但高频的网络交互仍有开销,存入多条数据时优先使用批量接口。
|
|
57
|
+
2. **应用编码隔离**:调用 `AppCache.get()` 时,务必传入正确的 `appId`,以实现各应用间的数据隔离。
|
|
58
|
+
3. **及时释放**:对于不再需要的应用缓存,应主动调用 `remove`,防止缓存堆积。
|
|
59
|
+
|
|
60
|
+
## 常见坑位
|
|
61
|
+
1. **缓存一致性**:由于是分布式缓存,注意在多节点并发更新同一 Key 时可能产生的数据覆盖问题。
|
|
62
|
+
2. **序列化要求**:存入 `AppCache` 的对象必须支持序列化(实现 `Serializable` 接口)。
|
|
63
|
+
3. **大小限制**:严禁将超大对象(如数万行的 List)放入缓存,这会显著增加网络传输和 Redis 内存压力。
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# 动态领域模型 - 公共服务 (ServiceHelpers 全集)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:各种 `ServiceHelper` 的快速索引,含存取、操作、编号、基础资料和微服务分发。
|
|
5
|
+
- 先抓:按场景先选对 Helper,再决定是否继续查具体签名。
|
|
6
|
+
- 跳转:若已知道确切 Helper 或要用团队封装,优先看 `adv` 文档或脚本验证。
|
|
7
|
+
- 继续读全文:当你要找公共服务入口、典型示例或跨微服务调用方式时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
苍穹平台提供了一系列 ServiceHelper,作为分布式环境下的基础工具类。它们封装了复杂的跨服务调用,使开发者能够以本地静态调用的方式完成数据存取、元数据获取、业务操作触发、编码生成及微服务调用。
|
|
11
|
+
|
|
12
|
+
## 核心类与用途
|
|
13
|
+
| 分类 | 核心类 | 说明 |
|
|
14
|
+
| :--- | :--- | :--- |
|
|
15
|
+
| **数据存取** | `BusinessDataServiceHelper` | 结构化对象加载(含缓存、主子表)。 |
|
|
16
|
+
| **数据查询** | `QueryServiceHelper` | 轻量级查询、DataSet 获取。 |
|
|
17
|
+
| **持久化操作** | `SaveServiceHelper` / `DeleteServiceHelper` | 物理层的数据新增、修改、物理/逻辑删除。 |
|
|
18
|
+
| **业务逻辑** | `OperationServiceHelper` | 执行单据生命周期操作(审核、提交等)。 |
|
|
19
|
+
| **编码/规则** | `CodeRuleServiceHelper` | 自动生成符合编码规则的单据编号。 |
|
|
20
|
+
| **基础资料** | `BaseDataServiceHelper` | 基础资料的分配、自动补值及权限过滤。 |
|
|
21
|
+
| **跨微服务** | `DispatchServiceHelper` | 调用其他微服务、二开服务或平台服务。 |
|
|
22
|
+
| **系统/环境** | `SystemParamServiceHelper` / `TimeServiceHelper` | 获取系统参数、全局统一时间。 |
|
|
23
|
+
|
|
24
|
+
## 常用 API 方法
|
|
25
|
+
|
|
26
|
+
### 1. 编码规则 (CodeRuleServiceHelper)
|
|
27
|
+
- `getNumber(String entityId, DynamicObject data)`: 获取单据编号。
|
|
28
|
+
- `getBatchCodes(String entityId, int count)`: 批量获取编码。
|
|
29
|
+
|
|
30
|
+
### 2. 基础资料分配与补值 (BaseDataServiceHelper)
|
|
31
|
+
- `assign(String entityId, long[] ids, long[] orgIds)`: 将基础资料分配到目标组织。
|
|
32
|
+
- `queryBaseDataFromCache(...)`: 高性能获取基础资料字段值。
|
|
33
|
+
|
|
34
|
+
### 3. 微服务分发与工厂 (DispatchServiceHelper / ServiceFactory)
|
|
35
|
+
- **调用业务微服务**: `DispatchServiceHelper.invokeBizService(cloud, app, svc, method, args)`。
|
|
36
|
+
- **调用二开服务**: `DispatchServiceHelper.invokeService(factory, app, svc, method, args)`。
|
|
37
|
+
- **自定义工厂模式**:
|
|
38
|
+
```java
|
|
39
|
+
public class ServiceFactory {
|
|
40
|
+
public static Object getService(String serviceName) {
|
|
41
|
+
String impl = "com.isv.mservice.impl." + serviceName + "Impl";
|
|
42
|
+
return TypesContainer.getOrRegisterSingletonInstance(impl);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 4. 数据删除 (DeleteServiceHelper)
|
|
48
|
+
- `delete(String entityId, Object[] ids)`: 物理删除。
|
|
49
|
+
- `deleteOperate(...)`: 执行删除操作(触发删除插件)。
|
|
50
|
+
|
|
51
|
+
### 5. 系统参数 (SystemParamServiceHelper)
|
|
52
|
+
- `getValue(String paramKey)`: 获取全局参数。
|
|
53
|
+
- `getValue(String paramKey, long orgId)`: 获取组织隔离的参数值。
|
|
54
|
+
|
|
55
|
+
## 示例代码
|
|
56
|
+
### 1. 自动生成单据编号
|
|
57
|
+
```java
|
|
58
|
+
// 创建新对象并自动根据规则填入编号
|
|
59
|
+
DynamicObject bill = BusinessDataServiceHelper.newDynamicObject("my_entity");
|
|
60
|
+
String billNo = CodeRuleServiceHelper.getNumber("my_entity", bill);
|
|
61
|
+
bill.set("billno", billNo);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. 调用外部微服务
|
|
65
|
+
```java
|
|
66
|
+
// 调用“供应链云”下的“库存服务”
|
|
67
|
+
Object result = DispatchServiceHelper.invokeBizService(
|
|
68
|
+
"scm", "im", "StockService", "queryInventory",
|
|
69
|
+
new Object[]{materialId, orgId}
|
|
70
|
+
);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 实践建议
|
|
74
|
+
1. **优先使用 Helper**:ServiceHelper 系列是苍穹开发的最标准入口,具备良好的事务和权限兼容性。
|
|
75
|
+
2. **时间统一性**:获取业务时间务必使用 `TimeServiceHelper.getSystemDate()`,以保证在集群环境下所有节点的时间严格一致。
|
|
76
|
+
3. **参数缓存**:系统参数读取较为频繁,`SystemParamServiceHelper` 内部已有良好缓存,无需在业务层二次缓存。
|
|
77
|
+
4. **基础资料**:你在处理基础资料(BaseData)相关的业务动作时,请务必先查阅 `BaseDataServiceHelper` 是否已有现成的方法。
|
|
78
|
+
|
|
79
|
+
## 常见坑位
|
|
80
|
+
1. **删除服务误用**:`DeleteServiceHelper.delete` 是物理删除,且不触发任何插件;对于业务单据,建议始终使用 `deleteOperate`。
|
|
81
|
+
2. **跨云调用超时**:使用 `DispatchServiceHelper` 调用时,若目标服务负载过高,可能导致当前线程挂死,建议对不稳定接口增加异步处理。
|
|
82
|
+
3. **编码规则失效**:调用 `getNumber` 前,单据对象中必须包含规则中定义的“条件字段”(如组织、业务类型),否则生成的编码可能不符合预期。
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# 动态领域模型 - 数据包 (DynamicObject)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:原生 `DynamicObject` 读写方式以及基础资料、分录字段访问。
|
|
5
|
+
- 先抓:先理解主子表和基础资料字段在运行时的真实结构。
|
|
6
|
+
- 跳转:更安全的团队推荐写法优先读 `adv/dynamic-object.md`。
|
|
7
|
+
- 继续读全文:当你要写原生 getter/setter、处理基础资料字段或排查类型坑时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
`DynamicObject` 是苍穹平台的核心数据载体,它是实体模型(EntityType)的运行时实例。它采用多层嵌套的数组结构存储数据,能够灵活地表达主子表、基础资料引用等复杂的业务结构。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.dataentity.entity.DynamicObject`**: 单条数据包对象。
|
|
14
|
+
- **`kd.bos.dataentity.entity.DynamicObjectCollection`**: 数据包集合(常用于单据体分录)。
|
|
15
|
+
|
|
16
|
+
## 常用 API 方法
|
|
17
|
+
### 获取值 (Getter)
|
|
18
|
+
- `get(String key)`: 通用取值,返回 `Object`。
|
|
19
|
+
- `getString(String key)` / `getLong(String key)` / `getBigDecimal(String key)`: 类型化取值。
|
|
20
|
+
- `getDynamicObject(String key)`: 获取关联的基础资料或 1:1 属性。
|
|
21
|
+
- `getDynamicObjectCollection(String key)`: 获取单据体分录集合。
|
|
22
|
+
|
|
23
|
+
### 设置值 (Setter)
|
|
24
|
+
- `set(String key, Object value)`: 设置字段值。
|
|
25
|
+
|
|
26
|
+
### 其他
|
|
27
|
+
- `getDataEntityType()`: 获取该数据包对应的元数据模型。
|
|
28
|
+
- `getPkValue()`: 获取该对象的主键值。
|
|
29
|
+
|
|
30
|
+
## 示例代码
|
|
31
|
+
### 1. 存取简单字段与分录
|
|
32
|
+
```java
|
|
33
|
+
// 获取主表字段
|
|
34
|
+
String billNo = bill.getString("billno");
|
|
35
|
+
BigDecimal totalAmt = bill.getBigDecimal("totalamount");
|
|
36
|
+
|
|
37
|
+
// 遍历分录
|
|
38
|
+
DynamicObjectCollection entryRows = bill.getDynamicObjectCollection("entryentity");
|
|
39
|
+
for (DynamicObject row : entryRows) {
|
|
40
|
+
BigDecimal qty = row.getBigDecimal("qty");
|
|
41
|
+
// 修改分录字段
|
|
42
|
+
row.set("amt", qty.multiply(new BigDecimal("10")));
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. 处理基础资料字段 (重要)
|
|
47
|
+
基础资料在 `DynamicObject` 中存有两个 Key:`xxx` (对象) 和 `xxx_id` (内码)。
|
|
48
|
+
```java
|
|
49
|
+
// 获取客户内码
|
|
50
|
+
long customerId = bill.getLong("customer_id");
|
|
51
|
+
// 获取客户对象并读取其编码
|
|
52
|
+
DynamicObject customer = bill.getDynamicObject("customer");
|
|
53
|
+
if (customer != null) {
|
|
54
|
+
String code = customer.getString("number");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 设置基础资料(必须传入 DynamicObject 对象,严禁直接给 customer 键设 ID)
|
|
58
|
+
DynamicObject newCust = BusinessDataServiceHelper.loadSingleFromCache(123456L, "bd_customer");
|
|
59
|
+
bill.set("customer", newCust);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 实践建议
|
|
63
|
+
1. **优先使用内码**:如果只需要 ID 进行过滤或关联,优先读取 `xxx_id` 键,避免触发不必要的对象加载。
|
|
64
|
+
2. **安全取值**:从 `getDynamicObject` 返回的对象可能为 `null`,访问前务必判空。
|
|
65
|
+
3. **性能注意**:`DynamicObject` 是纯内存对象,大批量处理时注意及时清理引用,或改用 `DataSet`。
|
|
66
|
+
|
|
67
|
+
## 常见坑位
|
|
68
|
+
1. **Key 拼写错误**:字段标识必须与表单设计器中的“标识”完全一致,大小写敏感。
|
|
69
|
+
2. **直接修改 Entity 集合**:对 `DynamicObjectCollection` 执行 `add` 或 `remove` 后,若在插件环境,必须确保 UI 能感知变化。
|
|
70
|
+
3. **基础资料设值误区**:执行 `bill.set("customer", 123456L)` 是错误的,这会导致后续代码通过 `getDynamicObject("customer")` 报错。必须先 load 出对象再 set。
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# 动态领域模型 - 实体模型 (Entity Model)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:原生实体模型和字段属性 API,用于动态分析主表、分录和基础资料字段。
|
|
5
|
+
- 先抓:`MainEntityType` / `FieldProp` / `EntryProp` 这组类型层级。
|
|
6
|
+
- 跳转:团队封装优先读 `adv/entity-metadata.md`;只处理数据值不必读本页。
|
|
7
|
+
- 继续读全文:当你要遍历字段元数据、判断字段类型或拿属性特征时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
实体模型(Entity Model)是苍穹平台对现实世界业务对象的抽象定义。它类似于 Java 中的“类”定义,规定了数据包(DynamicObject)的结构、字段类型、字段标识及字段间的关系(如主子表)。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.entity.MainEntityType`**: 所有实体的基类。
|
|
14
|
+
- **`kd.bos.entity.BillEntityType`**: 业务单据实体模型。
|
|
15
|
+
- **`kd.bos.entity.BasedataEntityType`**: 基础资料实体模型。
|
|
16
|
+
- **`kd.bos.entity.EntryType`**: 单据体(分录)实体模型。
|
|
17
|
+
- **`kd.bos.entity.property.FieldProp`**: 简单字段属性基类(如文本、数值)。
|
|
18
|
+
- **`kd.bos.entity.property.BasedataProp`**: 基础资料字段属性(复杂属性,指向另一个实体)。
|
|
19
|
+
- **`kd.bos.entity.property.EntryProp`**: 分录字段属性(集合属性,包含多行子数据)。
|
|
20
|
+
|
|
21
|
+
## 常用 API 方法
|
|
22
|
+
### 获取属性
|
|
23
|
+
- `getProperties()`: 获取实体的所有属性集合。
|
|
24
|
+
- `getProperty(String name)`: 根据字段标识获取属性对象。
|
|
25
|
+
- `getPrimaryKey()`: 获取主键属性。
|
|
26
|
+
|
|
27
|
+
### 属性特征访问
|
|
28
|
+
- `prop.getName()`: 获取字段标识(Key)。
|
|
29
|
+
- `prop.getAlias()`: 获取数据库字段名(Alias)。
|
|
30
|
+
- `prop.getDataType()`: 获取字段的物理数据类型。
|
|
31
|
+
|
|
32
|
+
## 示例代码
|
|
33
|
+
### 1. 遍历实体字段元数据
|
|
34
|
+
```java
|
|
35
|
+
MainEntityType entityType = MetadataServiceHelper.getDataEntityType("my_entity_id");
|
|
36
|
+
// 获取所有字段并打印其显示名称
|
|
37
|
+
for (IDataEntityProperty prop : entityType.getProperties()) {
|
|
38
|
+
String displayName = prop.getDisplayName().getLocaleValue();
|
|
39
|
+
String key = prop.getName();
|
|
40
|
+
System.out.println(key + " : " + displayName);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. 动态判断字段类型
|
|
45
|
+
```java
|
|
46
|
+
IDataEntityProperty prop = entityType.getProperty("customer");
|
|
47
|
+
if (prop instanceof BasedataProp) {
|
|
48
|
+
String baseEntityId = ((BasedataProp) prop).getBaseEntityId();
|
|
49
|
+
// 该字段是一个指向 baseEntityId 的基础资料
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 实践建议
|
|
54
|
+
1. **标识驱动**:在代码中访问数据时,务必使用 `prop.getName()`(标识),严禁硬编码 `prop.getAlias()`(数据库物理名),以保证模型的解耦。
|
|
55
|
+
2. **元数据缓存**:虽然平台有二级缓存,但在高频循环中建议将 `MainEntityType` 对象提取到循环外。
|
|
56
|
+
3. **区分分录**:通过 `prop instanceof EntryProp` 快速识别单据体字段,并递归处理子实体的元数据。
|
|
57
|
+
|
|
58
|
+
## 常见坑位
|
|
59
|
+
1. **同名冲突**:在主表和分录中可能存在标识相同的字段,获取属性时注意 `entityType` 所在的层级。
|
|
60
|
+
2. **多语言取值**:`prop.getDisplayName()` 返回的是多语言对象,必须调用 `getLocaleValue()` 才能获取当前语种的字符串。
|
|
61
|
+
3. **主键识别**:部分虚实体可能没有物理主键,调用 `getPrimaryKey()` 可能返回 null。
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# 异常处理 (Exception Handling)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:平台异常体系、错误码定义、多语言异常抛出与封装。
|
|
5
|
+
- 先抓:业务异常统一走 `KDException` / `ErrorCode`,先区分业务错误和系统错误。
|
|
6
|
+
- 跳转:日志记录不是本页;事务回滚边界要配合操作/事务文档一起看。
|
|
7
|
+
- 继续读全文:当你要定义错误码类、封装底层异常或规范前端提示时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
苍穹平台提供了统一的异常处理规范,要求所有的业务和系统异常均通过 `KDException` 或其子类进行表达。核心原则是:统一异常类型、错误码全局唯一、多语言支持以及精准的异常捕获。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.exception.KDException`**: 平台所有异常的基类。
|
|
14
|
+
- **`kd.bos.exception.KDBizException`**: 业务逻辑异常(通常直接继承自 `KDException`,用于在前端显示友好提示)。
|
|
15
|
+
- **`kd.bos.exception.ErrorCode`**: 错误码定义类,包含唯一的错误代码和多语言消息模板。
|
|
16
|
+
|
|
17
|
+
## 常用 API 方法
|
|
18
|
+
- `new ErrorCode(String code, String message)`: 构造错误码。格式建议:`云.应用.变量名`。
|
|
19
|
+
- `new KDException(ErrorCode code, Object... args)`: 抛出带错误码和格式化参数的异常。
|
|
20
|
+
- `new KDException(Throwable cause, ErrorCode code, Object... args)`: 封装原始异常并抛出。
|
|
21
|
+
- `exception.getErrorCode()`: 获取异常中的错误码对象。
|
|
22
|
+
|
|
23
|
+
## 示例代码
|
|
24
|
+
### 1. 定义错误码类
|
|
25
|
+
```java
|
|
26
|
+
public class MyModuleErrorCode {
|
|
27
|
+
private static ErrorCode create(String code, String message) {
|
|
28
|
+
return new ErrorCode("my.module." + code, message);
|
|
29
|
+
}
|
|
30
|
+
// 使用 %s 作为动态参数占位符
|
|
31
|
+
public final static ErrorCode orderNotFound = create("orderNotFound", "订单【%s】不存在或已删除。");
|
|
32
|
+
public final static ErrorCode dataProcessError = create("dataProcessError", "数据处理失败:%s");
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. 抛出与捕获异常
|
|
37
|
+
```java
|
|
38
|
+
public void processOrder(String billNo) {
|
|
39
|
+
if (StringUtils.isBlank(billNo)) {
|
|
40
|
+
// 直接抛出业务异常
|
|
41
|
+
throw new KDBizException(MyModuleErrorCode.orderNotFound, billNo);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
doComplexTask();
|
|
46
|
+
} catch (KDException e) {
|
|
47
|
+
// 关注的业务异常,再次往上抛(无需记录日志,平台会自动处理显示)
|
|
48
|
+
throw e;
|
|
49
|
+
} catch (Exception e) {
|
|
50
|
+
// 系统级异常(如网络、IO),封装为业务异常再抛出,并可在此记录日志
|
|
51
|
+
throw new KDException(e, MyModuleErrorCode.dataProcessError, e.getMessage());
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 实践建议
|
|
57
|
+
1. **业务异常优先**:业务逻辑校验失败时,应优先抛出 `KDBizException`,这样前端会自动拦截并以友好弹窗形式展示 `message`。
|
|
58
|
+
2. **错误码规范**:错误码应保持产品全局唯一,且对应的消息应在多语言资源文件中配置。
|
|
59
|
+
3. **按需捕获**:只 catch 那些你真正需要处理(如回滚、补偿、转换)的异常,其他异常任其向上抛出到框架层统一处理。
|
|
60
|
+
|
|
61
|
+
## 常见坑位
|
|
62
|
+
1. **吞掉异常不记录日志**:如果 catch 了异常且没有再次抛出,必须使用 `LogFactory` 记录详细堆栈,否则问题将极难定位。
|
|
63
|
+
2. **UI 显示非业务语言**:严禁直接将 `SQLException` 等底层堆栈信息抛给前端展示,必须封装为用户可理解的业务语义。
|
|
64
|
+
3. **乱用 Exception 基类**:尽量避免直接 `throw new Exception()`,这会导致框架无法精准区分系统错误和业务校验。
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# 文件服务 (File Service)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:物理文件上传、下载、删除以及图片/附件文件服务。
|
|
5
|
+
- 先抓:先选对 `FileServiceFactory` 提供的具体文件服务,再做流操作。
|
|
6
|
+
- 跳转:如果文件还要挂到业务附件面板,优先读 `adv/attachment-api.md`。
|
|
7
|
+
- 继续读全文:当你要确认文件对象、上传下载代码或清理策略时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
文件服务用于在苍穹平台中存储、下载和管理物理文件(如单据附件、单据图片)。它支持高可用部署,并提供统一的 SDK 接口,屏蔽了底层存储介质(文件服务器、S3、OSS 等)的差异。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.fileservice.FileServiceFactory`**: 获取文件服务的工厂类。
|
|
14
|
+
- **`kd.bos.fileservice.FileService`**: 执行文件操作的核心接口。
|
|
15
|
+
- **`kd.bos.fileservice.FileItem`**: 代表一个待上传的文件对象(包含文件名、输入流等)。
|
|
16
|
+
|
|
17
|
+
## 常用 API 方法
|
|
18
|
+
### 获取服务
|
|
19
|
+
- `FileServiceFactory.getAttachmentFileService()`: 获取通用的附件存储服务。
|
|
20
|
+
- `FileServiceFactory.getImageFileService()`: 获取专用的图片存储服务。
|
|
21
|
+
|
|
22
|
+
### 文件操作
|
|
23
|
+
- `upload(FileItem item)`: 上传文件,返回文件在服务器上的唯一 URL(路径)。
|
|
24
|
+
- `download(String url)`: 下载文件,返回文件字节数组。
|
|
25
|
+
- `getInputStream(String url)`: 获取文件的输入流(适用于大文件)。
|
|
26
|
+
- `delete(String url)`: 物理删除服务器上的文件。
|
|
27
|
+
- `preview(String url)`: 获取文件预览地址。
|
|
28
|
+
|
|
29
|
+
## 示例代码
|
|
30
|
+
```java
|
|
31
|
+
import kd.bos.fileservice.FileService;
|
|
32
|
+
import kd.bos.fileservice.FileServiceFactory;
|
|
33
|
+
import kd.bos.fileservice.FileItem;
|
|
34
|
+
import java.io.InputStream;
|
|
35
|
+
|
|
36
|
+
public class FileDemo {
|
|
37
|
+
public String uploadFile(String fileName, InputStream is) {
|
|
38
|
+
// 1. 获取附件服务
|
|
39
|
+
FileService fs = FileServiceFactory.getAttachmentFileService();
|
|
40
|
+
|
|
41
|
+
// 2. 构造上传对象
|
|
42
|
+
FileItem item = new FileItem(fileName, is);
|
|
43
|
+
|
|
44
|
+
// 3. 执行上传并返回 URL
|
|
45
|
+
return fs.upload(item);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public void deleteFile(String fileUrl) {
|
|
49
|
+
FileService fs = FileServiceFactory.getAttachmentFileService();
|
|
50
|
+
fs.delete(fileUrl);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 实践建议
|
|
56
|
+
1. **区分场景**:普通的业务附件使用 `getAttachmentFileService`;如果是单据上的头像、商品图片,建议使用 `getImageFileService`,以便平台执行特定的缩略图优化。
|
|
57
|
+
2. **资源释放**:通过 `getInputStream` 获取流后,务必在 `finally` 块或 `try-with-resources` 中手动关闭。
|
|
58
|
+
3. **URL 存储**:上传成功返回的 `url` 是访问该文件的唯一凭证,应将其保存到单据对应的附件表或字段中。
|
|
59
|
+
|
|
60
|
+
## 常见坑位
|
|
61
|
+
1. **文件后缀**:上传时 `FileItem` 的文件名后缀应准确,否则可能导致预览(`preview`)功能失效。
|
|
62
|
+
2. **URL 格式**:存储和传递 URL 时,不要随意拼凑,应保持 `fs.upload` 返回的原始字符串。
|
|
63
|
+
3. **权限控制**:物理删除(`delete`)操作不可逆,执行前务必在业务层做好权限校验。
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# 分布式 ID (Distributed ID)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:生成全局唯一主键或业务唯一 ID。
|
|
5
|
+
- 先抓:`ID.genLongId()` 是最常用入口,类型要与数据库字段匹配。
|
|
6
|
+
- 跳转:如果你要的是业务编码而不是主键,去 `CodeRuleServiceHelper` 文档。
|
|
7
|
+
- 继续读全文:当你要批量生成 ID、选择 `String`/`long` 类型或看示例时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
分布式 ID 服务用于在多微服务节点环境下产生全局唯一的 ID 值。它主要用作实体的主键,或其他需要唯一标识的业务场景。该服务具备高性能、趋势有序和高可用的特性。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.id.ID`**: ID 生成的核心工具类。
|
|
14
|
+
|
|
15
|
+
## 常用 API 方法
|
|
16
|
+
- `ID.genLongId()`: 获取单个 `long` 类型 ID(对应 DB 字段 `bigint(19)`)。
|
|
17
|
+
- `ID.genLongIds(int count)`: 一次性获取指定数量的 `long` 类型 ID 数组。
|
|
18
|
+
- `ID.genStringId()`: 获取单个 `String` 类型 ID(对应 DB 字段 `varchar(12)`)。
|
|
19
|
+
- `ID.genStringIds(int count)`: 一次性获取指定数量的 `String` 类型 ID 数组。
|
|
20
|
+
|
|
21
|
+
## 示例代码
|
|
22
|
+
```java
|
|
23
|
+
import kd.bos.id.ID;
|
|
24
|
+
|
|
25
|
+
public class IdDemo {
|
|
26
|
+
public void generateId() {
|
|
27
|
+
// 生成主键 ID
|
|
28
|
+
long billId = ID.genLongId();
|
|
29
|
+
|
|
30
|
+
// 批量生成主键
|
|
31
|
+
long[] batchIds = ID.genLongIds(10);
|
|
32
|
+
|
|
33
|
+
// 生成字符串类型的唯一标识
|
|
34
|
+
String traceId = ID.genStringId();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 实践建议
|
|
40
|
+
1. **主键必选**:凡是苍穹平台的业务实体主键,务必使用 `ID.genLongId()` 生成,不要使用外部随机数或自增 ID。
|
|
41
|
+
2. **批量获取**:在需要大批量创建单据或分录的循环中,建议先调用 `genLongIds` 一次性拿到 ID 数组,以减少内部锁竞争。
|
|
42
|
+
3. **类型匹配**:`long` 类型 ID 是对 `String` 类型进行 Base39 编码后的结果,两者可以互转且保持趋势有序。
|
|
43
|
+
|
|
44
|
+
## 常见坑位
|
|
45
|
+
1. **历史数据转换**:旧系统初始化数据或第三方系统导入的 ID 可能不是通过此服务生成的,强行互转可能导致数据错误。
|
|
46
|
+
2. **种子耗尽风险**:如果微服务节点频繁异常重启且系统时间跳动过大,可能导致 WorkerId 种子用完(上限 8192),此时需要清理 Zookeeper 上的种子节点。
|
|
47
|
+
3. **依赖 DLock**:ID 服务启动时依赖分布式锁(DLock)获取种子,若 Redis/Zookeeper 异常导致锁不可用,ID 服务将无法启动。
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# 分布式锁 (Distributed Lock)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:跨实例并发互斥,需要排他处理共享资源时。
|
|
5
|
+
- 先抓:默认优先可重入锁,并保证在 `finally` 里释放。
|
|
6
|
+
- 跳转:单据编辑互斥更常见的是网控,去 `sdk-network-control.md`。
|
|
7
|
+
- 继续读全文:当你要确认 `tryLock` 策略、示例或防死锁约束时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
分布式锁用于在分布式环境下对共享资源执行排他性操作。它能确保在多个微服务实例并发执行时,同一时刻只有一个线程能持有特定标识的锁。苍穹平台提供不可重入和可重入两种锁类型。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.dlock.DLock`**: 分布式锁的核心管理类。
|
|
14
|
+
|
|
15
|
+
## 常用 API 方法
|
|
16
|
+
- `DLock.create(String lockId, String desc)`: 创建一个不可重入锁。
|
|
17
|
+
- `DLock.createReentrant(String lockId, String desc)`: 创建一个可重入锁(推荐,防止同一线程死锁)。
|
|
18
|
+
- `lock()`: 阻塞式加锁,直到成功为止。
|
|
19
|
+
- `tryLock()`: 尝试加锁,不等待,立即返回成功或失败。
|
|
20
|
+
- `tryLock(long timeout, TimeUnit unit)`: 在指定时间内尝试加锁。
|
|
21
|
+
- `unlock()`: 释放锁。**必须在 finally 块中调用**。
|
|
22
|
+
|
|
23
|
+
## 示例代码
|
|
24
|
+
```java
|
|
25
|
+
import kd.bos.dlock.DLock;
|
|
26
|
+
import java.util.concurrent.TimeUnit;
|
|
27
|
+
|
|
28
|
+
public class LockDemo {
|
|
29
|
+
public void executeWithLock() {
|
|
30
|
+
// 1. 创建锁标识(建议包含模块和业务主键)
|
|
31
|
+
DLock lock = DLock.createReentrant("my_module/order/12345", "订单12345并发锁");
|
|
32
|
+
|
|
33
|
+
// 2. 加锁
|
|
34
|
+
try {
|
|
35
|
+
if (lock.tryLock(5, TimeUnit.SECONDS)) {
|
|
36
|
+
try {
|
|
37
|
+
// 执行排他性业务逻辑
|
|
38
|
+
processBusiness();
|
|
39
|
+
} finally {
|
|
40
|
+
// 3. 释放锁
|
|
41
|
+
lock.unlock();
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
throw new KDBizException("获取锁超时,请稍后重试");
|
|
45
|
+
}
|
|
46
|
+
} catch (InterruptedException e) {
|
|
47
|
+
Thread.currentThread().interrupt();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 实践建议
|
|
54
|
+
1. **优先使用可重入锁**:通过 `createReentrant` 创建的锁可以防止同一线程在嵌套调用中产生的死锁问题。
|
|
55
|
+
2. **Key 命名规范**:锁标识应具备唯一性且易于识别,建议采用 `模块/业务类型/主键ID` 的格式。
|
|
56
|
+
3. **超时控制**:尽量使用 `tryLock` 并设置合理的超时时间,避免因长时间阻塞导致微服务线程池枯竭。
|
|
57
|
+
|
|
58
|
+
## 常见坑位
|
|
59
|
+
1. **忘记释放锁**:如果不在 `finally` 中执行 `unlock()`,一旦业务代码抛出异常,锁将无法及时释放,直到节点心跳超时。
|
|
60
|
+
2. **死锁风险**:不可重入锁在同一个线程内重复调用 `lock()` 会导致永久阻塞。
|
|
61
|
+
3. **宕机延迟释放**:若持有锁的节点崩溃,锁会自动保留直到服务注册中心将其移除(约 5 分钟),期间其他节点可能无法获取该锁。
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# 日志框架 (Logging Framework)
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
- 适用:统一日志记录、级别判断和异常堆栈输出。
|
|
5
|
+
- 先抓:优先 `LogFactory.getLog(Class)`,避免 `System.out.println`。
|
|
6
|
+
- 跳转:如果继承了 Ext 插件基类,先直接用内置 `log` 对象,不必回到本页。
|
|
7
|
+
- 继续读全文:当你要确认参数化日志、异常记录和生产级日志建议时。
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
苍穹平台提供了一套统一的日志处理接口,底层默认基于 Logback 实现。它支持标准的日志级别(DEBUG, INFO, WARN, ERROR),并具备异步写入、链路追踪及集群环境下的统一日志收集能力。
|
|
11
|
+
|
|
12
|
+
## 核心类
|
|
13
|
+
- **`kd.bos.logging.LogFactory`**: 获取日志对象的工厂类。
|
|
14
|
+
- **`kd.bos.logging.Log`**: 日志执行接口。
|
|
15
|
+
|
|
16
|
+
## 常用 API 方法
|
|
17
|
+
### 获取日志实例
|
|
18
|
+
- `LogFactory.getLog(Class<?> clazz)`: 推荐方式,根据类名获取日志对象。
|
|
19
|
+
- `LogFactory.getLog(String name)`: 根据标识名获取。
|
|
20
|
+
|
|
21
|
+
### 级别判断
|
|
22
|
+
- `isDebugEnabled()` / `isInfoEnabled()` / `isWarnEnabled()` / `isErrorEnabled()`
|
|
23
|
+
|
|
24
|
+
### 记录日志
|
|
25
|
+
- `debug(String message, Object... args)`
|
|
26
|
+
- `info(String message, Object... args)`
|
|
27
|
+
- `warn(String message, Object... args)`
|
|
28
|
+
- `error(String message, Throwable t)`: 记录错误及异常堆栈。
|
|
29
|
+
|
|
30
|
+
## 示例代码
|
|
31
|
+
```java
|
|
32
|
+
import kd.bos.logging.Log;
|
|
33
|
+
import kd.bos.logging.LogFactory;
|
|
34
|
+
|
|
35
|
+
public class LogDemo {
|
|
36
|
+
// 1. 定义静态常量日志对象
|
|
37
|
+
private static final Log logger = LogFactory.getLog(LogDemo.class);
|
|
38
|
+
|
|
39
|
+
public void doWork(String billNo) {
|
|
40
|
+
// 2. 先判断级别,再输出(减少字符串拼接开销)
|
|
41
|
+
if (logger.isInfoEnabled()) {
|
|
42
|
+
logger.info("开始处理单据: {}", billNo);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
process();
|
|
47
|
+
} catch (Exception e) {
|
|
48
|
+
// 3. 记录异常堆栈
|
|
49
|
+
logger.error("单据处理失败: " + billNo, e);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 实践建议
|
|
56
|
+
1. **先判断后输出**:输出 DEBUG 或较长的 INFO 日志时,务必包裹在 `isXXXEnabled()` 判断中,以避免在高并发下产生大量的字符串计算开销。
|
|
57
|
+
2. **占位符写法**:推荐使用 `{}` 占位符,而不是手写字符串拼接。
|
|
58
|
+
3. **异常完整记录**:在 `error` 级别中,务必将异常对象 `e` 作为最后一个参数传入,以便记录完整的堆栈信息。
|
|
59
|
+
|
|
60
|
+
## 常见坑位
|
|
61
|
+
1. **`System.out` 滥用**:严禁在生产代码中使用 `System.out.println`,这些输出无法被集中收集和管理。
|
|
62
|
+
2. **循环内输出**:避免在处理几万行的循环内输出大量的日志,这会导致严重的 IO 瓶颈。
|
|
63
|
+
3. **敏感信息泄露**:记录日志时注意脱敏,避免将用户的密码、个人手机号等敏感信息直接打入日志。
|