From 1f346a72ee4ce8d14c3e540386ed184d347e903a Mon Sep 17 00:00:00 2001 From: Nop Assistant Date: Thu, 18 Apr 2024 02:02:34 +0000 Subject: [PATCH] chore: deploy docs of project Nop Entropy via GitHub Actions --- projects/nop-entropy/docs/arch/index.html | 1148 +-------------- .../docs/arch/module-dependency/index.html | 1240 ++--------------- projects/nop-entropy/docs/compare/index.html | 1150 +-------------- .../docs/compare/nop-vs-skyve/index.html | 1240 ++--------------- .../compare/nop-vs-springcloud/index.html | 1240 ++--------------- .../docs/core-code-guidance/index.html | 1240 ++--------------- .../docs/dev-guide/auth/auth/index.html | 1240 ++--------------- .../dev-guide/auth/impersonate/index.html | 1146 +-------------- .../docs/dev-guide/auth/index.html | 1154 +-------------- .../docs/dev-guide/auth/login/index.html | 1194 +--------------- .../dev-guide/auth/service-auth/index.html | 1164 +--------------- .../docs/dev-guide/auth/sso/index.html | 1178 +--------------- .../docs/dev-guide/autotest/index.html | 1240 ++--------------- .../dev-guide/batch/batch-design/index.html | 1152 +-------------- .../docs/dev-guide/batch/batch-gen/index.html | 1140 +-------------- .../dev-guide/batch/batch-task/index.html | 1140 +-------------- .../docs/dev-guide/biz/coderule/index.html | 1240 ++--------------- .../nop-entropy/docs/dev-guide/biz/index.html | 1152 +-------------- .../docs/dev-guide/biz/validate/index.html | 1164 +--------------- .../docs/dev-guide/biz/validator/index.html | 1224 ++-------------- .../nop-entropy/docs/dev-guide/cli/index.html | 1208 +--------------- .../docs/dev-guide/codegen/index.html | 1240 ++--------------- .../docs/dev-guide/command/command/index.html | 1184 +--------------- .../docs/dev-guide/config/index.html | 1240 ++--------------- .../docs/dev-guide/customization/index.html | 1188 +--------------- .../docs/dev-guide/debug/index.html | 1240 ++--------------- .../docs/dev-guide/delta-loader/index.html | 1140 +-------------- .../delta/delta-customization/index.html | 1240 ++--------------- .../docs/dev-guide/dict/index.html | 1188 +--------------- .../docs/dev-guide/error-code/index.html | 1210 +--------------- .../dev-guide/graphql/connection/index.html | 1168 +--------------- .../docs/dev-guide/graphql/crud/index.html | 1240 ++--------------- .../dev-guide/graphql/graphql-java/index.html | 1240 ++--------------- .../docs/dev-guide/graphql/index.html | 1158 +-------------- .../dev-guide/graphql/left-join/index.html | 1162 +-------------- .../docs/dev-guide/graphql/rest/index.html | 1184 +--------------- .../docs/dev-guide/graphql/upload/index.html | 1240 ++--------------- .../docs/dev-guide/graphql/xbiz/index.html | 1168 +--------------- .../docs/dev-guide/i18n/index.html | 1140 +-------------- .../docs/dev-guide/ide/idea/index.html | 1172 +--------------- .../docs/dev-guide/ide/plugin-dev/index.html | 1172 +--------------- .../nop-entropy/docs/dev-guide/index.html | 1140 +-------------- .../docs/dev-guide/integration/index.html | 1160 +-------------- .../docs/dev-guide/intro/index.html | 1140 +-------------- .../docs/dev-guide/ioc/aop/index.html | 1170 +--------------- .../nop-entropy/docs/dev-guide/ioc/index.html | 1240 ++--------------- .../docs/dev-guide/job/job-design/index.html | 1240 ++--------------- .../docs/dev-guide/job/job/index.html | 1140 +-------------- .../docs/dev-guide/job/trigger/index.html | 1140 +-------------- .../dev-guide/microservice/feign/index.html | 1198 +--------------- .../dev-guide/microservice/grpc/index.html | 1240 ++--------------- .../docs/dev-guide/microservice/index.html | 1156 +-------------- .../microservice/rpc-design/index.html | 1240 ++--------------- .../dev-guide/microservice/rpc/index.html | 1240 ++--------------- .../microservice/web-filter/index.html | 1226 ++-------------- .../docs/dev-guide/model/api-model/index.html | 1182 +--------------- .../dev-guide/model/core-models/index.html | 1240 ++--------------- .../dev-guide/model/custom-model/index.html | 1192 +--------------- .../dev-guide/model/excel-model/index.html | 1240 ++--------------- .../dev-guide/model/excel-xlsx/index.html | 1170 +--------------- .../docs/dev-guide/model/index.html | 1150 +-------------- .../dev-guide/nocode/dyn-model/index.html | 1240 ++--------------- .../dev-guide/nocode/dynamic-orm/index.html | 1184 +--------------- .../docs/dev-guide/nocode/index.html | 1140 +-------------- .../docs/dev-guide/orm/dao-lib/index.html | 1220 ++-------------- .../docs/dev-guide/orm/dao/index.html | 1222 ++-------------- .../dev-guide/orm/data-change-log/index.html | 1178 +--------------- .../docs/dev-guide/orm/dialect/index.html | 1164 +--------------- .../docs/dev-guide/orm/dql/index.html | 1206 +--------------- .../docs/dev-guide/orm/eql/index.html | 1204 +--------------- .../docs/dev-guide/orm/ext-field/index.html | 1240 ++--------------- .../dev-guide/orm/field-masking/index.html | 1170 +--------------- .../nop-entropy/docs/dev-guide/orm/index.html | 1158 +-------------- .../dev-guide/orm/many-to-many/index.html | 1170 +--------------- .../dev-guide/orm/multi-datasource/index.html | 1196 +--------------- .../docs/dev-guide/orm/multi-db/index.html | 1188 +--------------- .../docs/dev-guide/orm/null-value/index.html | 1152 +-------------- .../docs/dev-guide/orm/orm-basic/index.html | 1240 ++--------------- .../docs/dev-guide/orm/orm/index.html | 1212 +--------------- .../dev-guide/orm/session-cache/index.html | 1190 +--------------- .../docs/dev-guide/orm/sql-lib/index.html | 1240 ++--------------- .../docs/dev-guide/orm/tcc/index.html | 1140 +-------------- .../dev-guide/orm/to-one-relation/index.html | 1186 +--------------- .../docs/dev-guide/orm/transaction/index.html | 1178 +--------------- .../docs/dev-guide/quarkus/index.html | 1206 +--------------- .../dev-guide/recipe/add-field/index.html | 1168 +--------------- .../docs/dev-guide/recipe/crud/index.html | 1178 +--------------- .../dev-guide/recipe/filter-list/index.html | 1240 ++--------------- .../docs/dev-guide/recipe/index.html | 1140 +-------------- .../dev-guide/recipe/json-helper/index.html | 1180 +--------------- .../dev-guide/recipe/tree-entity/index.html | 1154 +-------------- .../dev-guide/recipe/xml-helper/index.html | 1226 ++-------------- .../dev-guide/report/examples/base/index.html | 1144 +-------------- .../report/examples/dynamic-col/index.html | 1202 +--------------- .../report/examples/form-printing/index.html | 1168 +--------------- .../dev-guide/report/excel-formula/index.html | 1174 +--------------- .../dev-guide/report/excel-import/index.html | 1240 ++--------------- .../docs/dev-guide/report/index.html | 1142 +-------------- .../dev-guide/report/report-design/index.html | 1240 ++--------------- .../docs/dev-guide/report/spl/index.html | 1168 +--------------- .../report/word-template-details/index.html | 1164 +--------------- .../dev-guide/report/word-template/index.html | 1240 ++--------------- .../dev-guide/report/xpt-report/index.html | 1240 ++--------------- .../docs/dev-guide/rule/rule/index.html | 1240 ++--------------- .../security/security-design/index.html | 1140 +-------------- .../docs/dev-guide/sonar/sonarqube/index.html | 1162 +-------------- .../docs/dev-guide/spring/index.html | 1214 ++-------------- .../dev-guide/spring/spring-delta/index.html | 1240 ++--------------- .../docs/dev-guide/tenant/index.html | 1198 +--------------- .../nop-entropy/docs/dev-guide/vfs/index.html | 1152 +-------------- .../dev-guide/vfs/model-loader/index.html | 1220 ++-------------- .../vfs/std-resource-path/index.html | 1152 +-------------- .../docs/dev-guide/vfs/vfs/index.html | 1240 ++--------------- .../workflow/flow-builder/index.html | 1210 +--------------- .../workflow/graph-designer/index.html | 1184 +--------------- .../workflow/task-concepts/index.html | 1240 ++--------------- .../dev-guide/workflow/task-flow/index.html | 1220 ++-------------- .../dev-guide/workflow/task-queue/index.html | 1166 +--------------- .../workflow/task-step-decorator/index.html | 1168 +--------------- .../docs/dev-guide/xlang/antlr/index.html | 1240 ++--------------- .../dev-guide/xlang/feature-expr/index.html | 1180 +--------------- .../docs/dev-guide/xlang/index.html | 1142 +-------------- .../xlang/meta-programming/index.html | 1240 ++--------------- .../dev-guide/xlang/x-override/index.html | 1240 ++--------------- .../docs/dev-guide/xlang/xdef/index.html | 1240 ++--------------- .../docs/dev-guide/xlang/xdsl/index.html | 1240 ++--------------- .../docs/dev-guide/xlang/xjson/index.html | 1184 +--------------- .../dev-guide/xlang/xlang-demo/index.html | 1220 ++-------------- .../docs/dev-guide/xlang/xlang/index.html | 1240 ++--------------- .../docs/dev-guide/xlang/xmeta/index.html | 1240 ++--------------- .../docs/dev-guide/xlang/xpath/index.html | 1140 +-------------- .../docs/dev-guide/xlang/xpl/index.html | 1240 ++--------------- .../docs/dev-guide/xlang/xscript/index.html | 1240 ++--------------- .../dev-guide/xlang/xtransform/index.html | 1140 +-------------- .../docs/dev-guide/xui/adapter/index.html | 1180 +--------------- .../docs/dev-guide/xui/amis/index.html | 1240 ++--------------- .../nop-entropy/docs/dev-guide/xui/index.html | 1140 +-------------- .../docs/dev-guide/xui/javascript/index.html | 1156 +-------------- .../docs/dev-guide/xui/layout/index.html | 1240 ++--------------- .../docs/dev-guide/xui/sdk/index.html | 1178 +--------------- .../docs/dev-guide/xui/typescript/index.html | 1156 +-------------- .../docs/dev-guide/xui/web-xlib/index.html | 1150 +-------------- .../docs/dev-guide/xui/xpage/index.html | 1240 ++--------------- .../docs/dev-guide/xui/xview/index.html | 1240 ++--------------- .../docs/faq/debug-errors/index.html | 1152 +-------------- projects/nop-entropy/docs/faq/faq/index.html | 1240 ++--------------- .../docs/frontend/frontend-design/index.html | 1240 ++--------------- .../docs/frontend/nop-site/index.html | 1150 +-------------- .../docs/frontend/react/index.html | 1182 +--------------- .../nop-entropy/docs/frontend/vite/index.html | 1174 +--------------- .../docs/gpt/aisuda-prompts/index.html | 1170 +--------------- .../docs/gpt/alpha-codium/READM/index.html | 1142 +-------------- .../docs/gpt/copilot-prompts/index.html | 1196 +--------------- .../docs/gpt/create-module/index.html | 1160 +-------------- .../docs/gpt/create-workflow/index.html | 1166 +--------------- .../docs/gpt/gpt-pilot/READM/index.html | 1148 +-------------- .../docs/gpt/proofreading/index.html | 1158 +-------------- .../nop-entropy/docs/gpt/read-doc/index.html | 1162 +-------------- .../docs/gpt/reference/tutor/index.html | 1240 ++--------------- .../docs/gpt/update-table/index.html | 1170 +--------------- projects/nop-entropy/docs/index.html | 1188 +--------------- .../nop-entropy/docs/intro/intro/index.html | 1178 +--------------- .../performance/optimize-theory/index.html | 1140 +-------------- .../docs/performance/optimize-tool/index.html | 1156 +-------------- .../theory/advantage-of-lowcode/index.html | 1156 +-------------- .../index.html | 1210 +--------------- .../theory/amis/why-amis-is-good/index.html | 1240 ++--------------- .../docs/theory/ddd-in-nop/index.html | 1240 ++--------------- .../theory/declarative-programming/index.html | 1240 ++--------------- .../docs/theory/decouple/index.html | 1224 ++-------------- .../delta-oriented-programming/index.html | 1240 ++--------------- .../docs/theory/design-methodology/index.html | 1224 ++-------------- .../index.html | 1240 ++--------------- .../theory/discusson-about-nop/index.html | 1188 +--------------- .../docs/theory/essence-of-react/index.html | 1240 ++--------------- .../docs/theory/framework-agnostic/index.html | 1240 ++--------------- .../generic-delta-composition/index.html | 1240 ++--------------- .../docs/theory/good_design/index.html | 1196 +--------------- .../docs/theory/graphql-vs-rest/index.html | 1206 +--------------- projects/nop-entropy/docs/theory/index.html | 1180 +--------------- .../docs/theory/lowcode-expained/index.html | 1240 ++--------------- .../docs/theory/lowcode-ioc/index.html | 1240 ++--------------- .../docs/theory/lowcode-orm-1/index.html | 1240 ++--------------- .../docs/theory/lowcode-orm-2/index.html | 1240 ++--------------- .../docs/theory/lowcode-task-flow/index.html | 1240 ++--------------- .../index.html | 1240 ++--------------- .../docs/theory/nop-for-gpt/index.html | 1240 ++--------------- .../nop-entropy/docs/theory/paxos/index.html | 1240 ++--------------- .../pros-and-cons-of-framework/index.html | 1240 ++--------------- .../nop-entropy/docs/theory/reuse/index.html | 1182 +--------------- .../index.html | 1240 ++--------------- .../index.html | 1240 ++--------------- .../index.html | 1240 ++--------------- .../theory/reversible-computation/index.html | 1240 ++--------------- .../docs/theory/technical-strategy/index.html | 1240 ++--------------- .../theory/tensor-product-lowcode/index.html | 1240 ++--------------- .../what-does-reversible-mean/index.html | 1240 ++--------------- .../theory/what-is-data-driven/index.html | 1228 ++-------------- .../why-nop-report-is-special/index.html | 1228 ++-------------- .../docs/theory/why-xml/index.html | 1228 ++-------------- .../docs/theory/xdsl-design/index.html | 1240 ++--------------- .../theory/xml-json-equivalence/index.html | 1240 ++--------------- .../simple/1-simple-service/index.html | 1240 ++--------------- .../tutorial/simple/2-simple-dao/index.html | 1220 ++-------------- .../tutorial/simple/3-simple-page/index.html | 1140 +-------------- .../docs/tutorial/tutorial/index.html | 1240 ++--------------- .../docs/tutorial/tutorial_en/index.html | 1240 ++--------------- .../docs/user-guide/batch/index.html | 1140 +-------------- .../user-guide/idea/idea-plugin/index.html | 1180 +--------------- .../nop-entropy/docs/user-guide/index.html | 1140 +-------------- .../docs/user-guide/installation/index.html | 1216 ++-------------- .../user-guide/monitor/grafana/index.html | 1240 ++--------------- .../docs/user-guide/report-qrcode/index.html | 1240 ++--------------- .../docs/user-guide/report/index.html | 1240 ++--------------- .../docs/user-guide/rule/index.html | 1150 +-------------- .../docs/user-guide/workflow/index.html | 1140 +-------------- projects/nop-entropy/docs/why-nop/index.html | 1206 +--------------- 217 files changed, 15302 insertions(+), 244888 deletions(-) diff --git a/projects/nop-entropy/docs/arch/index.html b/projects/nop-entropy/docs/arch/index.html index d4e3d70..3ffebe5 100644 --- a/projects/nop-entropy/docs/arch/index.html +++ b/projects/nop-entropy/docs/arch/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1105 +186,71 @@ -
+
+ + + +
+
+
+ + +

架构

-
+

模块依赖关系: module-dependency.md

-
- - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    - - - -
    - diff --git a/projects/nop-entropy/docs/arch/module-dependency/index.html b/projects/nop-entropy/docs/arch/module-dependency/index.html index b54a5aa..895f93e 100644 --- a/projects/nop-entropy/docs/arch/module-dependency/index.html +++ b/projects/nop-entropy/docs/arch/module-dependency/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/compare/index.html b/projects/nop-entropy/docs/compare/index.html index a2559a1..16a2460 100644 --- a/projects/nop-entropy/docs/compare/index.html +++ b/projects/nop-entropy/docs/compare/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1106 +186,72 @@ -
    +
    + + + +
    +
    +
    + + +

    与其他平台的对比

    -
    +

    与SpringCloud的对比

    参见 nop-vs-springcloud.md

    +

    与Skyve低代码平台的对比

    参见 nop-vs-skyve.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    - - - -
    - diff --git a/projects/nop-entropy/docs/compare/nop-vs-skyve/index.html b/projects/nop-entropy/docs/compare/nop-vs-skyve/index.html index 75743ff..520f1c1 100644 --- a/projects/nop-entropy/docs/compare/nop-vs-skyve/index.html +++ b/projects/nop-entropy/docs/compare/nop-vs-skyve/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/compare/nop-vs-springcloud/index.html b/projects/nop-entropy/docs/compare/nop-vs-springcloud/index.html index 0789264..db2a40c 100644 --- a/projects/nop-entropy/docs/compare/nop-vs-springcloud/index.html +++ b/projects/nop-entropy/docs/compare/nop-vs-springcloud/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/core-code-guidance/index.html b/projects/nop-entropy/docs/core-code-guidance/index.html index 3309dd7..e137c8a 100644 --- a/projects/nop-entropy/docs/core-code-guidance/index.html +++ b/projects/nop-entropy/docs/core-code-guidance/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/auth/auth/index.html b/projects/nop-entropy/docs/dev-guide/auth/auth/index.html index 8345f93..3798f18 100644 --- a/projects/nop-entropy/docs/dev-guide/auth/auth/index.html +++ b/projects/nop-entropy/docs/dev-guide/auth/auth/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/auth/impersonate/index.html b/projects/nop-entropy/docs/dev-guide/auth/impersonate/index.html index a79b714..dd6d91a 100644 --- a/projects/nop-entropy/docs/dev-guide/auth/impersonate/index.html +++ b/projects/nop-entropy/docs/dev-guide/auth/impersonate/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1108 +186,74 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/auth/index.html b/projects/nop-entropy/docs/dev-guide/auth/index.html index 67466b8..cad0464 100644 --- a/projects/nop-entropy/docs/dev-guide/auth/index.html +++ b/projects/nop-entropy/docs/dev-guide/auth/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1108 +186,74 @@ -
    +
    + + + +
    +
    +
    + + +

    权限配置

    -
    +

    Nop平台的权限管控可以精确到按钮和单个字段级别,并且可以支持数据权限控制,参见auth.md

    +

    用户登录

    参见login.md

    +

    服务认证

    在没有实际用户的情况下,如何控制服务之间的访问权限,参见service-auth.md

    +

    单点登录

    参见sso.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    权限配置

    - - - - -
    -

    Nop平台的权限管控可以精确到按钮和单个字段级别,并且可以支持数据权限控制,参见auth.md

    -

    用户登录

    参见login.md

    -

    服务认证

    在没有实际用户的情况下,如何控制服务之间的访问权限,参见service-auth.md

    -

    单点登录

    参见sso.md

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/auth/login/index.html b/projects/nop-entropy/docs/dev-guide/auth/login/index.html index 85b257e..6eb2af0 100644 --- a/projects/nop-entropy/docs/dev-guide/auth/login/index.html +++ b/projects/nop-entropy/docs/dev-guide/auth/login/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1131 +186,97 @@ -
    +
    + + + +
    +
    +
    + + +

    登录逻辑

    -
    +

    外部公开链接

    auth-service.beans.xml中定义了
    nopAuthHttpServerFilter和nopAuthFilterConfig。其中AuthHttpServerFilter负责执行所有用户登录检查,如果发现没有登录就返回HTTP 401错误或者重定向到登录页。

    +

    公开链接

    authFilter使用AuthFilterConfig中的配置来确定哪些路径是公开路径。

    +

    缺省情况下开放了如下路径:

    +
      +
    1. /r/LoginApi_* 等登录相关接口
    2. +
    3. /q/health* 等健康检查接口
    4. +
    5. /q/metrics* 等内部状态度量接口
    6. +
    +
    <bean id="nopAuthFilterConfig" class="io.nop.auth.core.filter.AuthFilterConfig">
    <!-- 未指定的情况下都是公开页面,主要是js/css/image等 -->
    <property name="defaultPublic" value="true"/>

    <property name="publicPaths">
    <list>
    <value>/r/LoginApi_*</value>
    <value>/q/health*</value>
    <value>/q/metrics*</value>
    </list>
    </property>

    <property name="authPaths">
    <list>
    <value>/graphql*</value>
    <!-- REST请求 -->
    <value>/r/*</value>
    <!-- quarkus内置管理页面 -->
    <value>/q/*</value>
    <!-- 返回具有指定contentType的内容 -->
    <value>/p/*</value>
    <!-- 文件上传下载 -->
    <value>/f/*</value>
    </list>
    </property>
    </bean>
    + +

    定制登录逻辑

    存在两种方式定制登录逻辑

    +

    1. 定制AuthHttpServerFilter

    如果需要定制登录逻辑,可以继承AuthHttpServerFilter,然后定义一个id为nopAuthHttpServerFilter的bean,即可覆盖平台中内置的authFilter。

    +
    <bean id="nopAuthServerFilter" class="xxx.MyFilter" />
    + +
    +

    因为平台内置的nopAuthServerFilter标记了ioc:default=true,所以只要发现有其他同名的bean,就会自动覆盖平台内置的authFilter

    +
    +

    2. 定制ILoginService

    authFilter中实际执行登录验证操作时使用的是ILoginService接口,可以提供一个ILoginService的实现来覆盖系统内置的登录逻辑。
    与AuthFilter不同的是,这里无法访问到Web环境,所以一些涉及到Web环境处理的逻辑只能通过继承AuthHttpServerFilter来实现(比如修改cookie绑定逻辑等)。

    +

    目前集成keycloak单点登录服务就是用通过增加OAuthLoginServiceImpl类来实现,参见sso.md

    +

    配置项

      +
    1. nop.auth.login.use-dao-user-context-cache
      设置为true后会启用DaoUserContextCache,将IUserContext中的信息保存到NopAuthSession表中。

      +
    2. +
    3. nop.auth.access-token-expire-seconds
      访问令牌(access token)超时时间,缺省为30*60,即30分钟

      +
    4. +
    5. nop.auth.refresh-token-expire-seconds
      刷新令牌(refresh token)的超时时间,缺省为300*60,即5个小时

      +
    6. +
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/auth/service-auth/index.html b/projects/nop-entropy/docs/dev-guide/auth/service-auth/index.html index 6be43a1..2d29dad 100644 --- a/projects/nop-entropy/docs/dev-guide/auth/service-auth/index.html +++ b/projects/nop-entropy/docs/dev-guide/auth/service-auth/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1113 +186,79 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    服务鉴权

    - - - - -
    -

    服务间鉴权的方式与普通用户相同,都是用accessToken。在LoginService的实现中可以判断accessToken是否对应于具体用户,如果不是,则可以创建一个系统用户上下文。

    -

    开放所有服务

    nop.auth.service-public: true会自动允许所有服务对象被匿名访问。如果Authorization这个http header中传递的accessToken为空或者解析失败,会自动创建一个系统上下文,
    而不是返回【尚未登录】的错误信息。

    -

    auth-service.beans.xml配置文件中通过nopAuthFilterConfig配置了服务路径,

    -
    <bean id="nopAuthFilterConfig" class="io.nop.auth.core.filter.AuthFilterConfig">
    <property name="servicePaths">
    <list>
    <value>/graphql*</value>
    <!-- REST请求 -->
    <value>/r/*</value>
    <!-- 返回具有指定contentType的内容 -->
    <value>/p/*</value>
    <!-- 文件上传下载 -->
    <value>/f/*</value>
    </list>
    </property>

    <property name="servicePublic" value="@cfg:nop.auth.service-public|false"/>
    </bean>
    - -
      -
    • 可以通过nop-tenant, nop-timezone, nop-locale等http header来设置系统用户上下文的tenantId和locale等信息
    • -
    • 系统用户的id固定为sys
    • -
    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/auth/sso/index.html b/projects/nop-entropy/docs/dev-guide/auth/sso/index.html index 4223471..3d1d655 100644 --- a/projects/nop-entropy/docs/dev-guide/auth/sso/index.html +++ b/projects/nop-entropy/docs/dev-guide/auth/sso/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1120 +186,86 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    启用SSO支持

    - - - - -
    -

    系统内置了对Keycloak单点登录服务器的支持,可以直接集成外部的keycloak服务器,而完全不使用nop-auth模块内置的NopAuthUser表。用户的角色也是直接从keycloak服务器获取。

    -
      -
    1. 引入nop-auth-sso模块,这里提供了OAuthLoginServiceImpl,它会替换nop-auth-service模块提供的缺省实现LoginServiceImpl
    2. -
    3. 在application.yaml中启用sso相关的配置
    4. -
    -
    nop:
    auth:
    sso:
    enabled: true
    server-url: http://localhost:8041
    realm: app
    client-id: test-client
    client-secret: qpgEjwXqd1TpgaA3aIi1jd4AVTLCrs8o
    - -
      -
    • nop.auth.sso.server-url对应于keycloak单点服务器的url
    • -
    • nop.auth.sso.realm是keycloak中配置的realm
    • -
    • nop.auth.sso.client-id和nop.auth.sso.client-secret是keycloak服务器中配置的客户端信息
    • -
    -

    单点退出

    通过访问如下链接可以调用nop.auth.sso.logout-url来退出点点

    -
    POST /r/LoginApi__ssoLogout

    {
    "accessToken": "xxx"
    }
    - -

    权限限制

    Nop平台只使用了单点服务器的用户和角色配置,对于更细粒度的资源访问权限,则需要在Nop平台内部配置。Nop平台通过指定Role可以访问哪些资源对象来控制用户操作权限。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/autotest/index.html b/projects/nop-entropy/docs/dev-guide/autotest/index.html index 481515d..d391a2b 100644 --- a/projects/nop-entropy/docs/dev-guide/autotest/index.html +++ b/projects/nop-entropy/docs/dev-guide/autotest/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/batch/batch-design/index.html b/projects/nop-entropy/docs/dev-guide/batch/batch-design/index.html index b2ee2fa..41ae925 100644 --- a/projects/nop-entropy/docs/dev-guide/batch/batch-design/index.html +++ b/projects/nop-entropy/docs/dev-guide/batch/batch-design/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1111 +186,77 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/batch/batch-gen/index.html b/projects/nop-entropy/docs/dev-guide/batch/batch-gen/index.html index 708fe53..fda9b3e 100644 --- a/projects/nop-entropy/docs/dev-guide/batch/batch-gen/index.html +++ b/projects/nop-entropy/docs/dev-guide/batch/batch-gen/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/batch/batch-task/index.html b/projects/nop-entropy/docs/dev-guide/batch/batch-task/index.html index 31bdef8..fda9b3e 100644 --- a/projects/nop-entropy/docs/dev-guide/batch/batch-task/index.html +++ b/projects/nop-entropy/docs/dev-guide/batch/batch-task/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/biz/coderule/index.html b/projects/nop-entropy/docs/dev-guide/biz/coderule/index.html index 8807d51..ca085ad 100644 --- a/projects/nop-entropy/docs/dev-guide/biz/coderule/index.html +++ b/projects/nop-entropy/docs/dev-guide/biz/coderule/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/biz/index.html b/projects/nop-entropy/docs/dev-guide/biz/index.html index de3c590..85cca83 100644 --- a/projects/nop-entropy/docs/dev-guide/biz/index.html +++ b/projects/nop-entropy/docs/dev-guide/biz/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1107 +186,73 @@ -
    +
    + + + +
    +
    +
    + + +

    业务扩展

    -
    +

    编码规则

    参见coderule.md

    +

    验证模型

    CrudBizModel中内置的验证规则,参见validate.md

    +

    验证模型详细介绍参见 validator.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    - - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/biz/validate/index.html b/projects/nop-entropy/docs/dev-guide/biz/validate/index.html index 0b8bdcd..f78a0f2 100644 --- a/projects/nop-entropy/docs/dev-guide/biz/validate/index.html +++ b/projects/nop-entropy/docs/dev-guide/biz/validate/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1113 +186,79 @@ -
    +
    + + + +
    +
    +
    + + +

    CrudBizModel中的自动验证

    -
    +

    通过save/update等标准方法保存时,会调用MetaBaseValidator验证输入数据的合法性

    +

    1. validator

    如果字段配置了validator,则会首先使用BizValidatorHelper.runValidatorModelForValue来验证字段值合法

    +

    验证模型详细介绍参见 validator.md

    +

    2. 字典数据

    如果字段配置了dict,则会自动加载字典数据,验证前台提交的值在字段范围之内

    +

    3. 关联数据

    对于外键关联,类如dept_id关联Department表,则代码生成时会自动生成如下配置

    +

    <props>
    <prop name="deptId" ext:relation="dept">
    ...
    </prop>

    <prop name="dept">
    <schema bizObjName="NopAuthDepartment"/>
    </prop>
    </props>
    + +

    当验证deptId字段时,会检查是否具有ext:relation属性,如果存在关联对象,则调用关联的BizObject的get方法来验证实体的存在性。

    +

    因为是通过IBizObject.invoke("get",{id: deptId})这种方式来检查参数有效性,所以会检查当前用户的数据权限配置,确保当前用户可以访问指定数据,
    并且该数据在数据库中存在。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    CrudBizModel中的自动验证

    - - - - -
    -

    通过save/update等标准方法保存时,会调用MetaBaseValidator验证输入数据的合法性

    -

    1. validator

    如果字段配置了validator,则会首先使用BizValidatorHelper.runValidatorModelForValue来验证字段值合法

    -

    验证模型详细介绍参见 validator.md

    -

    2. 字典数据

    如果字段配置了dict,则会自动加载字典数据,验证前台提交的值在字段范围之内

    -

    3. 关联数据

    对于外键关联,类如dept_id关联Department表,则代码生成时会自动生成如下配置

    -

    <props>
    <prop name="deptId" ext:relation="dept">
    ...
    </prop>

    <prop name="dept">
    <schema bizObjName="NopAuthDepartment"/>
    </prop>
    </props>
    - -

    当验证deptId字段时,会检查是否具有ext:relation属性,如果存在关联对象,则调用关联的BizObject的get方法来验证实体的存在性。

    -

    因为是通过IBizObject.invoke("get",{id: deptId})这种方式来检查参数有效性,所以会检查当前用户的数据权限配置,确保当前用户可以访问指定数据,
    并且该数据在数据库中存在。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/biz/validator/index.html b/projects/nop-entropy/docs/dev-guide/biz/validator/index.html index 7efecfb..751d993 100644 --- a/projects/nop-entropy/docs/dev-guide/biz/validator/index.html +++ b/projects/nop-entropy/docs/dev-guide/biz/validator/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1146 +186,112 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/cli/index.html b/projects/nop-entropy/docs/dev-guide/cli/index.html index a6c6501..ba9995a 100644 --- a/projects/nop-entropy/docs/dev-guide/cli/index.html +++ b/projects/nop-entropy/docs/dev-guide/cli/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1138 +186,104 @@ -
    +
    + + + +
    +
    +
    + + +

    NopCli命令行工具

    -
    +

    逆向工程

    可以通过JDBC连接数据库,获取数据库中的元数据生成Excel格式的数据模型定义。

    +
    java -jar nop-cli.jar reverse-db litemall -c=com.mysql.cj.jdbc.Driver --username=litemall --password=litemall123456 --jdbcUrl="jdbc:mysql://127.0.0.1:3306/litemall?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC"
    + +

    nop-cli的reverse-db命令需要传入参数【数据库模式名】,例如litemall,然后通过jdbcUrl等选项传入JDBC连接字符串等信息。

    +
    Usage: nop-cli reverse-db [-dhV] -c=<driverClassName> -j=<jdbcUrl>
    [-o=<outputFile>] [-p=<password>] [-t=<table>]
    -u=<username> <catalog>
    对数据库进行逆向工程分析,生成Excel模型文件
    <catalog> 数据库模式名
    -c, --driverClass=<driverClassName>
    JDBC驱动类
    -d, --dump 输出文件(缺省输出到命令行窗口中)
    -h, --help Show this help message and exit.
    -j, --jdbcUrl=<jdbcUrl> jdbc连接
    -o, --output=<outputFile> 输出文件(缺省输出到命令行窗口中)
    -p, --password=<password> 数据库密码
    -t, --table=<table> 数据库表模式,例如litemal%表示匹配litemall为前缀的表
    -u, --username=<username> 数据库用户名
    -V, --version Print version information and exit.
    + +

    代码生成

    如果已经获得Excel数据模型,则可以使用nop-cli命令行工具的gen命令来生成初始工程代码

    +
    java -jar nop-cli.jar gen -t=/nop/templates/orm model/app-mall.orm.xlsx
    + +

    具体生成的内容如下:

    +
    ├─app-mall-api       对外暴露的接口定义和消息定义
    ├─app-mall-codegen 代码生成辅助工程,根据ORM模型更新当前工程代码
    ├─app-mall-dao 数据库实体定义和ORM模型
    ├─app-mall-service GraphQL服务实现
    ├─app-mall-web AMIS页面文件以及View模型定义
    ├─app-mall-app 测试使用的打包工程
    ├─deploy 根据Excel模型生成的数据库建表语句
    + +

    只生成dao模块

    如果只想使用NopORM,不需要生成前端代码,也不需要生成GraphQL服务,则可以使用orm-dao模板

    +
    java -jar nop-cli.jar gen -t=/nop/templates/orm-dao -o=app-dao model/app-mall.orm.xlsx 
    + +

    使用自己定制的生成模板

    除了使用Nop平台内置的代码生成模板,我们还可以建立自己的模板工程。具体过程参见项目bsin-codegen.
    B站视频: 可逆计算原理和Nop平台介绍及答疑, 从44分钟20秒开始

    +

    java -Xbootclasspath/a:bsin-codegen-template/src/main/resources/ -jar nop-cli-2.0.0-BETA.1.jar gen bsin-demo/model/bsin-demo.orm.xlsx -t=/bsin/templates/orm -o=bsin-demo
    + +

    通过-Xbootclasspath/a:bsin-codegen-template/src/main/resources/引入外部的jar包或者目录到classpath中,然后通过-t=/bsin/templates/orm来引用classpath下的模板文件,就可以生成代码

    +

    动态监听文件目录,发现修改后执行代码生成

    使用NopCli工具可以监听指定目录,当目录下的文件发生变动时自动执行脚本代码。

    +
    java -jar nop-cli.jar watch app-meta -e=taks/gen-web.xrun
    + +

    以上配置表示监控 app-meta目录,当其中的文件发生变化时执行gen-web.xrun脚本文件

    +

    在这个脚本文件中,我们可以通过GenWithDependsCache等Xpl模板标签来动态生成代码

    +
    <c:unit xmlns:c="c" xmlns:run="run" xmlns:xpl="xpl">
    <run:GenWithCache xpl:lib="/nop/codegen/xlib/run.xlib"
    srcDir="/meta/test" appName="Test"
    targetDir="./target/gen"
    tplDir="/nop/test/meta-web"/>
    </c:unit>
    + +

    GenWithCache标签会设置srcDir,appName属性,然后执行tplDir指定的代码生成模板,生成文件的存放路径由targetDir指定。

    +

    代码生成的过程中启用了依赖追踪,第一次生成之后再此触发gen-web.xrun运行代码生成任务时会自动检查输出文件所对应的依赖模型文件,只有当依赖文件发生变化时才会重新生成,否则会自动跳过。

    +

    解析Excel模型导出为JSON或者XML

    java -jar nop-cli.jar extract test.orm.xlsx -o=my.orm.json
    + +

    extract指令会识别文件的后缀名,选择注册到系统中的解析器进行解析,得到Json对象后再导出为JSON文件。如果存在对应的xdef元模型定义,也可以选择导出为XML格式

    +

    根据JSON生成Excel文件

    java -jar nop-cli.jar gen-file my.orm.json -t=/nop/orm/imp/orm.imp.xml
    + +

    gen-file会根据-t参数指定的模板文件来导出Excel。模板文件可以如果是imp.xml,则使用导入模型关联的导出模板来导出。也可以是xpt.xlsx这种报表模板,
    此时将按照报表模型实现导出。JSON文件解析得到的对象在报表导出时对应于名为entity的对象。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/codegen/index.html b/projects/nop-entropy/docs/dev-guide/codegen/index.html index 31f1324..11f7655 100644 --- a/projects/nop-entropy/docs/dev-guide/codegen/index.html +++ b/projects/nop-entropy/docs/dev-guide/codegen/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    + + +
    +
    @@ -1358,20 +311,6 @@

    <c:unit>
    <gen:Render template="/nop/templates/orm/{appName}-dao" targetDir="${targetResource.path.$filePath()}"
    xpl:lib="/nop/codegen/xlib/gen.xlib" inheritCodeGenLoop="true"/>
    </c:unit>

    + + +
    -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/command/command/index.html b/projects/nop-entropy/docs/dev-guide/command/command/index.html index cb1440f..cca2553 100644 --- a/projects/nop-entropy/docs/dev-guide/command/command/index.html +++ b/projects/nop-entropy/docs/dev-guide/command/command/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1126 +186,92 @@ -
    +
    + + + +
    +
    +
    + + +

    命令行程序支持

    -
    +

    Nop平台内置了命令行程序支持,只要注册ICommand接口的bean,就可以通过命令行指令直接调用。执行完指令后会直接推出应用

    +

    1. 注册ICommand接口的实现类,bean的名称为nopCommand_xxx

    <bean id="nopCommand_test" class="test.TestCommand" />
    + +

    2. 通过nop-exec命令来调用对应命令

    java -jar app.jar nop-exec --command=test --myArg=a --myArg2=123
    + +

    详细配置

      +
    1. 启用开关 nop.core.nop-command-executor.enabled 是否启用命令行处理功能,缺省启用

      +
    2. +
    3. 将比较复杂的命令作为文件传入

      +
    4. +
    +
    jar -jar app.jar nop-exec --command=test.json
    + +

    test.json中为json格式的命令文件,对应于CommandBean对象。

    +
    {
    "command": "test",
    "params": {
    "myArg1": "a",
    "myArg2": 123
    }
    }
    + +
      +
    1. 依次执行多个命令
    2. +
    +
    java -jar app.jar nop-exec --command=test1.json --command=test2.json
    + +

    任何一个命令的返回值不是0的时候都会中断执行。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/config/index.html b/projects/nop-entropy/docs/dev-guide/config/index.html index 49dca05..b509146 100644 --- a/projects/nop-entropy/docs/dev-guide/config/index.html +++ b/projects/nop-entropy/docs/dev-guide/config/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/customization/index.html b/projects/nop-entropy/docs/dev-guide/customization/index.html index e3492bc..2f9da31 100644 --- a/projects/nop-entropy/docs/dev-guide/customization/index.html +++ b/projects/nop-entropy/docs/dev-guide/customization/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1128 +186,94 @@ -
    +
    + + + +
    +
    +
    + + +

    Delta定制

    -
    +

    Nop平台与其他开发平台相比,一个显著的特异之处在于它支持在完全不修改平台源码的情况下,通过Delta定制机制实现对平台功能的深度定制。

    +

    整体架构说明,参见delta-customization.md

    +

    定制bean

    Nop平台中所有的bean都由NopIoC容器统一管理,它是一个语法类似Spring1.0,但是增加了类似SpringBoot的条件装配和自动装配机制的,完全声明式的一个IoC容器。

    +

    为了避免命名冲突,Nop平台内置的bean的id一般以nop为前缀,例如nopJdbcTemplate等

    +

    查看bean的定义

    为了定制bean,首先可以查看_dump目录下的/nop/main/beans/merged-app.beans.xml文件。系统在调试模式下启动时会自动将所有被激活的bean的配置都输出
    到这个调试文件中。通过查看这个文件,可以获知系统中所有使用到的bean的配置细节。

    +

    <!--LOC:[15:6:0:0]/nop/auth/beans/auth-service.beans.xml-->
    <bean class="io.nop.auth.service.auth.DefaultActionAuthChecker" id="$DEFAULT$nopActionAuthChecker" ioc:aop="false"
    name="nopActionAuthChecker">
    <property name="siteMapProvider" ext:autowired="true">
    <ref bean="nopSiteMapProvider" ext:resolved-loc="[13:6:0:0]/nop/auth/beans/auth-service.beans.xml"
    ext:resolved-trace="/nop/auth/beans/app-service.beans.xml"/>
    </property>
    </bean>
    + +

    这个文件中可以看出每个bean所在的源文件位置,例如上面的示例表示

    +
      +
    1. 名为nopActionAuthChecker的bean在auth-service.beans.xml文件中定义。
    2. +
    3. siteMapProvider属性使用@Inject注解自动注入,实际注入的bean为 nopSiteMapProvider
    4. +
    5. nopSiteMapProvider的源码位置为 auth-service.beans.xml文件的第13行。
    6. +
    7. id="$DEFAULT$nopActionAuthChecker" 表示它定义的是一个default实现,如果存在一个具有相同名称的bean,则会自动替换这个实现。
    8. +
    +

    nopActionAuthChecker的原始定义如下,节点上标记了ioc:default=’true’。如果存在另外一个bean的name也是nopActionAuthChecker,则会自动
    覆盖这个缺省定义。ioc:default的作用类似于SpringBoot中的ConditionOnMissingBean

    +
    <bean id="nopActionAuthChecker" class="io.nop.auth.service.auth.DefaultActionAuthChecker" ioc:default="true"/>
    + +

    替换或者删除系统中的bean定义

    如果需要替换系统中bean的定义,只需要在/_vfs/_delta/default目录下定义同名的beans.xml文件,然后在其中使用x:extends机制来定制

    +

    <beans x:schema="/nop/schema/beans.xdef" xmlns:x="/nop/schema/xdsl.xdef"
    x:extends="super">
    <!-- 可以通过这种方式删除系统中内置的bean的定义-->
    <bean id="nopActionAuthChecker" x:override="remove" />
    </beans>
    + +

    也可以替换bean的实现类,例如

    +
    <beans x:schema="/nop/schema/beans.xdef" xmlns:x="/nop/schema/xdsl.xdef"
    x:extends="super">
    <!-- 这里的定义会和平台中的定义节点进行合并 -->
    <bean id="nopActionAuthChecker" claass="xxx.MyActionAuthChecker" />
    </beans>
    + +

    扩展Excel模型

    参见custom-model.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/debug/index.html b/projects/nop-entropy/docs/dev-guide/debug/index.html index 099dcc3..5860c2d 100644 --- a/projects/nop-entropy/docs/dev-guide/debug/index.html +++ b/projects/nop-entropy/docs/dev-guide/debug/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/delta-loader/index.html b/projects/nop-entropy/docs/dev-guide/delta-loader/index.html index 94dd982..a502b98 100644 --- a/projects/nop-entropy/docs/dev-guide/delta-loader/index.html +++ b/projects/nop-entropy/docs/dev-guide/delta-loader/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/delta/delta-customization/index.html b/projects/nop-entropy/docs/dev-guide/delta/delta-customization/index.html index 0cdc3dd..5ae0959 100644 --- a/projects/nop-entropy/docs/dev-guide/delta/delta-customization/index.html +++ b/projects/nop-entropy/docs/dev-guide/delta/delta-customization/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/dict/index.html b/projects/nop-entropy/docs/dev-guide/dict/index.html index fa18c4c..19e3e2b 100644 --- a/projects/nop-entropy/docs/dev-guide/dict/index.html +++ b/projects/nop-entropy/docs/dev-guide/dict/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1128 +186,94 @@ -
    +
    + + + +
    +
    +
    + + +

    字典表翻译

    -
    +

    在ORM模型中可以直接定义字典表,并且可以为字段指定关联的字典表,然后在GraphQL层会自动为这些字段生成对应的label字段,
    比如status生成status_label。参见meta-gen.xlib中GenDictLabelFields标签的实现。

    +

    为字段指定字典表

    如果手工添加,可以通过prop的schema配置来指定字典表

    +
    <meta>
    <props>
    <prop name="status">
    <schema dict="wf/wf-step-status" />
    </prop>
    </props>
    </meta>
    + +

    字典表文件

    我们可以在_vfs/dict目录下存放字典表文件,例如 wf/wf-step-status对应于_vfs/dict/core/wf/wf-step-status.dict.yaml

    +

    这个yaml文件中存放的就是DictBean类型的Java对象,例如

    +
    label: 步骤状态
    locale: zh-CN
    valueType: int
    description:
    options:
    - label: 已创建
    value: 0
    description:

    - label: 已暂停
    value: 10
    description:
    + +

    国际化

    DictProvider在加载字典表的时候,会检查字典定义中的locale与外部要求的locale是否相同。如果不同,会自动进行I18n翻译。

    +

    具体翻译规则是:

    +
      +
    1. dict.label.{dictName}
    2. +
    3. dict.option.label.{dictName}.{option.value}
    4. +
    +

    数据库中维护的字典表

    如果引入nop-sys-dao模块,会自动识别sys/xxx形式的字典表定义,它们存放在nop_sys_dict和nop_sys_dict_option表中。

    +

    Java枚举类

    dict可以直接指定Java Enum类名,例如dict="io.nop.xlang.xdef.XDefOverride"。对于没有包含/,可以作为类名看待的dictName,
    DictProvider会尝试按照类名去加载。

    +

    @Locale("zh-CN")
    public enum XDefOverride {
    @Option("remove")
    @Description("删除基类中的节点")
    REMOVE("remove"),

    @Option("replace")
    @Description("完全覆盖原有节点")
    REPLACE("replace")
    }
    + +

    在Java类中,可以通过@Option, @Label, @Description来指定字段项属性。

    +

    将业务表作为字典表

    在Excel数据模型中,如果为表增加了dict标签,则允许通过 obj/{bizObjName}的方式将业务表当作字典表来使用。这种用法要求有一列必须具有disp标签,
    它将作为显示名称,而字典项的值就是记录的主键。

    +

    使用SQL语句作为字典表

    在sql-lib.xml中后缀名称是_dict的SQL语句可以作为字典表来使用。例如sql/test.my_dict对应于/_vfs/{moduleId}/sql/test.sql-lib.xml
    名为my_dict的SQL语句。

    +
    <eql name="my_dict">
    select o.fldA as label, o.fldB as value
    from MyEntity o
    </eql>
    + +

    字典表SQL返回的字段名必须是DictOptionBean这个Java类中的属性名,它会被自动包装为DictOptionBean对象。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/error-code/index.html b/projects/nop-entropy/docs/dev-guide/error-code/index.html index 165c468..f8d938a 100644 --- a/projects/nop-entropy/docs/dev-guide/error-code/index.html +++ b/projects/nop-entropy/docs/dev-guide/error-code/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1139 +186,105 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/graphql/connection/index.html b/projects/nop-entropy/docs/dev-guide/graphql/connection/index.html index ad7c1e4..cd09c24 100644 --- a/projects/nop-entropy/docs/dev-guide/graphql/connection/index.html +++ b/projects/nop-entropy/docs/dev-guide/graphql/connection/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1115 +186,81 @@ -
    +
    + + + +
    +
    +
    + + +

    connection配置

    -
    +

    在Excel模型的外键关键对象上标注ref-connection,这样生成的一对多关联属性上会生成connection标签,并自动生成对应的Connection属性。
    例如NopAuthResource的site属性上标注ref-connection,则会自动在NopAuthSite对象的resources属性上增加connection标签。

    +

    +

    通过元编程机制会在编译期为meta文件增加对应的Connection属性,例如resourcesConnection。在_dump目录下可以看到最后生成的属性定义

    +

    <meta>
    <prop name="resources" displayName="资源列表" i18n-en:displayName="Resources" tagSet="pub,connection"
    ext:kind="to-many" internal="true" ext:joinLeftProp="siteId" ext:joinRightProp="siteId"
    ext:joinRightDisplayProp="displayName" insertable="false" updatable="false" lazy="true">
    <schema type="io.nop.orm.IOrmEntitySet&lt;io.nop.auth.dao.entity.NopAuthResource&gt;"
    bizObjName="NopAuthResource"/>
    </prop>
    <!--LOC:[90:22:0:0]/nop/core/xlib/biz-gen.xlib#/_delta/default/nop/auth/model/NopAuthSite/NopAuthSite.xmeta-->
    <prop name="resourcesConnection" displayName="资源列表" internal="true" graphql:connectionProp="resources">
    <graphql:inputType>io.nop.api.core.beans.graphql.GraphQLConnectionInput</graphql:inputType>
    <schema type="io.nop.api.core.beans.graphql.GraphQLConnection&lt;io.nop.auth.dao.entity.NopAuthResource&gt;"
    bizObjName="NopAuthResource"/>
    </prop>
    </meta>
    + +

    生成的resourcesConnection节点上通过graphql:connectionProp属性引用实体上的一个一对多关联属性,会自动使用这个关联属性对应的关联条件进行过滤。

    +

    具体测试用例可以参见 TestConnectionProp

    +

    resourcesConnection可以接收的参数为GraphQLConnectionInput类型

    +
    public class GraphQLConnectionInput {
    /**
    * first表示从afterCursor开始向后取n条数据
    */
    int first;
    int last;
    String after;
    String before;

    /**
    * 如果没有设置cursor,则也可以使用offset/limit机制进行分页
    */
    long offset;
    TreeBean filter;
    List<OrderFieldBean> orderBy;
    }
    +

    返回的结果类型为GraphQLConnection类型

    +
    class GraphQLConnection<T> {

    long total;
    List<GraphQLEdgeBean> edges;

    List<T> items;

    GraphQLPageInfo pageInfo;
    }

    class GraphQLPageInfo {
    String startCursor;
    String endCursor;
    Boolean hasNextPage;
    Boolean hasPreviousPage;
    }
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    connection配置

    - - - - -
    -

    在Excel模型的外键关键对象上标注ref-connection,这样生成的一对多关联属性上会生成connection标签,并自动生成对应的Connection属性。
    例如NopAuthResource的site属性上标注ref-connection,则会自动在NopAuthSite对象的resources属性上增加connection标签。

    -

    -

    通过元编程机制会在编译期为meta文件增加对应的Connection属性,例如resourcesConnection。在_dump目录下可以看到最后生成的属性定义

    -

    <meta>
    <prop name="resources" displayName="资源列表" i18n-en:displayName="Resources" tagSet="pub,connection"
    ext:kind="to-many" internal="true" ext:joinLeftProp="siteId" ext:joinRightProp="siteId"
    ext:joinRightDisplayProp="displayName" insertable="false" updatable="false" lazy="true">
    <schema type="io.nop.orm.IOrmEntitySet&lt;io.nop.auth.dao.entity.NopAuthResource&gt;"
    bizObjName="NopAuthResource"/>
    </prop>
    <!--LOC:[90:22:0:0]/nop/core/xlib/biz-gen.xlib#/_delta/default/nop/auth/model/NopAuthSite/NopAuthSite.xmeta-->
    <prop name="resourcesConnection" displayName="资源列表" internal="true" graphql:connectionProp="resources">
    <graphql:inputType>io.nop.api.core.beans.graphql.GraphQLConnectionInput</graphql:inputType>
    <schema type="io.nop.api.core.beans.graphql.GraphQLConnection&lt;io.nop.auth.dao.entity.NopAuthResource&gt;"
    bizObjName="NopAuthResource"/>
    </prop>
    </meta>
    - -

    生成的resourcesConnection节点上通过graphql:connectionProp属性引用实体上的一个一对多关联属性,会自动使用这个关联属性对应的关联条件进行过滤。

    -

    具体测试用例可以参见 TestConnectionProp

    -

    resourcesConnection可以接收的参数为GraphQLConnectionInput类型

    -
    public class GraphQLConnectionInput {
    /**
    * first表示从afterCursor开始向后取n条数据
    */
    int first;
    int last;
    String after;
    String before;

    /**
    * 如果没有设置cursor,则也可以使用offset/limit机制进行分页
    */
    long offset;
    TreeBean filter;
    List<OrderFieldBean> orderBy;
    }
    - -

    返回的结果类型为GraphQLConnection类型

    -
    class GraphQLConnection<T> {

    long total;
    List<GraphQLEdgeBean> edges;

    List<T> items;

    GraphQLPageInfo pageInfo;
    }

    class GraphQLPageInfo {
    String startCursor;
    String endCursor;
    Boolean hasNextPage;
    Boolean hasPreviousPage;
    }
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/graphql/crud/index.html b/projects/nop-entropy/docs/dev-guide/graphql/crud/index.html index 10df016..0db469e 100644 --- a/projects/nop-entropy/docs/dev-guide/graphql/crud/index.html +++ b/projects/nop-entropy/docs/dev-guide/graphql/crud/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/graphql/graphql-java/index.html b/projects/nop-entropy/docs/dev-guide/graphql/graphql-java/index.html index 913a1f2..cd0792c 100644 --- a/projects/nop-entropy/docs/dev-guide/graphql/graphql-java/index.html +++ b/projects/nop-entropy/docs/dev-guide/graphql/graphql-java/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/graphql/index.html b/projects/nop-entropy/docs/dev-guide/graphql/index.html index f3d9fbb..c658700 100644 --- a/projects/nop-entropy/docs/dev-guide/graphql/index.html +++ b/projects/nop-entropy/docs/dev-guide/graphql/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1110 +186,76 @@ -
    +
    + + + +
    +
    +
    + + +

    GraphQL引擎

    -
    +

    基本介绍

    参见graphql-java.md

    +

    内置的Crud服务

    参见crud.md

    +

    左连接

    参见left-join.md

    +

    文件上传

    参见upload.md

    +

    在XBiz文件中定义服务函数

    参见xbiz.md

    +

    对子表进行分页

    实现类似Relay框架的Connection机制,参见connection.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    - - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/graphql/left-join/index.html b/projects/nop-entropy/docs/dev-guide/graphql/left-join/index.html index d505d7a..6988b94 100644 --- a/projects/nop-entropy/docs/dev-guide/graphql/left-join/index.html +++ b/projects/nop-entropy/docs/dev-guide/graphql/left-join/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1112 +186,78 @@ -
    +
    + + + +
    +
    +
    + + +

    通过QueryBean实现左连接查询

    -
    +

    QueryBean中增加了leftJoinProps集合属性,这里指定的属性会转换为左连接语法。

    +
    {
    "leftJoinProps": [
    "dept"
    ],
    "filter": {
    "$type": "eq",
    "name": "dept.name",
    "value": "a"
    }
    }

    + +

    翻译成EQL对象查询时会变为

    +
    select o 
    from MyEntity o left join o.dept
    where o.dept.name = 'a'
    + +

    安全性控制

    为了避免前台发送预料之外的关联条件导致出现攻击,CrudBizModel中会检查leftJoinProps中的属性已经在meta的biz:allowedLeftJoinProps
    集合中定义。

    +

    缺省情况下不允许前端直接发送关联条件到后台,并且会限制关联个数不超过3。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    通过QueryBean实现左连接查询

    - - - - -
    -

    QueryBean中增加了leftJoinProps集合属性,这里指定的属性会转换为左连接语法。

    -
    {
    "leftJoinProps": [
    "dept"
    ],
    "filter": {
    "$type": "eq",
    "name": "dept.name",
    "value": "a"
    }
    }

    - -

    翻译成EQL对象查询时会变为

    -
    select o 
    from MyEntity o left join o.dept
    where o.dept.name = 'a'
    - -

    安全性控制

    为了避免前台发送预料之外的关联条件导致出现攻击,CrudBizModel中会检查leftJoinProps中的属性已经在meta的biz:allowedLeftJoinProps
    集合中定义。

    -

    缺省情况下不允许前端直接发送关联条件到后台,并且会限制关联个数不超过3。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/graphql/rest/index.html b/projects/nop-entropy/docs/dev-guide/graphql/rest/index.html index d48d164..c4dcba9 100644 --- a/projects/nop-entropy/docs/dev-guide/graphql/rest/index.html +++ b/projects/nop-entropy/docs/dev-guide/graphql/rest/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1123 +186,89 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    REST链接

    - - - - -
    -

    Nop平台中使用的REST链接很少,只有以下几种

    -
      -
    • /graphql
    • -
    • /r/{bizObjName}__{bizMethod}
    • -
    • /p/{bizObjName}__{bizMethod}
    • -
    • /f/download
    • -
    • /f/upload
    • -
    -
      -
    1. /r/的GET请求对应于graphql的Query,而POST请求可以调用query,也可以调用mutation
    2. -
    3. /p/会自动识别返回的结果是不是WebContentBean对象,如果是,则按照WebContentBean中设置的contentType来设置http的contentType,一般用于预览文件。
      例如调试模式下/p/DevDoc__beans会以XML格式显示系统中所有注册的bean
    4. -
    5. /f/download用于下载文件
    6. -
    -

    后台的实现代码对应于

    -
      -
    1. io.nop.quarkus.web.service.QuarkusGraphQLWebService
    2. -
    3. io.nop.file.quarkus.web.QuarkusFileService
    4. -
    -

    {bizObjName}__{bizMethod}会调用到后台BizModel对象的方法上。例如NopAuthUser__resetUserPassword
    会调用到 NopAuthUserBizModel对象的resetUserPassword方法。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/graphql/upload/index.html b/projects/nop-entropy/docs/dev-guide/graphql/upload/index.html index d22d023..33cd2ce 100644 --- a/projects/nop-entropy/docs/dev-guide/graphql/upload/index.html +++ b/projects/nop-entropy/docs/dev-guide/graphql/upload/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/graphql/xbiz/index.html b/projects/nop-entropy/docs/dev-guide/graphql/xbiz/index.html index aa238b2..f805e9b 100644 --- a/projects/nop-entropy/docs/dev-guide/graphql/xbiz/index.html +++ b/projects/nop-entropy/docs/dev-guide/graphql/xbiz/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1115 +186,81 @@ -
    +
    + + + +
    +
    +
    + + +

    Biz模型

    -
    +

    视频介绍:Nop平台中如何通过XBiz配置文件实现后台服务函数

    +

    代码生成

    缺省的代码生成模板会根据meta文件自动生成对应的xbiz模型文件,并且会自动引入biz-gen.xlib标签库,为CRUD操作生成缺省的函数参数声明。

    +

    在xbiz文件中可以直接编写query,muation, loader等函数定义,它们会覆盖Java的BizModel中的相应函数实现。
    也就是说,对外暴露的BizObject是由所有的BizModel类以及XBiz模型文件中定义的所有函数所组成的,在BizObjectManager启动的时候会扫描
    系统中所有的BizModel类,以及XBiz模型文件,生成对应的BizObject对象。

    +

    XBiz中定义的函数优先级最高,如果与已有的函数同名,则会自动覆盖

    +

    例如NopAuthUser.xbiz中增加了一个active_findPage函数

    +
    <query name="active_findPage" x:prototype="findPage">

    <source>
    <c:import class="io.nop.auth.api.AuthApiConstants" />

    <bo:DoFindPage query="${query}" selection="${selection}" xpl:lib="/nop/biz/xlib/bo.xlib">
    <filter>
    <eq name="status" value="${AuthApiConstants.USER_STATUS_ACTIVE}" />
    </filter>
    </bo:DoFindPage>
    </source>
    </query>
    + +

    x:prototype=”findPage”表示继承了缺省生成的findPage函数的参数定义。如果不继承,完整编写的函数如下:

    +
    <query name="active_findPage">
    <arg name="query" type="io.nop.api.core.beans.query.QueryBean"/>
    <arg name="selection" type="io.nop.api.core.beans.FieldSelectionBean" kind="FieldSelection"/>
    <arg name="svcCtx" type="io.nop.core.context.IServiceContext" kind="ServiceContext"/>
    <return type="PageBean&lt;io.nop.auth.dao.entity.NopAuthUser&gt;"/>
    <source>
    <c:import class="io.nop.auth.api.AuthApiConstants"/>
    <bo:DoFindPage query="${query}" selection="${selection}" xpl:lib="/nop/biz/xlib/bo.xlib">
    <filter>
    <eq name="status" value="${AuthApiConstants.USER_STATUS_ACTIVE}"/>
    </filter>
    </bo:DoFindPage>
    </source>
    </query>
    +

    这个函数定义等价于在Java中定义函数

    +

    @BizQuery
    public PageBean<NopAuthUser> active_findPage(@Name("query") QueryBean query,
    FieldSelection selection, IServiceContext ctx){
    return ...
    }
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    Biz模型

    - - - - -
    -

    视频介绍:Nop平台中如何通过XBiz配置文件实现后台服务函数

    -

    代码生成

    缺省的代码生成模板会根据meta文件自动生成对应的xbiz模型文件,并且会自动引入biz-gen.xlib标签库,为CRUD操作生成缺省的函数参数声明。

    -

    在xbiz文件中可以直接编写query,muation, loader等函数定义,它们会覆盖Java的BizModel中的相应函数实现。
    也就是说,对外暴露的BizObject是由所有的BizModel类以及XBiz模型文件中定义的所有函数所组成的,在BizObjectManager启动的时候会扫描
    系统中所有的BizModel类,以及XBiz模型文件,生成对应的BizObject对象。

    -

    XBiz中定义的函数优先级最高,如果与已有的函数同名,则会自动覆盖

    -

    例如NopAuthUser.xbiz中增加了一个active_findPage函数

    -
    <query name="active_findPage" x:prototype="findPage">

    <source>
    <c:import class="io.nop.auth.api.AuthApiConstants" />

    <bo:DoFindPage query="${query}" selection="${selection}" xpl:lib="/nop/biz/xlib/bo.xlib">
    <filter>
    <eq name="status" value="${AuthApiConstants.USER_STATUS_ACTIVE}" />
    </filter>
    </bo:DoFindPage>
    </source>
    </query>
    - -

    x:prototype=”findPage”表示继承了缺省生成的findPage函数的参数定义。如果不继承,完整编写的函数如下:

    -
    <query name="active_findPage">
    <arg name="query" type="io.nop.api.core.beans.query.QueryBean"/>
    <arg name="selection" type="io.nop.api.core.beans.FieldSelectionBean" kind="FieldSelection"/>
    <arg name="svcCtx" type="io.nop.core.context.IServiceContext" kind="ServiceContext"/>
    <return type="PageBean&lt;io.nop.auth.dao.entity.NopAuthUser&gt;"/>
    <source>
    <c:import class="io.nop.auth.api.AuthApiConstants"/>
    <bo:DoFindPage query="${query}" selection="${selection}" xpl:lib="/nop/biz/xlib/bo.xlib">
    <filter>
    <eq name="status" value="${AuthApiConstants.USER_STATUS_ACTIVE}"/>
    </filter>
    </bo:DoFindPage>
    </source>
    </query>
    - -

    这个函数定义等价于在Java中定义函数

    -

    @BizQuery
    public PageBean<NopAuthUser> active_findPage(@Name("query") QueryBean query,
    FieldSelection selection, IServiceContext ctx){
    return ...
    }
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/i18n/index.html b/projects/nop-entropy/docs/dev-guide/i18n/index.html index 8fc1514..fda9b3e 100644 --- a/projects/nop-entropy/docs/dev-guide/i18n/index.html +++ b/projects/nop-entropy/docs/dev-guide/i18n/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/ide/idea/index.html b/projects/nop-entropy/docs/dev-guide/ide/idea/index.html index 2aef9bf..967925d 100644 --- a/projects/nop-entropy/docs/dev-guide/ide/idea/index.html +++ b/projects/nop-entropy/docs/dev-guide/ide/idea/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1117 +186,83 @@ -
    +
    + + + +
    +
    +
    + + +

    安装JDK

    -
    +

    nop-chaos编译需要JDK11以上版本。 可以下载比较新的IDEA开发工具: Download

    +

    也可以通过菜单File/Project Structure/SDKS/Download SDK下载指定JDK版本。

    +

    idea-install-jdk

    +

    编译插件

    cd nop-idea-plugin
    gradlew buildPlugin
    +

    编译出来的插件存放在build/distributions目录下

    +

    安装插件

    编译nop-idea-plugin插件项目之后,点击 File/Settings/Plugins/Install Plugins From Disk菜单进行安装

    +

    idea-install-plugin

    +

    识别文件类型

    为了激活nop-idea-plugin插件的作用,文件类型必须是XLang DSL。可以点击菜单 File/Settings/Editor/File Types, 为XLang DSL增加文件名匹配模式。

    +

    idea-file-types

    +

    清空缓存

    插件使用过程中,如果IDEA异常关闭,可能导致文件索引损坏,插件无法正常工作。此时可以点击菜单 File/Invalidate Caches清空缓存,重建索引。

    +

    idea-clear-cache

    +

    更新 IDEA 之后,插件报错:Plugin ‘Nop Entropy’ (version ‘*’) is not compatible with the current version of the IDE, because it requires build * or older but the current build is *。

    这是因为插件的版本号不兼容当前IDEA版本。可以通过修改 build.gradle.kts 文件,将插件的版本号修改为当前IDEA版本号,之后重新编译插件。

    +
    patchPluginXml {
    sinceBuild.set("211")
    untilBuild.set("233.*") // 修改为当前IDEA版本号
    }
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    安装JDK

    - - - - -
    -

    nop-chaos编译需要JDK11以上版本。 可以下载比较新的IDEA开发工具: Download

    -

    也可以通过菜单File/Project Structure/SDKS/Download SDK下载指定JDK版本。

    -

    idea-install-jdk

    -

    编译插件

    cd nop-idea-plugin
    gradlew buildPlugin
    - -

    编译出来的插件存放在build/distributions目录下

    -

    安装插件

    编译nop-idea-plugin插件项目之后,点击 File/Settings/Plugins/Install Plugins From Disk菜单进行安装

    -

    idea-install-plugin

    -

    识别文件类型

    为了激活nop-idea-plugin插件的作用,文件类型必须是XLang DSL。可以点击菜单 File/Settings/Editor/File Types, 为XLang DSL增加文件名匹配模式。

    -

    idea-file-types

    -

    清空缓存

    插件使用过程中,如果IDEA异常关闭,可能导致文件索引损坏,插件无法正常工作。此时可以点击菜单 File/Invalidate Caches清空缓存,重建索引。

    -

    idea-clear-cache

    -

    更新 IDEA 之后,插件报错:Plugin ‘Nop Entropy’ (version ‘*’) is not compatible with the current version of the IDE, because it requires build * or older but the current build is *。

    这是因为插件的版本号不兼容当前IDEA版本。可以通过修改 build.gradle.kts 文件,将插件的版本号修改为当前IDEA版本号,之后重新编译插件。

    -
    patchPluginXml {
    sinceBuild.set("211")
    untilBuild.set("233.*") // 修改为当前IDEA版本号
    }
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/ide/plugin-dev/index.html b/projects/nop-entropy/docs/dev-guide/ide/plugin-dev/index.html index 260a657..69e5b6f 100644 --- a/projects/nop-entropy/docs/dev-guide/ide/plugin-dev/index.html +++ b/projects/nop-entropy/docs/dev-guide/ide/plugin-dev/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1117 +186,83 @@ -
    +
    + + + +
    +
    +
    + + +

    关联Gradle工程

    -
    +

    nop-idea-plugin工程是Gradle工程,在IDEA中可以鼠标右键点击文件build.gradle.kts,选择Link Gradle Project菜单

    +

    idea-link-gradle

    +

    调试

    导入Gradle工程之后,可以在Gradle任务的管理窗口中,选择Tasks/intellij/runIde任务,右键选择调试插件。
    IDEA会启动一个新的应用实例进行调试。

    +

    idea-plugin-runIde

    +

    插件功能

    语法校验

    XLangAnnotator负责检查XML文件是否符合xdef元模型定义

    +

    语法提示

    XLangCompletionContributor会根据xdef元模型定义,提示标签名、属性名、属性值等

    +

    快速文档

    鼠标悬停在标签名、属性名、属性值上的时候,会提示xdef元模型中定义的描述信息。实现类为 XLangDocumentationProvider。

    +

    链接跳转

    CTRL+鼠标悬停时会提示跳转到关联位置。XLangFileDeclarationHandler负责识别虚拟文件路径和XPL标签定义,并实现跳转。

    +

    断点调试

    XLangDebugExecutor负责增加与Debug/Run平级的调试执行按钮。

    +

    idea-xlang-executor

    +

    XLangDebuggerRunner负责启动调试器。具体实现方式是被调试程序启动一个RPC服务,对外暴露io.nop.api.debugger.IDebugger接口,在IDEA插件中通过远程RPC机制调用此接口,并接收返回消息。

    +

    虚拟文件系统

    Nop平台中通过单例对象VirtualFileSystem来访问虚拟文件系统,同时通过单例对象ResourceComponentManager来加载并缓存模型文件。

    +

    因为IDEA运行时可能打开多个Project,针对每个Project,nop-idea-plugin插件都必须建立独立的缓存。
    因此,在NopAppListener中对VirtualFileSystem/ResourceComponentManager/DictProvider等单例对象都注册了特殊的实现。它们会ProjectEnv类查找上下文环境中的Project对象,然后从中获取到NopProjectService服务,再利用该服务中的缓存来实现功能。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    关联Gradle工程

    - - - - -
    -

    nop-idea-plugin工程是Gradle工程,在IDEA中可以鼠标右键点击文件build.gradle.kts,选择Link Gradle Project菜单

    -

    idea-link-gradle

    -

    调试

    导入Gradle工程之后,可以在Gradle任务的管理窗口中,选择Tasks/intellij/runIde任务,右键选择调试插件。
    IDEA会启动一个新的应用实例进行调试。

    -

    idea-plugin-runIde

    -

    插件功能

    语法校验

    XLangAnnotator负责检查XML文件是否符合xdef元模型定义

    -

    语法提示

    XLangCompletionContributor会根据xdef元模型定义,提示标签名、属性名、属性值等

    -

    快速文档

    鼠标悬停在标签名、属性名、属性值上的时候,会提示xdef元模型中定义的描述信息。实现类为 XLangDocumentationProvider。

    -

    链接跳转

    CTRL+鼠标悬停时会提示跳转到关联位置。XLangFileDeclarationHandler负责识别虚拟文件路径和XPL标签定义,并实现跳转。

    -

    断点调试

    XLangDebugExecutor负责增加与Debug/Run平级的调试执行按钮。

    -

    idea-xlang-executor

    -

    XLangDebuggerRunner负责启动调试器。具体实现方式是被调试程序启动一个RPC服务,对外暴露io.nop.api.debugger.IDebugger接口,在IDEA插件中通过远程RPC机制调用此接口,并接收返回消息。

    -

    虚拟文件系统

    Nop平台中通过单例对象VirtualFileSystem来访问虚拟文件系统,同时通过单例对象ResourceComponentManager来加载并缓存模型文件。

    -

    因为IDEA运行时可能打开多个Project,针对每个Project,nop-idea-plugin插件都必须建立独立的缓存。
    因此,在NopAppListener中对VirtualFileSystem/ResourceComponentManager/DictProvider等单例对象都注册了特殊的实现。它们会ProjectEnv类查找上下文环境中的Project对象,然后从中获取到NopProjectService服务,再利用该服务中的缓存来实现功能。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/index.html b/projects/nop-entropy/docs/dev-guide/index.html index cb99216..3bb6881 100644 --- a/projects/nop-entropy/docs/dev-guide/index.html +++ b/projects/nop-entropy/docs/dev-guide/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/integration/index.html b/projects/nop-entropy/docs/dev-guide/integration/index.html index b9c7ce0..0222788 100644 --- a/projects/nop-entropy/docs/dev-guide/integration/index.html +++ b/projects/nop-entropy/docs/dev-guide/integration/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1111 +186,77 @@ -
    +
    + + + +
    +
    +
    + + +

    第三方框架集成

    -
    +

    Nop平台的核心模块都是从零开始编写,不依赖任何第三方框架。但是为了提高开发效率,Nop平台也提供了一些第三方框架的集成支持。
    它可以与Spring或者Quarkus框架集成在一起使用。基本做法都是先启动Spring或者Quarkus框架,然后监听Spring或者Quarkus的启动事件来启动Nop平台。

    +

    Nop平台的启动和停止使用如下调用:

    +
    CoreInitialization.initialize();
    CoreInitialization.destroy();
    + +

    Spring集成

    Spring集成配置参见spring.md

    +

    也可以改造Spring和MyBatis,加入部分可逆计算支持,参见spring-delta.md

    +

    Quarkus集成

    Quarkus集成配置参见quarkus.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    第三方框架集成

    - - - - -
    -

    Nop平台的核心模块都是从零开始编写,不依赖任何第三方框架。但是为了提高开发效率,Nop平台也提供了一些第三方框架的集成支持。
    它可以与Spring或者Quarkus框架集成在一起使用。基本做法都是先启动Spring或者Quarkus框架,然后监听Spring或者Quarkus的启动事件来启动Nop平台。

    -

    Nop平台的启动和停止使用如下调用:

    -
    CoreInitialization.initialize();
    CoreInitialization.destroy();
    - -

    Spring集成

    Spring集成配置参见spring.md

    -

    也可以改造Spring和MyBatis,加入部分可逆计算支持,参见spring-delta.md

    -

    Quarkus集成

    Quarkus集成配置参见quarkus.md

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/intro/index.html b/projects/nop-entropy/docs/dev-guide/intro/index.html index b63f4b8..fda9b3e 100644 --- a/projects/nop-entropy/docs/dev-guide/intro/index.html +++ b/projects/nop-entropy/docs/dev-guide/intro/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/ioc/aop/index.html b/projects/nop-entropy/docs/dev-guide/ioc/aop/index.html index b5c856e..b1dce2c 100644 --- a/projects/nop-entropy/docs/dev-guide/ioc/aop/index.html +++ b/projects/nop-entropy/docs/dev-guide/ioc/aop/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1116 +186,82 @@ -
    +
    + + + +
    +
    +
    + + +

    编译期代码生成

    -
    +

    Nop平台的AOP机制依赖于编译期代码生成,并不是在运行期动态生成字节码。

    +

    注意:必须先生成AOP包装类,然后NopIoC中的aop配置才能起作用

    +

    AOP包装类生成器

    GenAopProxy扫描指定工程下的target/classes目录以及target/test-classes目录,对其中的每个Java类生成aop包装类,
    生成代码输出到target/generated-sources目录和target/generated-test-sources目录。

    +
    File projectDir = ...;
    new GenAopProxy().execute(projectDir, generateForTestFile);
    + +

    在test目录下的XXXCodeGen.java中可以增加GenAopProxy调用。

    +
    public class AuthCodeGen {
    public static void main(String[] args) {
    CoreInitialization.initialize();
    try {
    File projectDir = MavenDirHelper.projectDir(AuthCodeGen.class);
    XCodeGenerator.runPrecompile(projectDir, "/", false);

    new GenAopProxy().execute(projectDir, false);
    new GenAopProxy().execute(projectDir, true);
    } finally {
    CoreInitialization.destroy();
    }
    }
    }
    + +

    通过maven工具生成AOP包装类

    在pom.xml中增加exec-maven-plugin配置,为了简单一般从nop-entropy的pom.xml继承,其中已经为exec-maven-plugin配置了aop代理生成功能。

    +
    <build>
    <plugins>
    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>
    +

    NopIoC配置

    在beans.xml中配置Interceptor,声明它可以应用到哪些注解以及它的应用优先级。
    NopIoC解析bean配置之后会检查所有的interceptor可以应用到容器中的哪些bean中,并将bean的class属性替换为对应的AOP包装类。

    +
    <bean id="nopTransactionalMethodInterceptor" ioc:default="true"
    class="io.nop.dao.txn.interceptor.TransactionalMethodInterceptor">
    <constructor-arg index="0" ref="nopTransactionTemplate"/>
    <ioc:pointcut annotations="io.nop.api.core.annotations.txn.Transactional"
    order="#{ApiConstants.INTERCEPTOR_PRIORITY_TRANSACTIONAL}"/>
    </bean>
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    编译期代码生成

    - - - - -
    -

    Nop平台的AOP机制依赖于编译期代码生成,并不是在运行期动态生成字节码。

    -

    注意:必须先生成AOP包装类,然后NopIoC中的aop配置才能起作用

    -

    AOP包装类生成器

    GenAopProxy扫描指定工程下的target/classes目录以及target/test-classes目录,对其中的每个Java类生成aop包装类,
    生成代码输出到target/generated-sources目录和target/generated-test-sources目录。

    -
    File projectDir = ...;
    new GenAopProxy().execute(projectDir, generateForTestFile);
    - -

    在test目录下的XXXCodeGen.java中可以增加GenAopProxy调用。

    -
    public class AuthCodeGen {
    public static void main(String[] args) {
    CoreInitialization.initialize();
    try {
    File projectDir = MavenDirHelper.projectDir(AuthCodeGen.class);
    XCodeGenerator.runPrecompile(projectDir, "/", false);

    new GenAopProxy().execute(projectDir, false);
    new GenAopProxy().execute(projectDir, true);
    } finally {
    CoreInitialization.destroy();
    }
    }
    }
    - -

    通过maven工具生成AOP包装类

    在pom.xml中增加exec-maven-plugin配置,为了简单一般从nop-entropy的pom.xml继承,其中已经为exec-maven-plugin配置了aop代理生成功能。

    -
    <build>
    <plugins>
    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>
    - -

    NopIoC配置

    在beans.xml中配置Interceptor,声明它可以应用到哪些注解以及它的应用优先级。
    NopIoC解析bean配置之后会检查所有的interceptor可以应用到容器中的哪些bean中,并将bean的class属性替换为对应的AOP包装类。

    -
    <bean id="nopTransactionalMethodInterceptor" ioc:default="true"
    class="io.nop.dao.txn.interceptor.TransactionalMethodInterceptor">
    <constructor-arg index="0" ref="nopTransactionTemplate"/>
    <ioc:pointcut annotations="io.nop.api.core.annotations.txn.Transactional"
    order="#{ApiConstants.INTERCEPTOR_PRIORITY_TRANSACTIONAL}"/>
    </bean>
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/ioc/index.html b/projects/nop-entropy/docs/dev-guide/ioc/index.html index 3521cec..0fc0528 100644 --- a/projects/nop-entropy/docs/dev-guide/ioc/index.html +++ b/projects/nop-entropy/docs/dev-guide/ioc/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/job/job-design/index.html b/projects/nop-entropy/docs/dev-guide/job/job-design/index.html index 13dc0e4..74ef4ba 100644 --- a/projects/nop-entropy/docs/dev-guide/job/job-design/index.html +++ b/projects/nop-entropy/docs/dev-guide/job/job-design/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/job/job/index.html b/projects/nop-entropy/docs/dev-guide/job/job/index.html index 3488e73..fda9b3e 100644 --- a/projects/nop-entropy/docs/dev-guide/job/job/index.html +++ b/projects/nop-entropy/docs/dev-guide/job/job/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/job/trigger/index.html b/projects/nop-entropy/docs/dev-guide/job/trigger/index.html index d6e0aba..fda9b3e 100644 --- a/projects/nop-entropy/docs/dev-guide/job/trigger/index.html +++ b/projects/nop-entropy/docs/dev-guide/job/trigger/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/microservice/feign/index.html b/projects/nop-entropy/docs/dev-guide/microservice/feign/index.html index bc2e126..cef5b35 100644 --- a/projects/nop-entropy/docs/dev-guide/microservice/feign/index.html +++ b/projects/nop-entropy/docs/dev-guide/microservice/feign/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1134 +186,100 @@ -
    +
    - -
    + - - - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    Feign集成

    - - - - -
    -

    springcloud中的Feign RPC框架本质上是架构在REST服务调用的基础上,原则上可以调用任何第三方的REST服务。因此NopRPC可以和Feign
    RPC混合在一起调用。

    -

    NopRPC目前集成了Nacos服务注册中心,因此只要SpringCloud也使用Nacos服务注册,就可以实现NopRPC和SpringCloud的互联互通。对于其他注册中心,
    原则上只要仿照nop-cluster-nacos模块中的做法,提供一个INamingService接口的实现即可。

    -

    1. Feign客户端调用 NopRPC服务端

    使用Feign的注解,单独编写一个Feign接口即可调用,NopRPC服务端不需要做任何处理。

    -

    @FeignClient(name="rpc-demo-service")
    public interface MyService {
    @PostMapping("/r/MyService__myMethod")
    ApiResponse<MyRespontBean> myMethod(@RequestBody MyRequest request, @QueryParam("%40selection") String selection);
    }
    - -
      -
    • NopRPC返回的结果类型固定为ApiResponse<T>类型, ApiResponse类定义在nop-api-core模块中。
    • -
    • NopRPC对外提供的REST接口url固定为/r/{bizObjName}__{bizMethod}形式,采用POST方式提交,通过body传递JSON数据
    • -
    • 可以通过在url中传递@selection=a,b,c{f,g}这种形式的字段选择表达式来实现类似GraphQL的字段选择机制
    • -
    -

    需要注意的是,Feign框架要求QueryParam的参数名必须是编码后的参数名,否则无法正常工作,所以@selection需要被替换为%40selection

    -

    2. 在NopRPC中调用Feign服务

    只需要引入普通的服务接口,并使用jaxrs注解来标记REST路径和参数名等

    -
    public interface EchoService {
    @Path("/echo/{id}")
    String echo(@QueryParam("msg") String msg, @PathParam("id") String id);
    }
    - -

    NopRPC使用NopIoC管理所有的服务对象,而NopIoC中所有的bean都需要在beans.xml中注册。注册服务对象只需要从AbstractRpcProxyFactoryBean继承,并指定服务名和服务接口即可

    -
    <bean id="testEchoService" parent="AbstractRpcProxyFactoryBean"
    ioc:type="io.nop.rpc.client.EchoService">
    <property name="serviceName" value="rpc-demo-producer"/>
    </bean>
    - -
      -
    • serviceName为服务提供端注册的服务名
    • -
    • ioc:type指定在本工程中指定的服务接口类。这种做法与Feign框架类型,客户端使用的接口与服务端使用的接口并没有直接关系,可以独立定义。
    • -
    -

    3. 在NopRPC中调用NopRPC服务端

    可以使用api.xlsx模型文件来定义API接口,然后通过代码生成模板/nop/templates/api来生成客户端接口定义以及服务端实现框架。

    -
    @BizModel("TestRpc")
    public interface TestRpc {
    @BizMutation
    ApiResponse<MyResponse> myMethod(ApiRequest<MyRequest> req);

    @BizMutation
    MyResponse myMethod(@RequestBean MyRequest req);

    @BizMutation
    CompletionStage<ApiResponse<MyResponse>> myMethodAsync(ApiRequest<MyRequest> req);
    }
    - -
      -
    • 在接口上通过@BizModel注解来指定对象名,通过@BizMutation@BizQuery等注解来标记GraphQL方法类型
    • -
    • 参数固定为ApiRequest<T>类型,也可以拆开写 RequestBean,并且可以传递额外的ICancelToken环境
    • -
    • 返回类型固定为ApiResponse<T>,如果直接返回T,则内部会判断ApiResponse是否成功,如果失败,自动把ApiResponse中的错误码和错误消息转换为Exception抛出。
    • -
    • 如果是异步调用,则返回类型为CompletionStage,方法名后增加Async后缀。注意,客户端接口的异步调用并不要求服务端采用异步方法实现,服务端可以是普通的同步函数。
    • -
    - -
    - -
    - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/microservice/grpc/index.html b/projects/nop-entropy/docs/dev-guide/microservice/grpc/index.html index 2aa2f2d..8e88892 100644 --- a/projects/nop-entropy/docs/dev-guide/microservice/grpc/index.html +++ b/projects/nop-entropy/docs/dev-guide/microservice/grpc/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/microservice/index.html b/projects/nop-entropy/docs/dev-guide/microservice/index.html index 5327bcb..e136e40 100644 --- a/projects/nop-entropy/docs/dev-guide/microservice/index.html +++ b/projects/nop-entropy/docs/dev-guide/microservice/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1109 +186,75 @@ -
    +
    + + + +
    +
    +
    + + +

    微服务框架

    -
    +

    分布式RPC

    集成nacos实现分布式RPC, 参见rpc.md

    +

    RPC框架的设计原理,参见rpc-design.md

    +

    过滤器

    Nop平台提供了一套基于过滤器的拦截机制,可以在请求处理前后进行拦截处理。filter的使用参见web-filter.md

    +

    Feign集成

    将NopRPC与Spring的Feign框架集成在一起使用,参见feign.md

    +

    gRPC集成

    通过简单配置即可将NopGraphQL中的服务函数暴露为gRPC服务,参见grpc.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    微服务框架

    - - - - -
    -

    分布式RPC

    集成nacos实现分布式RPC, 参见rpc.md

    -

    RPC框架的设计原理,参见rpc-design.md

    -

    过滤器

    Nop平台提供了一套基于过滤器的拦截机制,可以在请求处理前后进行拦截处理。filter的使用参见web-filter.md

    -

    Feign集成

    将NopRPC与Spring的Feign框架集成在一起使用,参见feign.md

    -

    gRPC集成

    通过简单配置即可将NopGraphQL中的服务函数暴露为gRPC服务,参见grpc.md

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/microservice/rpc-design/index.html b/projects/nop-entropy/docs/dev-guide/microservice/rpc-design/index.html index 81bcde1..07c54b3 100644 --- a/projects/nop-entropy/docs/dev-guide/microservice/rpc-design/index.html +++ b/projects/nop-entropy/docs/dev-guide/microservice/rpc-design/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/microservice/rpc/index.html b/projects/nop-entropy/docs/dev-guide/microservice/rpc/index.html index 28cef4e..b88cbff 100644 --- a/projects/nop-entropy/docs/dev-guide/microservice/rpc/index.html +++ b/projects/nop-entropy/docs/dev-guide/microservice/rpc/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/microservice/web-filter/index.html b/projects/nop-entropy/docs/dev-guide/microservice/web-filter/index.html index 928dc6a..6b580cd 100644 --- a/projects/nop-entropy/docs/dev-guide/microservice/web-filter/index.html +++ b/projects/nop-entropy/docs/dev-guide/microservice/web-filter/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1147 +186,113 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/model/api-model/index.html b/projects/nop-entropy/docs/dev-guide/model/api-model/index.html index 4cd871f..c9c3a83 100644 --- a/projects/nop-entropy/docs/dev-guide/model/api-model/index.html +++ b/projects/nop-entropy/docs/dev-guide/model/api-model/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1122 +186,88 @@ -
    +
    + + + +
    +
    +
    + + +

    Api模型

    -
    +

    通过Excel模型来定义对外暴露的服务接口。具体示例参见nop-wf.api.xlsx

    +

    在xxx-codegen模块中我们可以增加代码生成脚本,根据Excel模型自动生成代码。例如gen-orm.xgen中

    +
    <c:script>
    // 根据API模型生成服务消息和接口类
    codeGenerator.withTargetDir("../").renderModel('../../model/nop-wf.api.xlsx','/nop/templates/api', '/',$scope);
    </c:script>
    + +

    配置说明

    在【配置】页中可以配置如下变量

    +
      +
    1. apiName: 所有子模块的前缀,例如nop-wf
    2. +
    3. apiModuleName:生成接口定义以及接口消息类到哪个模块中,一般为xxx-api
    4. +
    5. serviceModuleName: 生成缺省的实现类到哪个模块中,一般为xxx-service
    6. +
    7. metaModuleName: 生成接口消息所对应的meta文件到哪个模块总,一般为xxx-meta
    8. +
    9. servicePackageName: 服务实现类所在的包名
    10. +
    11. apiPackageName: api模块的包名
    12. +
    +

    服务定义

    在【服务定义】页中可以定义当前模块对外暴露的所有服务。

    +
      +
    1. 【变更】用于配置服务方法是否对应于GraphQL中的mutation还是query
    2. +
    3. 【标签】列中可以为服务方法增加扩展标注。其中sync标识自动生成代码时后端服务函数是同步调用形式。如果没有加sync标签,则会生成返回值类型为CompletionStage形式的异步函数调用。
    4. +
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    Api模型

    - - - - -
    -

    通过Excel模型来定义对外暴露的服务接口。具体示例参见nop-wf.api.xlsx

    -

    在xxx-codegen模块中我们可以增加代码生成脚本,根据Excel模型自动生成代码。例如gen-orm.xgen中

    -
    <c:script>
    // 根据API模型生成服务消息和接口类
    codeGenerator.withTargetDir("../").renderModel('../../model/nop-wf.api.xlsx','/nop/templates/api', '/',$scope);
    </c:script>
    - -

    配置说明

    在【配置】页中可以配置如下变量

    -
      -
    1. apiName: 所有子模块的前缀,例如nop-wf
    2. -
    3. apiModuleName:生成接口定义以及接口消息类到哪个模块中,一般为xxx-api
    4. -
    5. serviceModuleName: 生成缺省的实现类到哪个模块中,一般为xxx-service
    6. -
    7. metaModuleName: 生成接口消息所对应的meta文件到哪个模块总,一般为xxx-meta
    8. -
    9. servicePackageName: 服务实现类所在的包名
    10. -
    11. apiPackageName: api模块的包名
    12. -
    -

    服务定义

    在【服务定义】页中可以定义当前模块对外暴露的所有服务。

    -
      -
    1. 【变更】用于配置服务方法是否对应于GraphQL中的mutation还是query
    2. -
    3. 【标签】列中可以为服务方法增加扩展标注。其中sync标识自动生成代码时后端服务函数是同步调用形式。如果没有加sync标签,则会生成返回值类型为CompletionStage形式的异步函数调用。
    4. -
    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/model/core-models/index.html b/projects/nop-entropy/docs/dev-guide/model/core-models/index.html index 27afa7f..b021164 100644 --- a/projects/nop-entropy/docs/dev-guide/model/core-models/index.html +++ b/projects/nop-entropy/docs/dev-guide/model/core-models/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/model/custom-model/index.html b/projects/nop-entropy/docs/dev-guide/model/custom-model/index.html index d2811a8..0e31aea 100644 --- a/projects/nop-entropy/docs/dev-guide/model/custom-model/index.html +++ b/projects/nop-entropy/docs/dev-guide/model/custom-model/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1130 +186,96 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/model/excel-model/index.html b/projects/nop-entropy/docs/dev-guide/model/excel-model/index.html index 5a24db4..e272421 100644 --- a/projects/nop-entropy/docs/dev-guide/model/excel-model/index.html +++ b/projects/nop-entropy/docs/dev-guide/model/excel-model/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/model/excel-xlsx/index.html b/projects/nop-entropy/docs/dev-guide/model/excel-xlsx/index.html index 6de0395..3665699 100644 --- a/projects/nop-entropy/docs/dev-guide/model/excel-xlsx/index.html +++ b/projects/nop-entropy/docs/dev-guide/model/excel-xlsx/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1116 +186,82 @@ -
    +
    + + + +
    +
    +
    + + +

    1. 解析Excel文件得到Workbook对象

    -
    +
    ExcelWorkbook wk = new ExcelWorkbookParser().parseFromVirtualPath(path);
    或者
    wk = new ExcelWorkbookParser().parseFromResource(new FileResource(file));
    + +

    2. 解析Excel文件得到领域对象

    根据imp.xml导入配置来实现自动解析Excel文件为领域模型对象。

    +
    FileResource resource = new FileResource(new File("c:/test.orm.xlsx"));
    OrmModel ormModel = (OrmModel) new XlsxObjectLoader("/nop/orm/imp/orm.imp.xml").parseFromResource(resource);
    + +

    3. 保存Workbook对象到文件中

    new ExcelTemplate(workbook).generateToFile(file, DisabledEvalScope.INSTANCE);
    + +

    4. 将Workbook转换为HTML格式

    ITemplateOutput output = reportEngine.getRendererForExcel(workbook, XptConstants.RENDER_TYPE_HTML);
    output.generateToFile(file, DisabledEvalScope.INSTANCE);

    或者

    ITextTemplateOutput output = reportEngine.getHtmlRenderer(workbook);
    String html = output.generateText(DisabledEvalScope.INSTANCE);
    + +

    5. 将领域对象保存为XLSX格式

    参考GenOrmHelper.saveOrmToExcel函数

    +
    IEvalScope scope = XLang.newEvalScope();
    scope.setLocalValue(null, XptConstants.VAR_ENTITY, ormModel);

    ExcelWorkbook workbook = reportEngine.buildXptModelFromImpModel("/nop/orm/imp/orm.imp.xml");
    ITemplateOutput output = reportEngine.getRendererForXptModel(workbook, "xlsx");
    output.generateToFile(outputFile, scope);
    +

    6. 解析ExcelSheet得到领域对象

    ExcelSheet configSheet = workbook.getSheet("Config");
    XLangCompileTool compileTool = XLang.newCompileTool().allowUnregisteredScopeVar(true);

    ImportModel importModel = ImportModelHelper.getImportModel(RuleConstants.IMP_PATH_RULE);
    ImportSheetModel sheetModel = importModel.getSheet(RuleConstants.SHEET_NAME_CONFIG);
    RuleModel rule = ImportModelHelper.parseSheet(sheetModel, configSheet, compileTool, RuleModel.class);
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    1. 解析Excel文件得到Workbook对象

    - - - - -
    -
    ExcelWorkbook wk = new ExcelWorkbookParser().parseFromVirtualPath(path);
    或者
    wk = new ExcelWorkbookParser().parseFromResource(new FileResource(file));
    - -

    2. 解析Excel文件得到领域对象

    根据imp.xml导入配置来实现自动解析Excel文件为领域模型对象。

    -
    FileResource resource = new FileResource(new File("c:/test.orm.xlsx"));
    OrmModel ormModel = (OrmModel) new XlsxObjectLoader("/nop/orm/imp/orm.imp.xml").parseFromResource(resource);
    - -

    3. 保存Workbook对象到文件中

    new ExcelTemplate(workbook).generateToFile(file, DisabledEvalScope.INSTANCE);
    - -

    4. 将Workbook转换为HTML格式

    ITemplateOutput output = reportEngine.getRendererForExcel(workbook, XptConstants.RENDER_TYPE_HTML);
    output.generateToFile(file, DisabledEvalScope.INSTANCE);

    或者

    ITextTemplateOutput output = reportEngine.getHtmlRenderer(workbook);
    String html = output.generateText(DisabledEvalScope.INSTANCE);
    - -

    5. 将领域对象保存为XLSX格式

    参考GenOrmHelper.saveOrmToExcel函数

    -
    IEvalScope scope = XLang.newEvalScope();
    scope.setLocalValue(null, XptConstants.VAR_ENTITY, ormModel);

    ExcelWorkbook workbook = reportEngine.buildXptModelFromImpModel("/nop/orm/imp/orm.imp.xml");
    ITemplateOutput output = reportEngine.getRendererForXptModel(workbook, "xlsx");
    output.generateToFile(outputFile, scope);
    - -

    6. 解析ExcelSheet得到领域对象

    ExcelSheet configSheet = workbook.getSheet("Config");
    XLangCompileTool compileTool = XLang.newCompileTool().allowUnregisteredScopeVar(true);

    ImportModel importModel = ImportModelHelper.getImportModel(RuleConstants.IMP_PATH_RULE);
    ImportSheetModel sheetModel = importModel.getSheet(RuleConstants.SHEET_NAME_CONFIG);
    RuleModel rule = ImportModelHelper.parseSheet(sheetModel, configSheet, compileTool, RuleModel.class);
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/model/index.html b/projects/nop-entropy/docs/dev-guide/model/index.html index 80858ca..94d1a70 100644 --- a/projects/nop-entropy/docs/dev-guide/model/index.html +++ b/projects/nop-entropy/docs/dev-guide/model/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1106 +186,72 @@ -
    +
    + + + +
    +
    +
    + + +

    Excel模型

    -
    +

    Excel数据模型

    读写Excel模型

    将Excel保存为html,将领域模型对象保存到XLSX格式等。

    +

    API模型

    自定义Excel模型

    除了使用平台的内置的数据模型、API模型等,我们还可以定制自己的领域模型。我们只需要编写imp导入模型文件,并把它注册到Nop平台中,就可以通过Excel文件来定义领域对象了。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    Excel模型

    - - - - -
    -

    Excel数据模型

    读写Excel模型

    将Excel保存为html,将领域模型对象保存到XLSX格式等。

    -

    API模型

    自定义Excel模型

    除了使用平台的内置的数据模型、API模型等,我们还可以定制自己的领域模型。我们只需要编写imp导入模型文件,并把它注册到Nop平台中,就可以通过Excel文件来定义领域对象了。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/nocode/dyn-model/index.html b/projects/nop-entropy/docs/dev-guide/nocode/dyn-model/index.html index 16cf153..d1d95f9 100644 --- a/projects/nop-entropy/docs/dev-guide/nocode/dyn-model/index.html +++ b/projects/nop-entropy/docs/dev-guide/nocode/dyn-model/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/nocode/dynamic-orm/index.html b/projects/nop-entropy/docs/dev-guide/nocode/dynamic-orm/index.html index 392ea80..db2cd61 100644 --- a/projects/nop-entropy/docs/dev-guide/nocode/dynamic-orm/index.html +++ b/projects/nop-entropy/docs/dev-guide/nocode/dynamic-orm/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1126 +186,92 @@ -
    +
    + + + +
    +
    +
    + + +

    内置工作流支持的动态实体

    -
    +

    NopORM引擎是一个完整的ORM引擎,不是专门为LowCode开发定制的一种狭窄用途的ORM引擎。基于NopORM的通用机制,平台也内置了一些LowCode专用的动态模型。

    +

    nop-dyn模块提供了一个NopDynEntity实体,它具有nopFlowId字段,可以自动与工作流引擎关联,作为工作流实例关联的业务实体来使用。无需建表,只要调整
    ORM配置即可利用基础的NopDynEntity分化出新的ORM实体对象(实体名和属性名不同),实际数据保存在nop_dyn_entity表(纵表)以及nop_dyn_entity_ext表的扩展字段中。

    +

    具体使用方法如下:

    +

    增加/_vfs/_delta/default/nop/dyn/orm/app.orm.xml文件,在其中增加动态实体定义

    <orm x:schema="/nop/schema/orm/orm.xdef" x:extends="super" xmlns:x="/nop/schema/xdsl.xdef" x:dump="false">

    <entities>

    <entity name="dyn.AppDynSalaryAdjustment" displayName="调薪申请" x:prototype="NopDynEntityTemplate">
    <filters>
    <filter name="nopObjType" value="AppDynSalaryAdjustment"/>
    </filters>

    <aliases>
    <alias name="employeeId" type="String" propPath="extFields.employeeId.string"/>
    <alias name="salary1" type="Double" propPath="extFields.salary1.double"/>
    <alias name="salary2" type="Double" propPath="extFields.salary2.double"/>
    </aliases>
    </entity>
    </entities>
    </orm>
    + +
      +
    1. x:prototype="NopDynEntityTemplate表示从nop-dyn-dao模块内置的NopDynEntityTemplate模板继承一些配置。NopDynEntityTemplate已经开启了扩展字段支持,
      扩展字段会存放在nop_dyn_entity_ext表中。
    2. +
    3. 动态实体实际存放在底层的NopDynEntity表中,只是每个动态实体都对应于不同的objType限制条件。通过filter配置过滤条件,从而从同一个业务对象中分化出多个具有不同属性的对象。
    4. +
    5. 通过alias可以将扩展字段重命名为具有业务含义的更加简洁的名称,在XScript脚本语言以及EQL查询语言中,alias可以看作是实体原生属性来使用。
    6. +
    7. extFields是将数据作为纵表保存,在NopDynEntity实体上还预留了stringValue1, longValue1等扩展字段,如果需要优化性能,可以将一些关键字段
      通过alias映射到这些预留字段上。预留字段上还可以建立索引,性能比extFields纵表扩展要好。
    8. +
    +

    完整实现

    从NopDynEntityTemplate继承是一种便捷的方式,但是它有一个限制就是必须定制nop-dyn-dao中的app.orm.xml模型文件,因为NopDynEntityTemplate节点是定义在这个文件中。

    +
    <!--
    必须将tagSet设置为空,去除继承的use-ext-field标签
    -->
    <entity name="NopDynEntityTemplate" x:abstract="true" registerShortName="true"
    x:prototype="io.nop.dyn.dao.entity.NopDynEntity" tableView="true" tagSet="">
    <relations>
    <to-many name="extFields" refEntityName="io.nop.dyn.dao.entity.NopDynEntityExt" keyProp="fieldName">
    <join>
    <on leftProp="id" rightProp="entityId"/>
    </join>
    </to-many>
    </relations>
    </entity>
    + +

    如果不想定制app.orm.xml,则需要将NopDynEntityTemplate的定义(包括它继承的NopDynEntity)的定义拷贝到其他模块中使用。

    +
    +

    拷贝过来的定义都要设置x:abstract=true,这表示它们仅仅作为模板使用,不会最终解析为具体的实体模型。

    +
    +
      +
    1. tableView表示本实体是在已有表的基础上所作的视图对象,不需要为本实体生成建表语句。
    2. +
    3. 如果需要限制视图不允许更新,可以设置readonly=true属性
    4. +
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/nocode/index.html b/projects/nop-entropy/docs/dev-guide/nocode/index.html index 3fc430d..9487ab5 100644 --- a/projects/nop-entropy/docs/dev-guide/nocode/index.html +++ b/projects/nop-entropy/docs/dev-guide/nocode/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/orm/dao-lib/index.html b/projects/nop-entropy/docs/dev-guide/orm/dao-lib/index.html index 97e579b..5261694 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/dao-lib/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/dao-lib/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1144 +186,110 @@ -
    +
    + + + +
    +
    +
    + + +

    在标签库中直接执行SQL语句

    -
    +

    <dao:FindPage xpl:lib='/nop/orm/xlib/dao.xlib' offset='0' limit='10'>
    select o from NopAuthUser o
    where o.id= ${id}
    </dao:FindPage>
    + +

    /nop/orm/xlib/dao.xlib提供了直接执行SQL语句的能力。在标签的body部分可以通过xpl标签动态生成SQL。

    +

    FindPage/FindFirst/FindAll标签的公共属性如下:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    名称说明
    sqlType值为sql或者eql,指定执行SQL语言还是EQL语言的语句
    rowType将查询得到的行数据包装为Java对象所对应的Java类
    querySpace查询空间,对应于不同的数据库链接
    timeoutSQL语句执行的超时时间
    cacheName缓存名称
    cacheKey缓存key
    disableLogicalDelete禁用逻辑删除条件
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    + - -
    diff --git a/projects/nop-entropy/docs/dev-guide/orm/dao/index.html b/projects/nop-entropy/docs/dev-guide/orm/dao/index.html index f7e0c66..d22c156 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/dao/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/dao/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1145 +186,111 @@ -
    +
    + + + +
    +
    +
    + + +

    基本约定

    -
    +

    IEntityDao接口提供了针对单实体对象的CRUD封装,一般开发CRUD功能无需编写Service类,也不需要像MyBatis那样封装SQL语句。
    EntityDao上提供的方法已经足够丰富,可以完成相当复杂的功能。

    +
    +

    自动生成的代码已经通过CrudBizModel实现了GraphQL层面的CRUD服务,一般只需要继承CrudBizModel,并做少量定制即可,不需要手工编写完整的CRUD实现。

    +
    +
      +
    1. findFirst前缀表示查找第一条,比如findFirstByExample, findFirstByQuery
    2. +
    3. findAll前缀表示返回满足条件的所有条目,比如findAllByExample, findAllByQuery
    4. +
    5. findPage前缀表示返回分页返回满足条件的条目,比如findPageByExample, findPageByQuery
    6. +
    7. loadEntityById按照Hibernate的惯例,它只是在内存中构建一个Proxy对象,并不真的查询数据库
    8. +
    9. getEntityById按照Hibernate的惯例,它会自动加载Proxy对象,确保内存中获取到实体数据,如果数据库中没有对应实体数据,则返回null
    10. +
    11. require前缀表示返回结果必须不为null,如果为null,则会抛出异常
    12. +
    13. batch前缀表示批量操作,例如batchDeleteEntities表示批量删除实体
    14. +
    +

    获取Dao对象

    @Inject
    IDaoProvider daoProvider;

    dao = daoProvider.daoFor(MyEntity.class);
    + +

    daoProvider统一关系系统中所有的dao对象,可以按照实体名、实体Java类、表名等不同方式获取到对应的dao对象。

    +

    在CrudBizModel的派生类中获取dao

      +
    1. 获取当前实体的dao: this.dao()
    2. +
    3. 获取指定类型实体的dao: this.daoFor(MyEntity.class)
    4. +
    +

    常用函数

    1. 按照属性查询

    MyEntity example = dao.newEntity();
    example.setMyField("a");
    // 查找满足条件的第一个
    MyEntity entity = dao.findFirstByExample(example);

    // require表示如果没有找到,则会抛出异常
    entity = dao.requireFirstByExample(example);
    + +

    2. 构造复杂查询条件

    QueryBean query = new QueryBean();
    query.setFilter(and(eq(MyEntity.PROP_NAME_myField,"a"), gt(MyEntity.PROP_NAME_myStatus,3)));
    query.setLimit(5);

    List<MyEntity> list = dao.findPageByQuery(query);
    + +

    FilterBeans类中定义了一些辅助函数,如and/or/eq,gt等,可以用于构建过滤条件。gt表示大于,ge表示大于等于,lt表示小于,le表示小于等于,eq表示等于

    +

    3. 新建并保存实体

    MyEntity entity = dao.newEntity();
    ...
    dao.saveEntity(entity);
    + +

    一般情况下我们应该使用dao.newEntity()函数创建实体,而不要直接使用new MyEntity()这种方式。这是因为当我们通过Delta定制方式来扩展实体类时,
    dao.newEntity()返回的Java对象可能是扩展类的对象,而不是当前实体类的对象。例如,我们在Delta模块中可以定义了class MyEntityEx extends MyEntity,
    然后配置ORM模型,使得test.MyEntity这个实体类名对应的Java类为MyEntityEx,则dao.newEntity()实际返回的是MyEntityEx

    +
    <orm>
    <entity name="test.MyEntity" class="test.MyEntityEx" >...</entity>
    </orm>
    + +

    4. 修改实体

    dao.saveOrUpdateEntity(entity);
    + +

    按照ORM引擎的一般原理,如果只是修改实体属性是不需要调用dao.updateEntity方法的。因为NopORM会通过OrmSession来管理所有的实体对象,当session.flush的时候
    会自动检查当前session中所有对象是否被修改,如果有修改,就会自动将修改同步到数据库中。dao.updateEntity()基本上是一个空函数,它只会做一些状态检查工作。

    +

    dao.saveOrUpdateEntity会根据实体上的状态标记信息来确定是否是新建的实体(Transient),如果是,则调用saveEntity,否则调用updateEntity

    +

    5. 删除实体

    dao.deleteEntity(entity);
    + +

    删除实体的时候,如果它的关联子表集合配置了cascade-delete,则子表集合中的元素也会被自动删除。

    +

    6. 批量加载属性

    JPA的一个常见性能问题是关联对象延迟加载导致出现N+1问题。IEntityDao提供了一个batchLoadProperties函数用于一次性加载所有关联属性。

    +
    List<MyEntity> list = dao.findAll();
    dao.batchLoadProps(list, Arrays.asList("parent","children","parent.parent"));
    + +

    内部实现方式有些类似于GraphQL的BatchDataLoader,只是它针对ORM实体的情况做了特别的优化。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/orm/data-change-log/index.html b/projects/nop-entropy/docs/dev-guide/orm/data-change-log/index.html index 1a894c2..da2f77e 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/data-change-log/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/data-change-log/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1119 +186,85 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    实体修改状态跟踪

    - - - - -
    -

    所有实体都从OrmEntity继承,在OrmEntity上提供了修改状态跟踪机制

    -
      -
    1. orm_propDirty(propId) 可以判断某个字段是否已经被修改
    2. -
    3. orm_propOldValue(propId) 返回修改前的值。如果没有被修改,则返回当前的值
    4. -
    5. orm_propValue(propId) 返回字段当前的值
    6. -
    7. orm_dirtyOldValues()和orm_dirtyNewValues() 返回所有被修改的字段的修改前和修改后的值,返回的Map的key为属性名
    8. -
    -

    修改监听器

    实现IOrmInterceptor接口,可以监听preSave/preUpdate/preDelete等事件,在其中记录修改日志。nop-sys模块提供了一个缺省的修改日志表,以及缺省实现

    -

    NopORM启动的时候会查找在IoC容器中查找所有IOrmInterceptor接口的实现类,

    -

    只要将IOrmInterceptor接口实现类注册到NopIoC容器中,OrmSessionFactoryBean初始化的时候就可以自动搜集得到所有的IOrmInterceptor,并自动应用。

    -
    -

    NopIoC的使用参见ioc.md。NopIoC缺省不使用类扫描机制,注册bean需要在beans.xml文件中增加bean的定义

    -
    -

    通过Xpl配置OrmInterceptor

    NopOrm内置引入的XplOrmInterceptorFactoryBean提供了一种灵活的OrmInterceptor定义机制。它的作用类似于是实现了实体级别的触发器机制。

    -

    只需要在各个模块增加/{moduleId}/orm/app.orm-interceptor.xml文件,就可以使用Xpl模板语言来实现OrmInterceptor。

    -

    <interceptor>
    <entity name="io.nop.auth.dao.entity.NopAuthUser">
    <post-save id="syncToEs">
    // 在这里可以写xpl脚本,entity对应于当前实体
    </post-save>
    </entity>
    </interceptor>
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/dialect/index.html b/projects/nop-entropy/docs/dev-guide/orm/dialect/index.html index f090455..4146e90 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/dialect/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/dialect/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1113 +186,79 @@ -
    +
    + + + +
    +
    +
    + + +

    Dialect的继承和定制

    -
    +

    NopOrm通过Dialect模型来封装不同数据库之间的差异。

    +

    default dialect

    +

    mysql dialect

    +

    postgresql dialect

    +

    参考上面的示例,mysql.dialect.xmlpostgresql.dialect.xml均从default.dialect.xml继承。与Hibernate通过编程方式构造Dialect对象相比,使用dialect模型文件明显信息密度更高,表达形式更加直观。更重要的是,在postgresql.dialect.xml中可以清楚的识别出相对于default.dialect.xml增加、修改和减少的配置。

    +

    因为整个Nop平台的底层都是基于可逆计算原理构建的,因此dialect模型文件的解析和验证可以由通用的DslModelParser完成,同时自动支持Delta定制,即在不修改default.dialect.xml文件,也不修改所有对default.dialect.xml文件的引用的情况下(例如不需要修改postgresql.dialect.xml中的x:extends属性),我们可以在/_delta目录下增加一个default.dialect.xml文件,通过它来定制系统内置的模型文件。

    +
    <!-- /_delta/myapp/nop/dao/dialect/default.dialect.xml -->
    <dialect x:extends="raw:/nop/dao/dialect/default.dialect.xml">
    这里只需要描述差量变化的部分
    </dialect>
    + +

    Delta定制类似Docker技术中的overlay fs差量文件系统,允许多个Delta层的叠加。与Docker不同的是,Delta定制不仅发生在文件层面,它还延展到文件内部的差量结构运算。借助于xdef元模型定义,Nop平台中的所有模型文件都自动支持Delta差量化定制

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    Dialect的继承和定制

    - - - - -
    -

    NopOrm通过Dialect模型来封装不同数据库之间的差异。

    -

    default dialect

    -

    mysql dialect

    -

    postgresql dialect

    -

    参考上面的示例,mysql.dialect.xmlpostgresql.dialect.xml均从default.dialect.xml继承。与Hibernate通过编程方式构造Dialect对象相比,使用dialect模型文件明显信息密度更高,表达形式更加直观。更重要的是,在postgresql.dialect.xml中可以清楚的识别出相对于default.dialect.xml增加、修改和减少的配置。

    -

    因为整个Nop平台的底层都是基于可逆计算原理构建的,因此dialect模型文件的解析和验证可以由通用的DslModelParser完成,同时自动支持Delta定制,即在不修改default.dialect.xml文件,也不修改所有对default.dialect.xml文件的引用的情况下(例如不需要修改postgresql.dialect.xml中的x:extends属性),我们可以在/_delta目录下增加一个default.dialect.xml文件,通过它来定制系统内置的模型文件。

    -
    <!-- /_delta/myapp/nop/dao/dialect/default.dialect.xml -->
    <dialect x:extends="raw:/nop/dao/dialect/default.dialect.xml">
    这里只需要描述差量变化的部分
    </dialect>
    - -

    Delta定制类似Docker技术中的overlay fs差量文件系统,允许多个Delta层的叠加。与Docker不同的是,Delta定制不仅发生在文件层面,它还延展到文件内部的差量结构运算。借助于xdef元模型定义,Nop平台中的所有模型文件都自动支持Delta差量化定制

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/dql/index.html b/projects/nop-entropy/docs/dev-guide/orm/dql/index.html index e2937ba..2acd92f 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/dql/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/dql/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1137 +189,103 @@ -
    +
    + + + +
    +
    +
    + + +

    -
    +

    润乾公司开源了一个前端BI系统,它在技术层面提出了一个别致的DQL(Dimentinal Query Language)语言。具体介绍可以参考乾学院的文章

    +

    告别宽表,用 DQL 成就新一代 BI - 乾学院

    +

    润乾的观点是终端用户难以理解复杂的SQL JOIN,为了便于多维分析,只能使用大宽表,这为数据准备带来一系列困难。而DQL则是简化了对终端用户而言JOIN操作的心智模型,并且在性能上相比于SQL更有优势。

    +

    以如何查找中国经理的美国员工为例

    +
    -- SQL
    SELECT A.*
    FROM 员工表 A
    JOIN 部门表 ON A.部门 = 部门表.编号
    JOIN 员工表 C ON 部门表.经理 = C.编号
    WHERE A.国籍 = '美国' AND C.国籍 = '中国'

    -- DQL
    SELECT *
    FROM 员工表
    WHERE 国籍='美国' AND 部门.经理.国籍='中国'
    + +

    这里的关键点被称为:外键属性化,也就是说外键指向表的字段可直接用子属性的方式引用,也允许多层和递归引用。

    +

    另一个类似的例子是根据订单表 (orders),区域表(area),查询订单的发货城市名称、以及所在的省份名称、地区名称。

    +
    -- DQL
    SELECT
    send_city.name city,
    send_city.pid.name province,
    send_city.pid.pid.name region
    FROM
    orders
    + +

    DQL的第二个关键思想是:同维表等同化,也就是一对一关联的表,不用明确写关联查询条件,可以认为它们的字段是共享的。例如,员工表和经理表是一对一的,我们需要查询所有员工的收入

    +
    -- SQL
    SELECT 员工表.姓名, 员工表.工资 + 经理表.津贴
    FROM 员工表
    LEFT JOIN 经理表 ON 员工表.编码 = 经理表.编号

    -- DQL
    SELECT 姓名,工资+津贴
    FROM 员工表
    + +

    DQL的第三个关键思想是:子表集合化,例如订单明细表可以看作是订单表的一个集合字段。如果要计算每张订单的汇总金额,

    +
    -- SQL
    SELECT T1.订单编号,T1.客户,SUM(T2.价格)
    FROM 订单表T1
    JOIN 订单明细表T2 ON T1.订单编号=T2.订单编号
    GROUP BY T1.订单编号,T1.客户

    -- DQL
    SELECT 订单编号,客户,订单明细表.SUM(价格)
    FROM 订单表
    + +

    “如果有多个子表时,SQL 需要分别先做 GROUP, 然后在一起和主表 JOIN 才行,会写成子查询的形式,但是 DQL 则仍然很简单,SELECT 后直接再加字段就可以了”。

    +

    DQL的第四个关键思想是:数据按维度自然对齐。我们不用特意指定关联条件,最终数据之所以能够放在同一张表里展示,原因不是因为它们之间存在什么先验的关联关系,仅仅是因为它们共享了最左侧的维度坐标而已。例如:我们希望按日期统计合同额、回款额和库存金额。我们需要从三个表分别取数据,然后按照日期对齐,汇总到结果数据集中。

    +
    -- SQL
    SELECT T1.日期,T1.金额,T2.金额, T3.金额
    FROM (SELECT 日期, SUM(金额) 金额 FROM 合同表 GROUP BY 日期)T1
    LEFT JOIN (SELECT 日期, SUM(金额) 金额 FROM 回款表 GROUP BY 日期)T2
    ON T1.日期 = T2.日期
    LEFT JOIN (SELECT 日期, SUM(金额) 金额 FROM 库存表 GROUP BY 日期 ) T3
    ON T2.日期 = T3.日期

    -- DQL
    SELECT 合同表.SUM(金额),回款表.SUM(金额),库存表.SUM(金额) ON 日期
    FROM 合同表 BY 日期
    LEFT JOIN 回款表 BY 日期
    LEFT JOIN 库存表 BY 日期
    + +

    在 DQL 中,维度对齐可以和外键属性化结合,例如

    +
    -- DQL
    SELECT 销售员.count(1),合同表.sum(金额) ON 地区
    FROM 销售员 BY 地区
    JOIN 合同表 BY 客户表.地区
    SELECT 销售员.count(1),合同表.sum(金额) ON 地区
    FROM 销售员 BY 地区
    JOIN 合同表 BY 客户表.地区
    + +

    如果从NopOrm的角度去看DQL的设计,则显然DQL本质上也是一种ORM的设计。

    +
      +
    1. DQL需要通过设计器定义主外键关联,并为每个字段指定界面上的显式名称,这一做法完全与ORM模型设计相同。

      +
    2. +
    3. DQL的外键属性化、同维等同化和子表集合化本质上就是EQL语法中的对象属性关联语法,只是它直接用数据库的关联字段作为关联对象名。这种做法比较简单,但缺点是对于复合主键关联的情况不太好处理。

      +
    4. +
    5. DQL的维度对齐是一个有趣的思想。它的具体实现应该是分多个SQL语句去加载数据,然后在内存中通过Hash Join来实现关联,速度很快。特别是在分页查询的情况下,我们可以只对主表进行分页查询,然后其他子表通过in条件只取本页数据涉及到的记录即可,在大表的情况下有可能加速很多。

      +
    6. +
    +

    Nop平台中的MdxQueryExecutor实现了类似DQL的维度对齐查询。因为EQL已经内置支持了对象属性关联,所以只要实现对QueryBean对象的拆分、分片执行、数据并置融合就可以了。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/orm/eql/index.html b/projects/nop-entropy/docs/dev-guide/orm/eql/index.html index 0163576..7c0e71d 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/eql/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/eql/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1136 +186,102 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/orm/ext-field/index.html b/projects/nop-entropy/docs/dev-guide/orm/ext-field/index.html index fefc8b0..c8dee3f 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/ext-field/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/ext-field/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/field-masking/index.html b/projects/nop-entropy/docs/dev-guide/orm/field-masking/index.html index 9bce2d5..a0531ef 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/field-masking/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/field-masking/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1116 +186,82 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    字段掩码

    - - - - -
    -

    处于安全性考虑,一些敏感的用户信息不允许打印到日志文件中,返回给前台演示的时候也需要进行掩码处理,不能显示全部内容,只能显示前几位、后几位等,
    例如信用卡卡号,用户的电话号码等。

    -

    在Excel模型中为列增加masked标签

    数据模型中标注的masked标签会生成到app.orm.xml模型文件中。当ORM引擎打印SQL语句时,所有具有masked标签的字段都显示为***XX。

    -
    -

    nop.core.default-masking-keep-chars 可以控制缺省掩码情况下显示最后几位字符,缺省为2

    -
    -

    在meta中为prop配置ui:maskPattern,控制显示前几位以及后几位字符

    <prop name="email" ui:maskPattern="3*4">

    </prop>
    - -

    ui:maskPattern="3*4" 表示保留前3位以及后4位字符,其他用*来替换。

    -

    程序控制

      -
    • 在Java代码中可以通过StringHelper.maskPattern(text,”3*4”) 这种调用来进行掩码处理。
    • -
    • 在sql-lib中,可以通过 ${masked(cardNo)} 来表示需要被掩码的SQL参数。masked函数将会把value包装为MaskedValue类型,这样处理之后当框架将它打印到日志文件中时会自动进行掩码处理
    • -
    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/index.html b/projects/nop-entropy/docs/dev-guide/orm/index.html index b46e149..e834e08 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1110 +186,76 @@ -
    +
    + + + +
    +
    +
    + + +

    [数据库方言](dialect.md)

    -
    +

    DAO封装

    针对单个实体对象的增删改查封装,支持复杂查询条件,支持分页。一般编写业务代码时我们只需要使用IEntityDao接口,而无需使用IOrmTemplate接口

    +

    ORM引擎

    类似JPA的完整的ORM引擎的实现,它支持EQL对象查询语言,支持租户过滤、级联删除、逻辑删除、字段自动加解密等功能。

    +

    事务管理

    多数据源

    数据修改历史

    多对多配置

    SQL管理

    类似于MyBatis的动态SQL管理框架。

    +

    增加扩展字段

    在不修改数据库的情况下,通过纵表来保存扩展字段名和扩展字段值,支持对扩展字段的查询和排序。在XPL模板语言中使用的时候,扩展字段和普通字段的使用方式完全一致,
    都是entity.fld属性访问语法。

    +

    DQL查询语言

    类似于润乾DQL查询语言的查询机制,可以简化BI系统的数据获取

    +

    字段掩码

    信用卡号等敏感数据显示到界面上或者打印到日志中时需要进行掩码处理

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    [数据库方言](dialect.md)

    - - - - -
    -

    DAO封装

    针对单个实体对象的增删改查封装,支持复杂查询条件,支持分页。一般编写业务代码时我们只需要使用IEntityDao接口,而无需使用IOrmTemplate接口

    -

    ORM引擎

    类似JPA的完整的ORM引擎的实现,它支持EQL对象查询语言,支持租户过滤、级联删除、逻辑删除、字段自动加解密等功能。

    -

    事务管理

    多数据源

    数据修改历史

    多对多配置

    SQL管理

    类似于MyBatis的动态SQL管理框架。

    -

    增加扩展字段

    在不修改数据库的情况下,通过纵表来保存扩展字段名和扩展字段值,支持对扩展字段的查询和排序。在XPL模板语言中使用的时候,扩展字段和普通字段的使用方式完全一致,
    都是entity.fld属性访问语法。

    -

    DQL查询语言

    类似于润乾DQL查询语言的查询机制,可以简化BI系统的数据获取

    -

    字段掩码

    信用卡号等敏感数据显示到界面上或者打印到日志中时需要进行掩码处理

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/many-to-many/index.html b/projects/nop-entropy/docs/dev-guide/orm/many-to-many/index.html index 9b0a9ab..152822a 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/many-to-many/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/many-to-many/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1116 +186,82 @@ -
    +
    + + + +
    +
    +
    + + +

    多对多关联

    -
    +

    视频演示

    +

    多对多关联在数据库层面一般是通过引入中间关联表来实现,例如nop_auth_user_role表实现user_id和role_id之间的多对多关联。

    +

    在NopOrm引擎内部并没有针对多对多关联的内置支持,它只支持to-one和to-many两种关联形式。 Nop平台的做法是在应用层生成一些帮助函数,然后把多对多关联分解到
    一对多关联形式上。具体做法如下:

    +
    import java.util.List;

    class NopAuthUser extends OrmEntity {
    public IOrmEntitySet<NopAuthUserRole> getUserRoles() {
    返回指向中间表实体的集合对象
    }

    public List<NopAuthRole> getRelatedRoleList() {
    // getRefProps是一个帮助函数,遍历集合返回集合元素上的指定属性
    return (List<NopAuthRole>) OrmEntityHelper.getRefProps(getUserRoles(),"role");
    }

    public List<String> getRelatedRoleIdList(){
    return (List<String>) OrmEntityHelper.getRefProps(getUserRoles(),"roleId");
    }

    public void setRelatedRoleIdList(List<String> roleIds){
    // setRefProps内部会识别roleId是否已经存在,是否需要新建NopAuthUserRole对象,是否需要删除集合中已经不再被使用的对象
    OrmEntityHelper.setRefProps(getUserRoles(),"roleId",roleIds);
    }
    }
    + +

    OrmEntityHelper仅仅是在Java实体层面提供一些帮助函数,简化我们从关联实体集合中存取相关属性的过程。

    +
    +

    借助于ORM引擎所提供的对象关联,我们可以在聚合实体上提供很多帮助性的get/set方法,并把它们暴露为外部可以访问的GraphQL服务,从而简化外部接口。

    +
    +

    Excel模型配置

    在Excel数据模型中,只需要为中间表实体增加many-to-many标签,则会自动生成以上方法。

    +

    界面控件

    缺省情况下多对多关联属性,例如上面的relatedRoleIdList会通过picker控件弹出选择。

    +

    多对多关联表作为一对一关联使用

    虽然中间表一般是用来表达多对多关联。但是有的时候我们暂时只存在一对一关联,则可以在Excel模型上标注one-to-one,则会自动生成针对单个对象的关联属性。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    多对多关联

    - - - - -
    -

    视频演示

    -

    多对多关联在数据库层面一般是通过引入中间关联表来实现,例如nop_auth_user_role表实现user_id和role_id之间的多对多关联。

    -

    在NopOrm引擎内部并没有针对多对多关联的内置支持,它只支持to-one和to-many两种关联形式。 Nop平台的做法是在应用层生成一些帮助函数,然后把多对多关联分解到
    一对多关联形式上。具体做法如下:

    -
    import java.util.List;

    class NopAuthUser extends OrmEntity {
    public IOrmEntitySet<NopAuthUserRole> getUserRoles() {
    返回指向中间表实体的集合对象
    }

    public List<NopAuthRole> getRelatedRoleList() {
    // getRefProps是一个帮助函数,遍历集合返回集合元素上的指定属性
    return (List<NopAuthRole>) OrmEntityHelper.getRefProps(getUserRoles(),"role");
    }

    public List<String> getRelatedRoleIdList(){
    return (List<String>) OrmEntityHelper.getRefProps(getUserRoles(),"roleId");
    }

    public void setRelatedRoleIdList(List<String> roleIds){
    // setRefProps内部会识别roleId是否已经存在,是否需要新建NopAuthUserRole对象,是否需要删除集合中已经不再被使用的对象
    OrmEntityHelper.setRefProps(getUserRoles(),"roleId",roleIds);
    }
    }
    - -

    OrmEntityHelper仅仅是在Java实体层面提供一些帮助函数,简化我们从关联实体集合中存取相关属性的过程。

    -
    -

    借助于ORM引擎所提供的对象关联,我们可以在聚合实体上提供很多帮助性的get/set方法,并把它们暴露为外部可以访问的GraphQL服务,从而简化外部接口。

    -
    -

    Excel模型配置

    在Excel数据模型中,只需要为中间表实体增加many-to-many标签,则会自动生成以上方法。

    -

    界面控件

    缺省情况下多对多关联属性,例如上面的relatedRoleIdList会通过picker控件弹出选择。

    -

    多对多关联表作为一对一关联使用

    虽然中间表一般是用来表达多对多关联。但是有的时候我们暂时只存在一对一关联,则可以在Excel模型上标注one-to-one,则会自动生成针对单个对象的关联属性。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/multi-datasource/index.html b/projects/nop-entropy/docs/dev-guide/orm/multi-datasource/index.html index 43037aa..5f64d49 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/multi-datasource/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/multi-datasource/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1132 +186,98 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/orm/multi-db/index.html b/projects/nop-entropy/docs/dev-guide/orm/multi-db/index.html index c90b7b3..3572529 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/multi-db/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/multi-db/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1128 +186,94 @@ -
    +
    + + + +
    +
    +
    + + +

    多数据源配置

    -
    +

    NopOrm引擎中每个querySpace对应于一个独立的DataSource。

    +

    1. 配置多个DataSource

    可以配置多个DataSource,命名格式为 nopDataSource_{querySpace}。后缀名对应于querySpace

    +
    <bean id="nopDataSource_test"
    class="com.zaxxer.hikari.HikariDataSource">
    <constructor-arg index="0">
    <bean class="com.zaxxer.hikari.HikariConfig">
    <property name="driverClassName" value="org.h2.Driver"/>
    <property name="jdbcUrl" value="jdbc:h2:mem:test"/>
    <property name="username" value="sa"/>
    <property name="password" value=""/>
    <property name="maximumPoolSize" value="8"/>
    </bean>
    </constructor-arg>
    </bean>
    + +

    在dao-defaults.beans.xml中,会自动收集所有前缀为nopDataSource_的bean

    +
    <bean id="nopTransactionManager" ioc:default="true"
    class="io.nop.dao.txn.impl.DefaultTransactionManager">
    <property name="defaultFactory" ref="nopTransactionFactory"/>

    <property name="dataSourceMap">
    <ioc:collect-beans only-concrete-classes="true" as-map="true" name-prefix="nopDataSource_"/>
    </property>
    </bean>
    + +

    2. 不同的实体属于不同的数据库

    在app.orm.xml模型文件中,针对每个实体可以指定不同的querySpace

    +
    <entity name="test.TestGeo" querySpace="test">
    ...
    </entity>
    + +

    3. 在sql-lib中可以为SQL语句指定querySpace

    <sql name="getAllLocations" querySpace="test" sqlMethod="findAll">
    <source>
    select location from test_geo
    </source>
    </sql>
    + +

    4. 直接执行SQL时指定querySpace

    构造SQL对象时可以直接指定querySpace

    +
    jdbcTemplate.executeUpdate(SQL.begin().querySpace("test").sql("update ...").end());
    + +

    5. 直接为数据源指定dialect

    一般情况下会根据DataSource获取到Connection,然后猜测得到对应的数据库方言。如果需要,也可以直接指定

    +
    nop:
    dao:
    config:
    query-space-to-dialect: test=h2gis
    + +

    上面示例指定querySpace=test对应的数据源使用h2gis这个方言

    +

    6. 数据库事务

    在NopOrm引擎中,只有ormTemplate.flush()调用的时候才会执行数据库操作,只有在flush函数中才会真正打开JDBC事务。因此业务处理异常时一般还没有执行数据库更新动作,不涉及到数据库回滚的问题。

    +

    对于多数据源配置,我们可以配置多个querySpace对应于一个事务组,则提交的时候会先执行所有数据库访问操作,等所有数据库操作都执行成功之后再逐个commit。

    +
    nop.dao.config.txn-group-map= test=default
    + +

    以上配置表示querySpace=test的数据库操作归属于default这个事务组

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/orm/null-value/index.html b/projects/nop-entropy/docs/dev-guide/orm/null-value/index.html index f4dcc13..2c32424 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/null-value/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/null-value/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1107 +186,73 @@ -
    +
    + + + +
    +
    +
    + + +

    空值的处理

    -
    +

    不同的数据库对于空字符串的处理逻辑不一致。Oracle数据库不支持空字符串,当一个字段值被设置为空字符串时,实际保存到数据库中的是null值。

    +

    NopORM为了确保在不同数据库之间的可迁移性,它对于空字符串进行了特殊识别和处理,具体代码参见DialectImpl.getDataParameterBinder函数的实现。

    +

    如果字段值设置为空字符串,则保存到数据库中的时候会自动修改为null。可以通过设置nop.orm.auto_convert_empty_string_to_null来关闭这一行为。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    空值的处理

    - - - - -
    -

    不同的数据库对于空字符串的处理逻辑不一致。Oracle数据库不支持空字符串,当一个字段值被设置为空字符串时,实际保存到数据库中的是null值。

    -

    NopORM为了确保在不同数据库之间的可迁移性,它对于空字符串进行了特殊识别和处理,具体代码参见DialectImpl.getDataParameterBinder函数的实现。

    -

    如果字段值设置为空字符串,则保存到数据库中的时候会自动修改为null。可以通过设置nop.orm.auto_convert_empty_string_to_null来关闭这一行为。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/orm-basic/index.html b/projects/nop-entropy/docs/dev-guide/orm/orm-basic/index.html index 95362e7..8572657 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/orm-basic/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/orm-basic/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/orm/index.html b/projects/nop-entropy/docs/dev-guide/orm/orm/index.html index a1f50ae..d716a13 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/orm/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/orm/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1140 +186,106 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/orm/session-cache/index.html b/projects/nop-entropy/docs/dev-guide/orm/session-cache/index.html index 7af471e..16cd027 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/session-cache/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/session-cache/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1129 +186,95 @@ -
    +
    + + + +
    +
    +
    + + +

    一级缓存

    -
    +

    NopORM与Hibernate类似,作为一个完整设计的ORM引擎,它提供了Session概念,所有通过ORM引擎获取的实体数据都缓存到当前打开的OrmSession对象中。
    当调用session.flush()函数时,NopORM引擎会递归遍历session中所有实体对象,如果发现entity.orm_isDirty()
    或者实体处于transient状态或者Deleting状态,
    则生成对应的sql语句真正对数据库进行修改。执行SQL语句时会尽量利用JDBC的Batch优化机制,提升数据库性能

    +
    +

    ,一般在开启事务的情况下,PrepareStatement的executeBatch函数执行性能最高。具体代码参见JdbcBatcher.java

    +
    +

    借助于实体对象实现OrmSession级别的业务数据缓存

    在OrmSession打开期间,所有获取到的实体数据都会缓存到OrmSession中,而且确保一个主键值只对应于唯一的一个Java实体对象
    如果两次SQL查询都包含了同样的实体数据,则会自动使用同一个实体对象,第二次从数据库中查询得到的数据会被自动放弃。例如

    +
    List<MyEntity> list = dao.findPage(query1);
    assertEquals("abc", list.get(0).getName());

    list.get(0).setName("sss");

    List<MyEntity> list2 = dao.findPage(query2);
    assertTrue(list.get(0) == list2.get(0));
    assertEquals("sss", list2.get(0).getName());

    assertEquals("sss", dao.getEntityById(list2.get(0).getId());
    + +
      +
    1. 根据查询条件query1返回实体列表,其中第一条记录的name的值为abc,它对应数据库中的值也是abc。
    2. +
    3. 在第一次查询后我们将实体对象的属性修改为sss,此时因为我们没有调用session.flush,所以内存中的修改并没有同步到数据库中。
    4. +
    5. 我们再次查询时,在JDBC层面会返回数据库中的当前值,即name=abc
    6. +
    7. 但是当JDBC查询得到的数据集被包装为Java实体对象时,NopORM引擎会根据实体对象的主键查找当前OrmSession中是否已经存在了对应的实体对象。此时发现OrmSession中
      已经存在了对应的记录,引擎会自动丢弃从数据库中获取到的记录值(name=abc
      ),而使用当前OrmSession中已经存在的实体对象来代替(name=sss)。
    8. +
    9. 根据id获取实体时,如果当前OrmSession中已经存在对应实体对象,则会直接返回,跳过数据库访问。
    10. +
    +

    利用NopORM引擎这种内置的Session级别的缓存机制(在Hibernate的技术体系中称为一级缓存),我们可以很自然的将实体对象作为业务数据的一种缓存容器。

    +
    class MyEntity extends OrmEntity {
    private MyCachedData cachedData;

    public MyCachedData getCachedData() {
    if (cachedData == null) {
    cachedData = buildCachedDataFromRelatedObjects();
    }
    return cachedData;
    }
    }
    + +

    因为实体对象总是按主键被缓存,因此一些业务层面的缓存计算结果可以直接存放在实体上。

    +

    OrmEntity内置了一个Map类型的缓存属性_t,我们在报表引擎中可以利用这个属性来缓存一些报表计算的中间结果。

    +
    entity.make_t().put("total",computeTotal());
    entity.get_t().get("total");
    + +

    概念层面不属于实体对象的缓存数据

    如果需要缓存的业务数据不方便设置到实体对象上,则我们可以使用OrmSession中内置的sessionCache对象。

    +
    interface IOrmTemplate{
    ICache<Object, Object> sessionCache();

    <T> T cacheGet(Object key, Supplier<T> loader);
    }
    +

    通过NopORM引擎获取数据时,可以指定缓存的key对象。

    +
    Object cacheKey = Arrays.asList("MyEntity","queryCondition",key1,key2);
    ormTemplate.cacheGet(cacheKey, ()-> dao.findListByQuery(query)));
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/orm/sql-lib/index.html b/projects/nop-entropy/docs/dev-guide/orm/sql-lib/index.html index ce88b2b..15ca115 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/sql-lib/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/sql-lib/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    + + +
    +
    @@ -1404,20 +357,6 @@

    SQL.begin().allowUnderscoreName(true).sql("....").end();

    + + +
    -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/orm/tcc/index.html b/projects/nop-entropy/docs/dev-guide/orm/tcc/index.html index a0b9fa6..3245db8 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/tcc/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/tcc/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/orm/to-one-relation/index.html b/projects/nop-entropy/docs/dev-guide/orm/to-one-relation/index.html index ea2d56b..9a7c9ab 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/to-one-relation/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/to-one-relation/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1127 +186,93 @@ -
    +
    + + + +
    +
    +
    + + +

    多对一或者一对一关联

    -
    +

    在Excel数据模型中只需要配置子表到父表的外键关联:
    to-one关联。如果需要在父表实体上增加集合属性,则只需要设置to-one关联上的关联属性名(relatedPropName)即可。

    +

    +

    例如,在nop_auth_user_role表中的user_id字段关联了nop_auth_user表。只需要在nop_auth_user_role的配置中增加to-one关联属性,属性名user,
    关联的实体对象是NopAuthUser。因为设置了关联属性名roleMappings,代码生成时NopAuthUser对象上会增加一个Set
    类型的集合属性,
    属性名为roleMappings。具体生成的实体类伪代码如下:

    +
    class NopAuthUserRole {
    String userId;
    NopAuthUser user;

    // ...
    }

    class NopAuthUser {
    //...
    Set<NopAuthUserRole> roleMappings;
    }
    + +

    支持关联查询

    定义了关联属性之后后台代码就可以直接使用关联查询了。但是为了暴露GraphQL服务还需要在meta文件中进行配置

    +
    +

    要求在meta中配置主要是从安全性考虑,避免暴露太多的功能给前端,出现安全漏洞。比如前端不断发起对关联的大表的各种复杂查询请求。

    +
    +

    为关联对象增加queryable和sortable标签

    如果关联的to-one属性上具有queryable标签则表示关联对象上的所有属性都可以参与查询。如果具有sortable标签,则表示关联对象上的所有属性都可以作为排序条件
    在Excel数据模型中增加对应标签即可。

    +

    逐个配置可查询字段

    如果不想开放整个关联对象上的属性,在可以逐个指定。

    +

    具体参见NopAuthOpLog.xmeta
    中的配置

    +

    <meta>
    <props>
    <prop name="session.loginAddr" displayName="登录地址" queryable="true" sortable="true">
    </prop>
    </props>
    </meta>
    + +

    queryable表示该字段可查询,sortable表示该字段可排序。此外还可以设置insertable,updatable等属性。

    +

    在前端使用关联属性

    在前端的XView模型中就可以使用session.loginAddr这样的字段了。

    +

    <grid>
    <cols>
    <col id="sessionId"/>
    <col id="session.loginAddr" sortable="true"/>
    </cols>
    </grid>
    + +

    meta中prop的sortable是后台服务是否支持排序,而grid的prop上的sortable则是在前台是否允许排序

    +

    sessionId是列表中已有的字段。session.loginAddr是新增的关联字段,它被插入到sessionId字段的后面。

    +
    +
    +

    Nop平台的Delta合并策略会尽量保持原有节点顺序,具体规则参见 x-override.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/orm/transaction/index.html b/projects/nop-entropy/docs/dev-guide/orm/transaction/index.html index 55e9579..16b7f44 100644 --- a/projects/nop-entropy/docs/dev-guide/orm/transaction/index.html +++ b/projects/nop-entropy/docs/dev-guide/orm/transaction/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1120 +186,86 @@ -
    +
    + + + +
    +
    +
    + + +

    事务模板

    -
    +

    在Nop平台中主要通过TransactionTemplate来控制事务范围,它的设计类似于Spring框架中的事务模板对象,只是增加了异步上下文支持。

    +

    在代码中我们可以通过依赖注入来获得事务模板。

    +
    @Inject
    ITransactionTemplate transactionTemlate;

    public void myMethod(){
    transactionTemplate.runInTransaction(null, TransactionPropagation.REQUIRED, txn-> doSomething());
    }
    + +

    因为Nop平台的JdbcTransaction的实现做了如下优化:

    +
      +
    1. 延迟获取连接: 开启事务后并没有立刻获取JDBC连接,只有第一次访问到数据库时才真的获取连接。
    2. +
    3. 主动释放连接: 如果执行了commit操作,则主动释放JDBC连接(此时事务并没有关闭)。因为事务已经提交,后面再访问数据库的时候可以获取新的连接。
    4. +
    +

    @Transactional注解

    在应用代码中可以通过 @Transactional注解来标记Java方法需要在事务环境中执行。限制条件是AOP增强由NopIoC引擎负责执行,因此只有在beans.xml文件中注册的bean才具有事务支持。
    而且AOP会提前生成代码,

    +

    注意这里的Transactional是Nop平台的注解,而不是Spring框架的注解。Nop平台内部功能不依赖于Spring框架

    +

    @BizMutation

    NopGraphQL引擎对应mutation操作会自动开启事务。所以只要方法上增加了@BizMutation注解就不用再额外增肌@Transactional注解。

    +
    @BizModel("NopAuthUser")
    @Locale("zh-CN")
    public class NopAuthUserBizModel extends CrudBizModel<NopAuthUser> {
    @Description("@i18n:common.resetUserPassword")
    @BizMutation
    @BizAudit(logRequestFields = "userId")
    public void resetUserPassword(@Name("userId") String userId,
    @Name("password") String password,
    IServiceContext context) {
    NopAuthUser user = this.get(userId, false, context);
    ...
    }
    }
    + +

    多数据源事务

    参见 multi-db.md

    +

    NopORM引擎支持同时使用多个数据源,例如一些表存放在数据库A中,另一些表存放在数据库B中,它们映射到实体对象后可以存在于同一个OrmSession中。
    缺省情况下,所有的的数据源都属于同一个事务组(txnGroup=default),当打开事务的时候会认为打开的是事务组,然后不同数据源的事务都挂接在这一个事务组中。
    事务组提交的时候会逐一提交打开的下层数据源的事务。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    事务模板

    - - - - -
    -

    在Nop平台中主要通过TransactionTemplate来控制事务范围,它的设计类似于Spring框架中的事务模板对象,只是增加了异步上下文支持。

    -

    在代码中我们可以通过依赖注入来获得事务模板。

    -
    @Inject
    ITransactionTemplate transactionTemlate;

    public void myMethod(){
    transactionTemplate.runInTransaction(null, TransactionPropagation.REQUIRED, txn-> doSomething());
    }
    - -

    因为Nop平台的JdbcTransaction的实现做了如下优化:

    -
      -
    1. 延迟获取连接: 开启事务后并没有立刻获取JDBC连接,只有第一次访问到数据库时才真的获取连接。
    2. -
    3. 主动释放连接: 如果执行了commit操作,则主动释放JDBC连接(此时事务并没有关闭)。因为事务已经提交,后面再访问数据库的时候可以获取新的连接。
    4. -
    -

    @Transactional注解

    在应用代码中可以通过 @Transactional注解来标记Java方法需要在事务环境中执行。限制条件是AOP增强由NopIoC引擎负责执行,因此只有在beans.xml文件中注册的bean才具有事务支持。
    而且AOP会提前生成代码,

    -

    注意这里的Transactional是Nop平台的注解,而不是Spring框架的注解。Nop平台内部功能不依赖于Spring框架

    -

    @BizMutation

    NopGraphQL引擎对应mutation操作会自动开启事务。所以只要方法上增加了@BizMutation注解就不用再额外增肌@Transactional注解。

    -
    @BizModel("NopAuthUser")
    @Locale("zh-CN")
    public class NopAuthUserBizModel extends CrudBizModel<NopAuthUser> {
    @Description("@i18n:common.resetUserPassword")
    @BizMutation
    @BizAudit(logRequestFields = "userId")
    public void resetUserPassword(@Name("userId") String userId,
    @Name("password") String password,
    IServiceContext context) {
    NopAuthUser user = this.get(userId, false, context);
    ...
    }
    }
    - -

    多数据源事务

    参见 multi-db.md

    -

    NopORM引擎支持同时使用多个数据源,例如一些表存放在数据库A中,另一些表存放在数据库B中,它们映射到实体对象后可以存在于同一个OrmSession中。
    缺省情况下,所有的的数据源都属于同一个事务组(txnGroup=default),当打开事务的时候会认为打开的是事务组,然后不同数据源的事务都挂接在这一个事务组中。
    事务组提交的时候会逐一提交打开的下层数据源的事务。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/quarkus/index.html b/projects/nop-entropy/docs/dev-guide/quarkus/index.html index eaaaf66..e274237 100644 --- a/projects/nop-entropy/docs/dev-guide/quarkus/index.html +++ b/projects/nop-entropy/docs/dev-guide/quarkus/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1138 +186,104 @@ -
    +
    - -
    + - - - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    日志配置

    - - - - -
    -

    日志格式

    在Quarkus中,日志格式 %d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n 表示以下内容:

    -
      -
    • %d{yyyy-MM-dd HH:mm:ss,SSS} : 日期和时间的格式,例如 “2022-01-01 12:34:56,789”,其中 SSS 表示毫秒。
    • -
    • %h : 主机名。
    • -
    • %N[%i] : 线程名称和线程ID。
    • -
    • %-5p : 日志级别,左对齐并且最多占据5个字符的宽度。
    • -
    • [%c{3.}] : 类名,最多显示3个字符。
    • -
    • (%t) : 线程上下文。
    • -
    • %s : 日志消息。
    • -
    • %e : 异常信息。
    • -
    • %n : 换行符。
    • -
    -

    这个日志格式的含义是,每条日志记录将包含日期、时间、主机名、线程名称和ID、日志级别、类名、线程上下文、日志消息和异常信息,并以换行符结束。

    -

    配置示例


    quarkus:
    log:
    level: INFO

    category:
    "io.nop":
    level: DEBUG

    file:
    enable: true
    path: log/app-demo.log
    # # 输出格式
    # format: %d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n
    # # Indicates whether to log asynchronously
    async: true
    rotation:
    max-file-size: 100M
    max-backup-index: 300
    file-suffix: .yyyy-MM-dd

    - -

    要开启TRACE级别的日志,必须同时配置 quarkus.log.min-level=TRACE, 否则最多只输出DEBUG级别

    -

    分包编译

    使用了quarkus的IoC注解的bean,在打包成jar包时,必须引入jandex插件,将bean的详细信息记录在jandex索引文件中,否则quarkus只会扫描当前工程中的文件,而无法使用
    jar包中的bean。

    -
     <plugin>
    <groupId>org.jboss.jandex</groupId>
    <artifactId>jandex-maven-plugin</artifactId>
    <version>1.2.3</version>
    <executions>
    <execution>
    <id>make-index</id>
    <goals>
    <goal>jandex</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    - -

    原生编译

    需要使用maven 3.9.3以后版本

    -
    mvnw install -Dnative -DskipTests -Dquarkus.native.container-build=true
    - -
      -
    • windows下中文VC存在问题,配置-H:-CheckToolchain 可以跳过
    • -
    • 不能使用awt模块下的Font等类
    • -
    • 不能包含–report-unsupported-elements-at-runtime选项,否则通过Delete注解排除的class仍然会报错
    • -
    • GraalVM 23.1无法使用quarkus3.3.3进行原生编译,必须升级到3.4.1
    • -
    -

    上传解析

    需要引入com.sun.mail依赖,并禁用内置依赖的angus-mail模块,并且不能排除jaxb-provider

    -
    <dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-multipart</artifactId>
    <exclusions>
    <exclusion>
    <artifactId>angus-mail</artifactId>
    <groupId>org.eclipse.angus</groupId>
    </exclusion>
    </exclusions>
    </dependency>

    <dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>jakarta.mail</artifactId>
    </dependency>
    - -

    仅使用Nop平台的后端

    如果需要使用NopGraphQL服务,则可以引入nop-quarkus-web-starter模块

    -

    <pom>
    <!-- parent 设置为nop-entropy可以集成缺省的maven plugin,缺省的包管理配置 -->
    <parent>
    <artifactId>nop-entropy</artifactId>
    <groupId>io.github.entropy-cloud</groupId>
    <version>2.0.0-SNAPSHOT</version>
    </parent>

    <dependencies>
    <!-- 引入 Nop平台依赖。因为设置了parent为nop-entropy,这里就不用写具体的包的版本号 -->
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-quarkus-web-orm-starter</artifactId>
    </dependency>

    <!-- 用户、权限管理,这是可选依赖 -->
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-auth-service</artifactId>
    </dependency>

    <!-- 可选依赖,字典表、编码规则表、扩展字段表、全局序号表等 -->
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-sys-service</artifactId>
    </dependency>

    <!-- 需要使用Nop平台生成的AMIS页面的时候才需要依赖xxx-web模块 -->
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-auth-web</artifactId>
    </dependency>

    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-sys-web</artifactId>
    </dependency>

    <!-- 这里包含了nop-chaos项目打包生成的js和css,它提供了前台菜单框架包括登录页面等。如果自己实现前端,可以不依赖这个模块 -->
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-web-site</artifactId>
    </dependency>

    </dependencies>
    </pom>
    - -

    仅使用NopReport报表引擎


    <dependencies>
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-quarkus-core-starter</artifactId>
    </dependency>

    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-report-core</artifactId>
    </dependency>
    </dependencies>
    -
    - -
    - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/recipe/add-field/index.html b/projects/nop-entropy/docs/dev-guide/recipe/add-field/index.html index ee0da42..6de432f 100644 --- a/projects/nop-entropy/docs/dev-guide/recipe/add-field/index.html +++ b/projects/nop-entropy/docs/dev-guide/recipe/add-field/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1115 +186,81 @@ -
    +
    + + + +
    +
    +
    + + +

    在后台Graph中增加字段

    -
    +

    1. 所有GraphQL中返回的字段都需要在xmeta文件中定义

    代码生成时会自动根据数据库模型设置为每个published=true的字段生成prop定义,自动生成的xmeta定义存放在以下划线为前缀的文件中。
    例如 NopAuthUser.xmeta继承了_NopAuthUser.xmeta。我们可以在不带下划线的文件中对自动生成的xmeta进行增强。
    可以增加字段、为字段增加属性或者删除自动生成的字段定义。

    +

    2. 为xmeta中定义的prop提供Loader

    xmeta定义会自动转化为GraphQL的类型定义,后台还需要增加GraphQL所要求的Fetcher定义才能实际返回数据

    +

    2.1 在Java实体上增加get方法

    直接在NopAuthUser.java类中增加对应的get/set方法即可实现数据存取。xmeta仅仅涉及到接口层,对底层存储机制没有任何假定。

    +

    2.2 在BizModel上增加方法,并设置@BizLoader注解

    例如为NopAuthUser增加roleUsers属性对应的fetcher

    +
    @BizModel("NopAuthRole")
    public class NopAuthRoleBizModel extends CrudBizModel<NopAuthRole> {

    @BizLoader
    @GraphQLReturn(bizObjName = "NopAuthUser")
    public List<NopAuthUser> roleUsers(@ContextSource NopAuthRole role) {
    return role.getUserMappings().stream().map(NopAuthUserRole::getUser)
    .sorted(comparing(NopAuthUser::getUserName)).collect(Collectors.toList());
    }
    }
    + +

    2.3 在XBiz模型中定义loader

    2.4 在XMeta模型中直接定义getter/setter

    对于比较简单的情况,我们不需要修改BizModel或者实体类,可以直接在后台接口层的xmeta模型中直接定义存取器。

    +
    <meta>
    <props>
    <prop name="createDate">
    <getter>
    entity.createTime.$toLocalDate()
    </getter>
    </prop>
    </props>
    </meta>
    + +

    $toLocalDate是扩展类型转换函数。所有的表达式最后都可以通过$toLocalDate/toInt()等方式调用ConvertHelper上的类型转换函数。

    +

    对于一些常见的可复用转换函数等,我们可以利用Nop平台内置的x:gen-extendsx:post-extends等元编程机制自动生成属性定义。
    参见biz-gen.xlib

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    在后台Graph中增加字段

    - - - - -
    -

    1. 所有GraphQL中返回的字段都需要在xmeta文件中定义

    代码生成时会自动根据数据库模型设置为每个published=true的字段生成prop定义,自动生成的xmeta定义存放在以下划线为前缀的文件中。
    例如 NopAuthUser.xmeta继承了_NopAuthUser.xmeta。我们可以在不带下划线的文件中对自动生成的xmeta进行增强。
    可以增加字段、为字段增加属性或者删除自动生成的字段定义。

    -

    2. 为xmeta中定义的prop提供Loader

    xmeta定义会自动转化为GraphQL的类型定义,后台还需要增加GraphQL所要求的Fetcher定义才能实际返回数据

    -

    2.1 在Java实体上增加get方法

    直接在NopAuthUser.java类中增加对应的get/set方法即可实现数据存取。xmeta仅仅涉及到接口层,对底层存储机制没有任何假定。

    -

    2.2 在BizModel上增加方法,并设置@BizLoader注解

    例如为NopAuthUser增加roleUsers属性对应的fetcher

    -
    @BizModel("NopAuthRole")
    public class NopAuthRoleBizModel extends CrudBizModel<NopAuthRole> {

    @BizLoader
    @GraphQLReturn(bizObjName = "NopAuthUser")
    public List<NopAuthUser> roleUsers(@ContextSource NopAuthRole role) {
    return role.getUserMappings().stream().map(NopAuthUserRole::getUser)
    .sorted(comparing(NopAuthUser::getUserName)).collect(Collectors.toList());
    }
    }
    - -

    2.3 在XBiz模型中定义loader

    2.4 在XMeta模型中直接定义getter/setter

    对于比较简单的情况,我们不需要修改BizModel或者实体类,可以直接在后台接口层的xmeta模型中直接定义存取器。

    -
    <meta>
    <props>
    <prop name="createDate">
    <getter>
    entity.createTime.$toLocalDate()
    </getter>
    </prop>
    </props>
    </meta>
    - -

    $toLocalDate是扩展类型转换函数。所有的表达式最后都可以通过$toLocalDate/toInt()等方式调用ConvertHelper上的类型转换函数。

    -

    对于一些常见的可复用转换函数等,我们可以利用Nop平台内置的x:gen-extendsx:post-extends等元编程机制自动生成属性定义。
    参见biz-gen.xlib

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/recipe/crud/index.html b/projects/nop-entropy/docs/dev-guide/recipe/crud/index.html index 6b5da07..efa7511 100644 --- a/projects/nop-entropy/docs/dev-guide/recipe/crud/index.html +++ b/projects/nop-entropy/docs/dev-guide/recipe/crud/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1120 +186,86 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    1. 传递一些实体上没有的字段到后台

    - - - - -
    -

    在meta中增加prop,然后设置它的virtual属性为true,表示是虚拟字段,就不会自动拷贝到实体上。

    -

    如果不允许读取,则需要配置readable=false,这样查询后台的时候就不允许从实体上读取此属性。

    -
    <meta>
    <props>
    <prop name="myProp" readable="false" virtual="true">
    <schema stdDomain="string" />
    </prop>
    </props>
    </meta>
    - -

    在后台可以通过entityData读取

    -
    class MyEntityBizModel extends CrudBizModel {
    @BizMutation
    public MyEntity myMethod(@Name("data") Map<String, Object> data, IServiceContext ctx) {
    return doSave(data, null, (entityData, ctx) -> {
    String myProp = (String) entityData.getData().get("myProp");
    //...
    }, ctx);
    }
    }
    - -

    2. 在事务提交成功之后再执行某个操作

    使用ITransactionTemplate.afterCommit(null, action)函数。

    -

    CrudBizModel已经注入了transactionTemplate,可以通过this.txn()来使用。

    -

    3. 扩展CrudBizModel内置的save/update等操作,增加业务相关的特殊处理

    如果只是少量的更新几个字段,原则上可以使用自定义的bean作为参数,然后直接调用dao().save(entity)即可。
    但是如果要接收大量字段,并考虑到未来是否有新扩展的字段需要保存,保存的时候需要执行定制的处理逻辑等,这时就
    不要使用自定义的JavaBean作为参数,应该直接使用内置的doSave等函数。

    -
    @BizMutation
    @GraphQLReturn(bizObjName = BIZ_OBJ_NAME_THIS_OBJ)
    @BizMakerChecker(tryMethod = METHOD_TRY_SAVE)
    public MyEntity my_save(@Name("data") Map<String, Object> data, IServiceContext context) {
    // 如果需要限制只允许接收部分字段,可以在meta中配置。如果没有特殊限制,inputSelection设置为null即可
    FieldInputSelection inputSelection = getObjMeta().getFieldSelection("my_selectio");
    return doSave(data, inputSelection, this::myPrepareSave, context);
    }
    - -
      -
    • inputSelection参数可以用于限制只接收前端传过来的某些参数
    • -
    • prepareSave回调函数可以用于定制实体实际保存前执行的额外的业务逻辑
    • -
    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/recipe/filter-list/index.html b/projects/nop-entropy/docs/dev-guide/recipe/filter-list/index.html index 66d57b9..5671bd9 100644 --- a/projects/nop-entropy/docs/dev-guide/recipe/filter-list/index.html +++ b/projects/nop-entropy/docs/dev-guide/recipe/filter-list/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    + + + + + +
    -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/recipe/index.html b/projects/nop-entropy/docs/dev-guide/recipe/index.html index 3b6e917..c5d55c1 100644 --- a/projects/nop-entropy/docs/dev-guide/recipe/index.html +++ b/projects/nop-entropy/docs/dev-guide/recipe/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/recipe/json-helper/index.html b/projects/nop-entropy/docs/dev-guide/recipe/json-helper/index.html index 8ff2758..8575ab4 100644 --- a/projects/nop-entropy/docs/dev-guide/recipe/json-helper/index.html +++ b/projects/nop-entropy/docs/dev-guide/recipe/json-helper/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1121 +186,87 @@ -
    +
    + + + +
    +
    +
    + + +

    JSON处理

    -
    +

    1. 解析JSON文本

    JsonTool.parseNonStrict(text);

    JsonTool.parse(text); // 解析标准JSON格式

    + +

    2. 解析JSON文件

    JsonTool.parseBeanFromResource(resource, beanType);
    + +

    如果根据文件的后缀名是json、json5或者yaml,采用不同的解析器去解析。返回结果缺省为普通Map或者List对象。如果设置了beanType为具体的Java类型,
    则尝试将Json对象转换为对应的强类型的Java对象。

    +

    例如

    +
    JsonTool.parseBeanFromResource(resource, Map.class);
    JsonTool.parseBeanFromResource(resource, RuleModel.class);
    + +

    3. 加载JSON或者Yaml文件,并自动按照Delta合并规则处理其中的x:extendsx:gen-extends等差量合并算子。

    JsonTool.loadDeltaBean(resource, beanType, new DeltaJsonOptions());
    + +

    4. 将Java对象转换为普通JSON对象

    json = JsonTool.serializeToJson(bean);
    + +

    5. 将Java对象序列化为JSON文本

    json = JsonTool.serialize(bean, pretty);
    + +

    pretty参数控制生成文本时是否使用缩进。

    +

    6. 将Java对象序列化为Yaml文本

    json = JsonTool.serializeToYaml(bean);
    +

    7. 将Java对象序列化为JSON文本,并保存到文件中

    ResourceHelper.writeJson(resource,obj);
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    JSON处理

    - - - - -
    -

    1. 解析JSON文本

    JsonTool.parseNonStrict(text);

    JsonTool.parse(text); // 解析标准JSON格式

    - -

    2. 解析JSON文件

    JsonTool.parseBeanFromResource(resource, beanType);
    - -

    如果根据文件的后缀名是json、json5或者yaml,采用不同的解析器去解析。返回结果缺省为普通Map或者List对象。如果设置了beanType为具体的Java类型,
    则尝试将Json对象转换为对应的强类型的Java对象。

    -

    例如

    -
    JsonTool.parseBeanFromResource(resource, Map.class);
    JsonTool.parseBeanFromResource(resource, RuleModel.class);
    - -

    3. 加载JSON或者Yaml文件,并自动按照Delta合并规则处理其中的x:extendsx:gen-extends等差量合并算子。

    JsonTool.loadDeltaBean(resource, beanType, new DeltaJsonOptions());
    - -

    4. 将Java对象转换为普通JSON对象

    json = JsonTool.serializeToJson(bean);
    - -

    5. 将Java对象序列化为JSON文本

    json = JsonTool.serialize(bean, pretty);
    - -

    pretty参数控制生成文本时是否使用缩进。

    -

    6. 将Java对象序列化为Yaml文本

    json = JsonTool.serializeToYaml(bean);
    - -

    7. 将Java对象序列化为JSON文本,并保存到文件中

    ResourceHelper.writeJson(resource,obj);
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/recipe/tree-entity/index.html b/projects/nop-entropy/docs/dev-guide/recipe/tree-entity/index.html index 98b29bb..4664998 100644 --- a/projects/nop-entropy/docs/dev-guide/recipe/tree-entity/index.html +++ b/projects/nop-entropy/docs/dev-guide/recipe/tree-entity/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1108 +186,74 @@ -
    +
    + + + +
    +
    +
    + + +

    1. 如何取出当前节点的所有兄弟节点,以及所有父节点

    -
    +
    dao.batchLoadPropsForEntity(entity,"parent.parent.parent.parent","parent.children")
    + +

    可以通过IEntityDao接口上的batchLoadPropsForEntity函数来获取到向上几层的父节点,以及父节点下的兄弟节点。

    +

    然后通过上的关联属性,如entity.getParent()entity.getChildren()等来获取到所有实体对象

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    1. 如何取出当前节点的所有兄弟节点,以及所有父节点

    - - - - -
    -
    dao.batchLoadPropsForEntity(entity,"parent.parent.parent.parent","parent.children")
    - -

    可以通过IEntityDao接口上的batchLoadPropsForEntity函数来获取到向上几层的父节点,以及父节点下的兄弟节点。

    -

    然后通过上的关联属性,如entity.getParent()entity.getChildren()等来获取到所有实体对象

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/recipe/xml-helper/index.html b/projects/nop-entropy/docs/dev-guide/recipe/xml-helper/index.html index 65e8002..2bde1bd 100644 --- a/projects/nop-entropy/docs/dev-guide/recipe/xml-helper/index.html +++ b/projects/nop-entropy/docs/dev-guide/recipe/xml-helper/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1147 +186,113 @@ -
    +
    + + + +
    +
    +
    + + +

    1. 解析XML文本

    -
    +
    XNode node = XNodeParser.instance().parseFromText(loc, text);
    + +

    XNode解析结果与DOM解析不同。DOM总是保留节点之间的空白节点。而XNode解析时如果两个节点之间只有空白文本,则该空白文本会被忽略。例如

    +
    <root>
    <child1/>
    <child2/>
    </root>
    + +

    XNode解析得到的root节点,它具有两个子节点child1和child2。

    +

    2. 解析XML文件

    XNode node = XNodeParser.instance().parseFromReource(resource);
    或者

    XNode node = ResourceHelper.readXml(resource);
    + +

    3. 将XNode序列化为XML保存到文件中

    ResourceHelper.writeXml(resource,node);e
    + +

    4. 根据XDef元模型定义将XML文件解析为Java对象

    new DslModelParser(xdefPath).parseFromResource(resource);
    + +

    5. 递归遍历XNode的每一个节点

    node.forEachNode(n-> process(n));
    + +

    6. 常用函数


    node.getTagName() // 读取标签名
    node.getAttr(name) // 读取属性
    node.setAttr(name,value) // 设置属性

    node.attrText(name) // 得到文本属性,如果文本值为空,则返回null而不是空串
    node.attrTextOrEmpty(name) // 如果属性值为空,则返回null。属性值不存在时返回null
    node.attrInt(name) // 得到属性值并转换为Integer类型
    node.attrInt(name, defaultValue) // 如果属性值为空,则返回缺省值
    node.attrBoolean(name) // 读取属性值并转换为Boolean类型
    node.attrLong(name) // 读取属性值并转换为Long类型
    node.attrCsvSet(name) // 读取属性值,如果是字符串,则按照逗号分隔转换字符串集合


    node.getAttrs() // 得到属性集合
    node.getChildren() // 得到子节点集合
    node.childByTag(tagName) // 根据子节点名查找得到对应子节点
    node.childByAttr(attrName, attrValue) // 根据属性值查找得到子节点
    node.getContentValue() // 读取节点值

    node.hasChild() // 是否有子节点
    node.hasAttr() // 是否有属性
    node.hasContent() // 直接内容是否不为空
    node.hasBody() // 是否有子节点或者直接内容

    node.getParent() // 得到父节点

    node.cloneInstance() // 复制节点

    list = node.cloneChildren() // 复制所有子节点

    node.detach() // 解除父子关系

    node.remove() // 从父节点中删除

    node.replaceBy(newNode) // 在父节点的children集合中将本节点替换为newNode


    node.xml() // 得到节点的XML文本
    node.innerXml() // 得到节点内部对应的XML文本

    node.toTreeBean() // 转换为TreeBean对象

    XNode.fromTreeBean(treeBean) // 从TreeBean转换为XNode

    + +

    7. XML和JSON之间的转换


    node.toXJson() // 按照XJson格式转换为JSON对象

    node.toJsonObject() // 按照标准格式转换为json
    + +

    标准格式规定如下:

    +
      +
    1. tagName 对应于 $type
    2. +
    3. children和content 对应于 $body
    4. +
    5. 属性直接对应于对象属性。
    6. +
    +

    例如:

    +
    <div class='a'>
    <span />
    </div>
    + +

    转换为

    +
    {
    "$type": "div",
    "class": "a",
    "$body": [
    {
    "$type": "span"
    }
    ]
    }
    + +

    XJson规定如下:

    +
      +
    1. 一般情况下属性和子节点都对应于对象属性
    2. +
    3. 如果节点上标记了j:list=’true’表示当前节点对应于一个列表对象
    4. +
    5. 如果节点名为 _,则表示节点名被忽略
    6. +
    7. 如果节点没有属性,且没有子节点,则它的内容作为它的值
    8. +
    9. 如果节点具有j:key属性,则它替代节点名作为属性名
    10. +
    11. 列表节点的子节点的tagName对应于type属性。但有个例外,如果节点名为 _,则表示节点名被忽略
    12. +
    +

    例如:

    +
    <root a="1">
    <buttons j:list="true">
    <button id="a" >
    <description>aa</description>
    </button>
    </buttons>

    <options j:list="true">
    <_>A</_>
    <_>B</_>
    </options>
    </root>
    +

    对应于

    +
    {
    "type": "root",
    "a": "1",
    "buttons": [
    {
    "type": "button",
    "id": "a",
    "description": "aa"
    }
    ],
    "options": ["A","B"]
    }
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/report/examples/base/index.html b/projects/nop-entropy/docs/dev-guide/report/examples/base/index.html index 7c4eb73..d603dea 100644 --- a/projects/nop-entropy/docs/dev-guide/report/examples/base/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/examples/base/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1107 +186,73 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/report/examples/dynamic-col/index.html b/projects/nop-entropy/docs/dev-guide/report/examples/dynamic-col/index.html index c73cbec..1ef1234 100644 --- a/projects/nop-entropy/docs/dev-guide/report/examples/dynamic-col/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/examples/dynamic-col/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1135 +186,101 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/report/examples/form-printing/index.html b/projects/nop-entropy/docs/dev-guide/report/examples/form-printing/index.html index 1678021..1b60611 100644 --- a/projects/nop-entropy/docs/dev-guide/report/examples/form-printing/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/examples/form-printing/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1115 +186,81 @@ -
    +
    + + + +
    +
    +
    + + +

    套打

    -
    +

    套打的做法如下:

    +
      +
    1. 在报表中插入图片
    2. +
    3. 设置图片打印的时候不显示
    4. +
    +

    +

    动态生成图片

    如果不是静态图片,必须根据条件动态生成图片,则需要配置数据生成表达式。

    +

    在图片上点击右键【查看可选文字】,然后在【替换文字】信息中通过dataExpr表达式来生成图片数据,返回格式为byte[]或者IResource对象。

    +

    注意:需要插入单独的一行-----表示后续是表达式部分。

    +

    +

    具体如何加载图片需要应用自行编写,这里的myHelper仅仅是一个示例对象。应用可以在【展开前】使用inject从bean容器中获取自己的帮助对象。
    或者使用import语法导入外部帮助类。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    套打

    - - - - -
    -

    套打的做法如下:

    -
      -
    1. 在报表中插入图片
    2. -
    3. 设置图片打印的时候不显示
    4. -
    -

    -

    动态生成图片

    如果不是静态图片,必须根据条件动态生成图片,则需要配置数据生成表达式。

    -

    在图片上点击右键【查看可选文字】,然后在【替换文字】信息中通过dataExpr表达式来生成图片数据,返回格式为byte[]或者IResource对象。

    -

    注意:需要插入单独的一行-----表示后续是表达式部分。

    -

    -

    具体如何加载图片需要应用自行编写,这里的myHelper仅仅是一个示例对象。应用可以在【展开前】使用inject从bean容器中获取自己的帮助对象。
    或者使用import语法导入外部帮助类。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/report/excel-formula/index.html b/projects/nop-entropy/docs/dev-guide/report/excel-formula/index.html index ec0c8e9..a39a28c 100644 --- a/projects/nop-entropy/docs/dev-guide/report/excel-formula/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/excel-formula/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1118 +186,84 @@ -
    +
    + + + +
    +
    +
    + + +

    报表导出时支持Excel公式

    -
    +

    1. 在报表模板中如果设置了Excel公式,则导出Excel时会自动转换为Excel公式

    例如 =SUM(A3:B4)

    +

    在导出到Excel后,会将A3:B4这种单元格区间表达式替换为展开后的单元格范围,例如 =SUM(A3:B10)

    +

    2. 根据条件对单元格进行过滤

    Excel公式中存在一些特殊语法,可以用于动态过滤,但是如果要按照Excel的方式来实现需要为表达式引擎增加大量特殊处理。
    为了减少报表引擎的工作量,目前的选择是引入一种特殊语法。

    +

    NopReport特殊识别一种特殊格式的IF语句,IF(testExpr, rangeExpr),然后把它重新翻译为ReportExpr。

    +

    举例来说 IF(“e.rp.ev.name==’%’”, C2:D2)

    +
      +
    1. 第一个参数是一个字符串格式的ReportExpr,会使用NopReport的表达式引擎去解析。
      表达式中e参数表示需要判断的单元格。注意,具体的表达式语法是ReportExpr,它与Excel公式语法并不相同,比如等于判断使用==。
    2. +
    3. 第二个参数是单元格区间表达式。
    4. +
    +

    整个IF函数的语义是使用reportExpr对于C2:D2这个区间中的单元格进行过滤,只返回满足条件的单元格。

    +

    基本等价于如下调用 xptRpt.cells("C2:D2").filter(e=> e.rp.ev.name == '%')

    +
    +

    e.rp.ev.name 表示获取cell的rowParent的expandedValue的name属性。 expandedValue是展开单元格中expandExpr返回的展开值

    +
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    报表导出时支持Excel公式

    - - - - -
    -

    1. 在报表模板中如果设置了Excel公式,则导出Excel时会自动转换为Excel公式

    例如 =SUM(A3:B4)

    -

    在导出到Excel后,会将A3:B4这种单元格区间表达式替换为展开后的单元格范围,例如 =SUM(A3:B10)

    -

    2. 根据条件对单元格进行过滤

    Excel公式中存在一些特殊语法,可以用于动态过滤,但是如果要按照Excel的方式来实现需要为表达式引擎增加大量特殊处理。
    为了减少报表引擎的工作量,目前的选择是引入一种特殊语法。

    -

    NopReport特殊识别一种特殊格式的IF语句,IF(testExpr, rangeExpr),然后把它重新翻译为ReportExpr。

    -

    举例来说 IF(“e.rp.ev.name==’%’”, C2:D2)

    -
      -
    1. 第一个参数是一个字符串格式的ReportExpr,会使用NopReport的表达式引擎去解析。
      表达式中e参数表示需要判断的单元格。注意,具体的表达式语法是ReportExpr,它与Excel公式语法并不相同,比如等于判断使用==。
    2. -
    3. 第二个参数是单元格区间表达式。
    4. -
    -

    整个IF函数的语义是使用reportExpr对于C2:D2这个区间中的单元格进行过滤,只返回满足条件的单元格。

    -

    基本等价于如下调用 xptRpt.cells("C2:D2").filter(e=> e.rp.ev.name == '%')

    -
    -

    e.rp.ev.name 表示获取cell的rowParent的expandedValue的name属性。 expandedValue是展开单元格中expandExpr返回的展开值

    -
    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/report/excel-import/index.html b/projects/nop-entropy/docs/dev-guide/report/excel-import/index.html index 7bd8c47..c9e95dc 100644 --- a/projects/nop-entropy/docs/dev-guide/report/excel-import/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/excel-import/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/report/index.html b/projects/nop-entropy/docs/dev-guide/report/index.html index 0409c90..b0345db 100644 --- a/projects/nop-entropy/docs/dev-guide/report/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1105 +186,71 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/report/report-design/index.html b/projects/nop-entropy/docs/dev-guide/report/report-design/index.html index 54e516a..c94f450 100644 --- a/projects/nop-entropy/docs/dev-guide/report/report-design/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/report-design/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/report/spl/index.html b/projects/nop-entropy/docs/dev-guide/report/spl/index.html index 49e47ee..a33ea08 100644 --- a/projects/nop-entropy/docs/dev-guide/report/spl/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/spl/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1114 +186,80 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    润乾集算器(SPL)

    - - - - -
    -

    SPL介绍视频: 没有 RDB 也敢揽 SQL 活的开源金刚钻 SPL
    SPL参考文档: 集算器 - 敏捷计算编程语言

    -

    Nop平台集成SPL的介绍视频

    -

    -

    在Nop平台中集成SPL只需要引入nop-report-spl模块。在程序中可以通过以下几种方式来调用SPL;

    -
      -
    1. 调用 SplExecutor.executeForPath(IEvalScope scope, String path)函数来执行SPL文件。 path为SPL或者SPLX文件所对应的虚拟路径。
    2. -
    3. 直接调用SplExecutor.executeSPL(IEvalScope scope, String splSource)函数来执行SPL语句。
    4. -
    5. 在XPL模板语言中可以通过标签库 <spl:Execute src="xxx.splx" xpl:return="result" />来调用
    6. -
    7. 在NopReport报表引擎中,可以通过如下方式调用SPL语句来构造数据集
    8. -
    -
    <spl:MakeDataSet xpl:lib="/nop/report/spl/spl.xlib" dsName="ds1" src="/nop/report/demo/spl/test-data.splx" />
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/report/word-template-details/index.html b/projects/nop-entropy/docs/dev-guide/report/word-template-details/index.html index 6066ec6..5851038 100644 --- a/projects/nop-entropy/docs/dev-guide/report/word-template-details/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/word-template-details/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1113 +186,79 @@ -
    +
    + + + +
    +
    +
    + + +

    超链接

    -
    +
    <w:p>
    <w:r>
    <w:t xml:space="preserve">This is an external link to </w:t>
    </w:r>
    <w:hyperlink r:id="rId4">
    <w:r>
    <w:rPr>
    <w:rStyle w:val="Hyperlink"/>
    </w:rPr>
    <w:t>xpl:entity.name</w:t>
    </w:r>
    </w:hyperlink>
    </w:p>
    +

    NopReport引擎识别出xpl表达式之后会做如下处理:

    +
      +
    1. 如果是xpl-begin或者xpl-end,则将它们配对,插入到它们共同的父节点外部。这样在表格的第一个单元格插入begin,在最后一个单元格插入end,就可以实现整行循环的效果。
    2. +
    3. 如果是tpl-expr或者expr,需要将w:hyperlink标签替换为w:r标签(使用sourceNode替换linkNode)。此时的linkNode实际上是从w:hyperlink内的w:r标签加工而来,这样可以保持样式设置
    4. +
    5. 如果是xpl,则检查xpl源码解析得到的节点是否是w:p,如果是,则将w:hyperlink所在的w:p标签整体替换为xpl标签的内容,否则只替换linkNode。
    6. +
    +

    另外一种超链接形式

    +

    <w:p>
    <w:pPr>
    <w:rPr>
    <w:rFonts w:ascii="Cambria" w:hAnsi="Cambria"/>
    <w:kern w:val="0"/>
    <w:sz w:val="20"/>
    <w:szCs w:val="20"/>
    </w:rPr>
    </w:pPr>
    <w:r>
    <w:fldChar w:fldCharType="begin"/>
    </w:r>
    <w:r>
    <w:instrText xml:space="preserve"> HYPERLINK "xpl:%3cc:for%20var=%22project%22%20items=%22$%7bentity.projectList%7d%22%3e" </w:instrText>
    </w:r>
    <w:r>
    <w:fldChar w:fldCharType="separate"/>
    </w:r>
    <w:r>
    <w:rPr>
    <w:rStyle w:val="7"/>
    <w:rFonts w:ascii="Cambria" w:hAnsi="Cambria"/>
    <w:kern w:val="0"/>
    <w:sz w:val="20"/>
    <w:szCs w:val="20"/>
    </w:rPr>
    <w:t>
    &lt;c:for&gt;
    </w:t>
    </w:r>
    <w:r>
    <w:rPr>
    <w:rStyle w:val="7"/>
    <w:rFonts w:ascii="Cambria" w:hAnsi="Cambria"/>
    <w:kern w:val="0"/>
    <w:sz w:val="20"/>
    <w:szCs w:val="20"/>
    </w:rPr>
    <w:fldChar w:fldCharType="end"/>
    </w:r>
    </w:p>
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    超链接

    - - - - -
    -
    <w:p>
    <w:r>
    <w:t xml:space="preserve">This is an external link to </w:t>
    </w:r>
    <w:hyperlink r:id="rId4">
    <w:r>
    <w:rPr>
    <w:rStyle w:val="Hyperlink"/>
    </w:rPr>
    <w:t>xpl:entity.name</w:t>
    </w:r>
    </w:hyperlink>
    </w:p>
    - -

    NopReport引擎识别出xpl表达式之后会做如下处理:

    -
      -
    1. 如果是xpl-begin或者xpl-end,则将它们配对,插入到它们共同的父节点外部。这样在表格的第一个单元格插入begin,在最后一个单元格插入end,就可以实现整行循环的效果。
    2. -
    3. 如果是tpl-expr或者expr,需要将w:hyperlink标签替换为w:r标签(使用sourceNode替换linkNode)。此时的linkNode实际上是从w:hyperlink内的w:r标签加工而来,这样可以保持样式设置
    4. -
    5. 如果是xpl,则检查xpl源码解析得到的节点是否是w:p,如果是,则将w:hyperlink所在的w:p标签整体替换为xpl标签的内容,否则只替换linkNode。
    6. -
    -

    另外一种超链接形式

    -

    <w:p>
    <w:pPr>
    <w:rPr>
    <w:rFonts w:ascii="Cambria" w:hAnsi="Cambria"/>
    <w:kern w:val="0"/>
    <w:sz w:val="20"/>
    <w:szCs w:val="20"/>
    </w:rPr>
    </w:pPr>
    <w:r>
    <w:fldChar w:fldCharType="begin"/>
    </w:r>
    <w:r>
    <w:instrText xml:space="preserve"> HYPERLINK "xpl:%3cc:for%20var=%22project%22%20items=%22$%7bentity.projectList%7d%22%3e" </w:instrText>
    </w:r>
    <w:r>
    <w:fldChar w:fldCharType="separate"/>
    </w:r>
    <w:r>
    <w:rPr>
    <w:rStyle w:val="7"/>
    <w:rFonts w:ascii="Cambria" w:hAnsi="Cambria"/>
    <w:kern w:val="0"/>
    <w:sz w:val="20"/>
    <w:szCs w:val="20"/>
    </w:rPr>
    <w:t>
    &lt;c:for&gt;
    </w:t>
    </w:r>
    <w:r>
    <w:rPr>
    <w:rStyle w:val="7"/>
    <w:rFonts w:ascii="Cambria" w:hAnsi="Cambria"/>
    <w:kern w:val="0"/>
    <w:sz w:val="20"/>
    <w:szCs w:val="20"/>
    </w:rPr>
    <w:fldChar w:fldCharType="end"/>
    </w:r>
    </w:p>
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/report/word-template/index.html b/projects/nop-entropy/docs/dev-guide/report/word-template/index.html index 1de5781..14b5664 100644 --- a/projects/nop-entropy/docs/dev-guide/report/word-template/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/word-template/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/report/xpt-report/index.html b/projects/nop-entropy/docs/dev-guide/report/xpt-report/index.html index d437bcd..8ca55c0 100644 --- a/projects/nop-entropy/docs/dev-guide/report/xpt-report/index.html +++ b/projects/nop-entropy/docs/dev-guide/report/xpt-report/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/rule/rule/index.html b/projects/nop-entropy/docs/dev-guide/rule/rule/index.html index 38d422d..52916b9 100644 --- a/projects/nop-entropy/docs/dev-guide/rule/rule/index.html +++ b/projects/nop-entropy/docs/dev-guide/rule/rule/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/security/security-design/index.html b/projects/nop-entropy/docs/dev-guide/security/security-design/index.html index c521599..6e11934 100644 --- a/projects/nop-entropy/docs/dev-guide/security/security-design/index.html +++ b/projects/nop-entropy/docs/dev-guide/security/security-design/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/sonar/sonarqube/index.html b/projects/nop-entropy/docs/dev-guide/sonar/sonarqube/index.html index add8657..c8fc218 100644 --- a/projects/nop-entropy/docs/dev-guide/sonar/sonarqube/index.html +++ b/projects/nop-entropy/docs/dev-guide/sonar/sonarqube/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1112 +186,78 @@ -
    +
    + + + +
    +
    +
    + + +

    配置

    -
    +
      +
    1. 修改maven的settings文件
    2. +
    +
    <profile>
    <id>sonar</id>
    <activation>
    <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
    <sonar.host.url>http://localhost:9000</sonar.host.url>
    <sonar.token>xxx</sonar.token>
    <sonar.scm.provider>git</sonar.scm.provider>
    </properties>
    </profile>
    +
      +
    1. 修改工程根目录的pom文件
    2. +
    +

    <pom>
    <properties>
    <sonar.coverage.jacoco.xmlReportPaths>
    ${maven.multiModuleProjectDirectory}/tests/target/site/jacoco-aggregate/jacoco.xml
    </sonar.coverage.jacoco.xmlReportPaths>
    <sonar.language>java</sonar.language>
    </properties>

    <build>
    <plugins>
    <!-- mvn surefire-report:report指令生成测试报告 -->
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.2.2</version>

    <configuration>
    <argLine>
    ${jacocoArgLine}
    </argLine>
    <testFailureIgnore>false</testFailureIgnore>
    <forkCount>4</forkCount>
    <reuseForks>true</reuseForks>
    </configuration>

    </plugin>
    </plugins>
    </build>

    <profiles>
    <profile>
    <id>coverage</id>
    <activation>
    <activeByDefault>true</activeByDefault>
    </activation>
    <build>
    <plugins>
    <plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.11</version>
    <executions>
    <execution>
    <id>default-prepare-agent</id>
    <goals>
    <goal>prepare-agent</goal>
    </goals>
    <!-- 与surefire共用时需要重命名argLine -->
    <configuration>
    <propertyName>jacocoArgLine</propertyName>
    </configuration>
    </execution>
    </executions>
    <configuration>
    <excludes>
    <exclude>**/_gen/*.*</exclude>
    <exclude>**/*Errors.*</exclude>
    <exclude>**/*Configs.*</exclude>
    <exclude>**/*Constants*</exclude>
    <exclude>**/parse/antlr/*.*</exclude>
    </excludes>
    </configuration>
    </plugin>
    </plugins>
    </build>
    </profile>
    </profiles>
    </pom>
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    配置

    - - - - -
    -
      -
    1. 修改maven的settings文件
    2. -
    -
    <profile>
    <id>sonar</id>
    <activation>
    <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
    <sonar.host.url>http://localhost:9000</sonar.host.url>
    <sonar.token>xxx</sonar.token>
    <sonar.scm.provider>git</sonar.scm.provider>
    </properties>
    </profile>
    - -
      -
    1. 修改工程根目录的pom文件
    2. -
    -

    <pom>
    <properties>
    <sonar.coverage.jacoco.xmlReportPaths>
    ${maven.multiModuleProjectDirectory}/tests/target/site/jacoco-aggregate/jacoco.xml
    </sonar.coverage.jacoco.xmlReportPaths>
    <sonar.language>java</sonar.language>
    </properties>

    <build>
    <plugins>
    <!-- mvn surefire-report:report指令生成测试报告 -->
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.2.2</version>

    <configuration>
    <argLine>
    ${jacocoArgLine}
    </argLine>
    <testFailureIgnore>false</testFailureIgnore>
    <forkCount>4</forkCount>
    <reuseForks>true</reuseForks>
    </configuration>

    </plugin>
    </plugins>
    </build>

    <profiles>
    <profile>
    <id>coverage</id>
    <activation>
    <activeByDefault>true</activeByDefault>
    </activation>
    <build>
    <plugins>
    <plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.11</version>
    <executions>
    <execution>
    <id>default-prepare-agent</id>
    <goals>
    <goal>prepare-agent</goal>
    </goals>
    <!-- 与surefire共用时需要重命名argLine -->
    <configuration>
    <propertyName>jacocoArgLine</propertyName>
    </configuration>
    </execution>
    </executions>
    <configuration>
    <excludes>
    <exclude>**/_gen/*.*</exclude>
    <exclude>**/*Errors.*</exclude>
    <exclude>**/*Configs.*</exclude>
    <exclude>**/*Constants*</exclude>
    <exclude>**/parse/antlr/*.*</exclude>
    </excludes>
    </configuration>
    </plugin>
    </plugins>
    </build>
    </profile>
    </profiles>
    </pom>
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/spring/index.html b/projects/nop-entropy/docs/dev-guide/spring/index.html index 724ee24..edb8390 100644 --- a/projects/nop-entropy/docs/dev-guide/spring/index.html +++ b/projects/nop-entropy/docs/dev-guide/spring/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1141 +186,107 @@ -
    +
    + + + +
    +
    +
    + + +

    Spring集成

    -
    +

    只需引入nop-spring-core-starter模块即可实现Spring框架和Nop平台的集成

    +
    <pom>
    <dependencyManagement>

    <dependencies>
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-bom</artifactId>
    <version>${nop-entropy.version}</version>
    <type>pom</type>
    <scope>import</scope>
    </dependency>

    </dependencies>
    </dependencyManagement>

    <dependencies>
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-spring-core-starter</artifactId>
    </dependency>
    </dependencies>
    </pom>
    + +
      +
    1. Spring框架启动完毕的时候自动调用CoreInitialization.initialize()函数来执行Nop平台的初始化.
      参见NopSpringCoreWebConfig.java
    2. +
    3. Nop平台管理的bean可以通过@Inject来使用Spring容器中的bean
    4. +
    5. Spring容器中无法直接使用Nop平台管理的bean,需要使用 BeanContainer.getBeanByType(IDaoProvider.class)等方法来获取
    6. +
    7. Nop平台和Spring共用application.yaml配置文件,Nop平台的配置格式参见 config.md
    8. +
    +

    仅使用NopOrm来访问数据库

    如果仅需要使用NopOrm平台提供的ORM引擎,可以在nop-spring-core-starter的基础上再引入nop-orm模块

    +

    <dependencies>
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-orm</artifactId>
    </dependency>

    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-sys-dao</artifactId>
    </dependency>
    </dependencies>
    + +

    如果需要使用NopSysSequence表来统一管理sequence,或者需要扩展字段支持,则可以引入nop-sys-dao模块。

    +

    如果希望和Spring共用DataSource,而不是在Nop平台中使用自己管理的nopDataSource,则可以配置

    +
    nop.dao.use-parent-data-source=true
    + +

    这个配置会禁用Nop平台内部的nopDataSource定义,然后将nopDataSource对应于别名dataSource。因此要求Spring容器中提供一个名称为dataSource的数据源定义。

    +

    使用Spring事务管理统一管理事务

    需要注意的时,如果使用Spring事务,则NopORM的异步执行逻辑会不正确,只能采用同步执行。

    +
    nop.dao.use-parent-transaction-factory=true
    + +

    使用NopGraphQL服务

    如果需要使用NopGraphQL服务,则可以引入nop-spring-web-starter模块

    +

    <dependencies>
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-spring-web-starter</artifactId>
    </dependency>
    </dependencies>
    + +

    如果需要引入orm支持,则引入nop-spring-web-orm-starter,它会自动引入nop-orm,从而引入数据源配置,必须在application.yaml中配置nop.datasource.jdbc-url等参数,或者配置nop.orm.use-parent-data-source=true

    +

    集成Nop平台的AMIS前端

    仿照nop-for-ruoyi项目的相关配置.
    B站视频: 在若依(Ruoyi)框架中集成Nop平台

    +

    为Spring和MyBatis增加Delta定制能力

    引入 nop-spring-delta模块,然后模块目录下的beans/spring-*.beans.xml文件以及mapper/*.mapper.xml文件支持Delta定制。

    +

    nop-spring-delta对于Java中的Mapper接口也增加了定制能力

    +

    <bean id="sysUserMapper" parent="nopBaseMapper">
    <property name="mapperInterface" value="io.nop.demo.spring.SysUserMapper"/>
    <property name="mapperTypeEx" value="io.nop.demo.spring.SysUserMapperEx"/>
    </bean>
    +

    mapperInterface对应于Mapper XML文件中的namespace配置,一般情况下mapperTypeEx与namespace相同,但是在扩展模块中我们可以配置mapperTypeEx使用扩展接口。

    +

    具体设计原理参加 spring-delta.md

    +

    使用nop-all-for-spring来简化包管理

    Nop平台采用多模块设计,目前尚未上传maven中心仓库。如果要把nop平台的包上传私服进行管理,可以仿照nop-all-for-spring模块的做法,先将用到的
    Nop平台的包打包为一个nop-all-for-xxx.jar,然后只需要上传这一个jar包即可。

    +

    nop-spring-demo2工程演示了使用nop-all-for-spring的具体方法。

    +
    +

    因为Nop平台内核已经升级到Quarkus3.0,为了在Spring2.X版本中使用,需要明确指定jakarta相关包的版本号,否则会出现兼容性问题。

    +
    +

    打包时重命名包

    nop-maven-shaded-plugin插件提供了重命名包的功能。可以通过如下配置实现打包时自动重命名为java包名,并自动修改所有dsl文件中的对应名称。

    +
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.5.0</version>
    <executions>
    <execution>
    <phase>package</phase>
    <goals>
    <goal>shade</goal>
    </goals>
    <configuration>
    <transformers>
    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
    <transformer implementation="io.nop.maven.plugin.shaded.XdslResourceTransformer" />
    <transformer implementation="io.nop.maven.plugin.shaded.SpringFactoryResourceTransformer" />
    </transformers>
    <artifactSet>
    <includes>
    <include>io.github.entropy-cloud:*</include>
    </includes>
    </artifactSet>
    <filters>
    <filter>
    <artifact>*:*</artifact>
    <excludes>
    <exclude>META-INF/maven/**</exclude>
    <exclude>META-INF/native-image/**</exclude>
    </excludes>
    </filter>
    </filters>

    <relocations>
    <relocation>
    <pattern>io.nop</pattern>
    <shadedPattern>com.xxx</shadedPattern>
    </relocation>
    </relocations>
    </configuration>
    </execution>
    </executions>

    <dependencies>
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-maven-shaded-plugin</artifactId>
    <version>${nop-entropy.version}</version>
    </dependency>
    </dependencies>
    </plugin>
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/spring/spring-delta/index.html b/projects/nop-entropy/docs/dev-guide/spring/spring-delta/index.html index e09b2f3..c22fe86 100644 --- a/projects/nop-entropy/docs/dev-guide/spring/spring-delta/index.html +++ b/projects/nop-entropy/docs/dev-guide/spring/spring-delta/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/tenant/index.html b/projects/nop-entropy/docs/dev-guide/tenant/index.html index 6322197..3e56580 100644 --- a/projects/nop-entropy/docs/dev-guide/tenant/index.html +++ b/projects/nop-entropy/docs/dev-guide/tenant/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1132 +189,98 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/vfs/index.html b/projects/nop-entropy/docs/dev-guide/vfs/index.html index ba4342c..6274cd0 100644 --- a/projects/nop-entropy/docs/dev-guide/vfs/index.html +++ b/projects/nop-entropy/docs/dev-guide/vfs/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1107 +186,73 @@ -
    +
    + + + +
    +
    +
    + + +

    虚拟文件系统

    -
    +

    支持Delta的VFS

    参见vfs.md

    +

    统一模型加载器

    参见model-loader.md

    +

    虚拟文件系统中的标准路径格式

    Nop平台内部约定了一定的资源路径模式,会自动查找满足模式的文件进行加载。参见std-resource-path.md

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    虚拟文件系统

    - - - - -
    -

    支持Delta的VFS

    参见vfs.md

    -

    统一模型加载器

    参见model-loader.md

    -

    虚拟文件系统中的标准路径格式

    Nop平台内部约定了一定的资源路径模式,会自动查找满足模式的文件进行加载。参见std-resource-path.md

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/vfs/model-loader/index.html b/projects/nop-entropy/docs/dev-guide/vfs/model-loader/index.html index 4ccd77c..8b029e9 100644 --- a/projects/nop-entropy/docs/dev-guide/vfs/model-loader/index.html +++ b/projects/nop-entropy/docs/dev-guide/vfs/model-loader/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1144 +186,110 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/vfs/std-resource-path/index.html b/projects/nop-entropy/docs/dev-guide/vfs/std-resource-path/index.html index 21d6b2f..843ea23 100644 --- a/projects/nop-entropy/docs/dev-guide/vfs/std-resource-path/index.html +++ b/projects/nop-entropy/docs/dev-guide/vfs/std-resource-path/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1107 +186,73 @@ -
    +
    + + + +
    +
    +
    + + +

    标准资源路径模式

    -
    +

    Nop平台内部约定了一定的资源路径模式,会自动查找满足模式的文件进行加载。

    +
    META-INF/services
    io.nop.core.initialize.ICoreInitializer 使用Java内置的ServiceLoader机制注册分级初始化函数
    CoreInitialization会读取所有CoreInitializer,按照优先级顺序执行
    bootstrap.yaml 静态全局配置文件,其中的内容优先级最高,不会被外部配置所覆盖
    application.yaml 全局的配置文件
    application-{profile}.yaml 全局的配置文件,profile是通过nop.profile指定的部署环境名称

    _vfs/
    /_delta
    /{deltaDir} 这里是delta层的名称,缺省会加载default层
    这里的文件会覆盖标准路径的同名文件
    /dict
    {dictName}.dict.yaml 字典文件不会被自动加载,但是通过dictName加载指定字典文件
    /i18n
    /{locale}
    {moduleName}.i18n.yaml I18nManager初始化的时候会自动加载所有i18n文件
    /nop
    /aop
    {xxx}.annotations Nop的AOP代码生成器生成包装类时会读取所有的annotations文件,并为每个标注了指定注解的类生成AOP包装类
    /autoconfig
    {xxx}.beans NopIoC会自动扫描解析所有后缀名为beans的文件,加载其中的beans.xml文件
    /core
    /reigstry
    {xxx}.register-model.xml 初始化时会自动扫描所有registry-model.xml文件,并注册对应的DSL模型解析器,
    将它们和特定的文件类型关联起来
    /dao
    /dialect
    /selector
    {xxx}.selector.xml 初始化时会自动扫描所有selector.xml文件,加载数据库方言的匹配规则
    {dialectName}.dialect.xml 数据库方言定义文件,按照dialectName来加载
    /main
    /auth
    /app.action-auth.xml 全局的操作权限和菜单定义文件,在其中通过x:extends来引用其他权限文件
    /app.data-auth.xml 全局的数据权限定义文件,在其中通过x:extends来引用其他数据权限文件
    /{moduleId} Nop模块的moduleId必须是nop/auth这种两级目录结构
    _module 每个Nop模块下都有一个_module文件来标记它是模块。
    /beans
    app-{xxx}.beans.xml NopIoC启动时会自动扫描每个模块的beans目录下以`app-`为前缀的beans.xml文件
    /model
    /{bizObjName}
    {bizObjName}.xbiz 所有的服务对象原则上都是要在beans.xml中注册,然后再通过对象名查找到对应的xbiz和xmeta文件
    {bizObjName}.xmeta NopDynEntity对象采用了简化注册流程,直接向BizObjectManager注册,没有在beans.xml中定义服务对象
    /orm
    app.orm.xml NopOrm引擎初始化的时候会加载所有模块的orm目录下的app.orm.xml模型文件
    /pages
    /{bizObjName}
    {pageId}.page.yaml 可以配置页面文件在系统初始化的情况下加载,它引用的view模型因此被连带加载
    {bizObjName}.view.xml View模型不会被自动加载,但是一般会放置在这个位置
    +

    模型文件自动加载顺序

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    标准资源路径模式

    - - - - -
    -

    Nop平台内部约定了一定的资源路径模式,会自动查找满足模式的文件进行加载。

    -
    META-INF/services
    io.nop.core.initialize.ICoreInitializer 使用Java内置的ServiceLoader机制注册分级初始化函数
    CoreInitialization会读取所有CoreInitializer,按照优先级顺序执行
    bootstrap.yaml 静态全局配置文件,其中的内容优先级最高,不会被外部配置所覆盖
    application.yaml 全局的配置文件
    application-{profile}.yaml 全局的配置文件,profile是通过nop.profile指定的部署环境名称

    _vfs/
    /_delta
    /{deltaDir} 这里是delta层的名称,缺省会加载default层
    这里的文件会覆盖标准路径的同名文件
    /dict
    {dictName}.dict.yaml 字典文件不会被自动加载,但是通过dictName加载指定字典文件
    /i18n
    /{locale}
    {moduleName}.i18n.yaml I18nManager初始化的时候会自动加载所有i18n文件
    /nop
    /aop
    {xxx}.annotations Nop的AOP代码生成器生成包装类时会读取所有的annotations文件,并为每个标注了指定注解的类生成AOP包装类
    /autoconfig
    {xxx}.beans NopIoC会自动扫描解析所有后缀名为beans的文件,加载其中的beans.xml文件
    /core
    /reigstry
    {xxx}.register-model.xml 初始化时会自动扫描所有registry-model.xml文件,并注册对应的DSL模型解析器,
    将它们和特定的文件类型关联起来
    /dao
    /dialect
    /selector
    {xxx}.selector.xml 初始化时会自动扫描所有selector.xml文件,加载数据库方言的匹配规则
    {dialectName}.dialect.xml 数据库方言定义文件,按照dialectName来加载
    /main
    /auth
    /app.action-auth.xml 全局的操作权限和菜单定义文件,在其中通过x:extends来引用其他权限文件
    /app.data-auth.xml 全局的数据权限定义文件,在其中通过x:extends来引用其他数据权限文件
    /{moduleId} Nop模块的moduleId必须是nop/auth这种两级目录结构
    _module 每个Nop模块下都有一个_module文件来标记它是模块。
    /beans
    app-{xxx}.beans.xml NopIoC启动时会自动扫描每个模块的beans目录下以`app-`为前缀的beans.xml文件
    /model
    /{bizObjName}
    {bizObjName}.xbiz 所有的服务对象原则上都是要在beans.xml中注册,然后再通过对象名查找到对应的xbiz和xmeta文件
    {bizObjName}.xmeta NopDynEntity对象采用了简化注册流程,直接向BizObjectManager注册,没有在beans.xml中定义服务对象
    /orm
    app.orm.xml NopOrm引擎初始化的时候会加载所有模块的orm目录下的app.orm.xml模型文件
    /pages
    /{bizObjName}
    {pageId}.page.yaml 可以配置页面文件在系统初始化的情况下加载,它引用的view模型因此被连带加载
    {bizObjName}.view.xml View模型不会被自动加载,但是一般会放置在这个位置
    - -

    模型文件自动加载顺序

    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/vfs/vfs/index.html b/projects/nop-entropy/docs/dev-guide/vfs/vfs/index.html index ecc3c86..f323be5 100644 --- a/projects/nop-entropy/docs/dev-guide/vfs/vfs/index.html +++ b/projects/nop-entropy/docs/dev-guide/vfs/vfs/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/workflow/flow-builder/index.html b/projects/nop-entropy/docs/dev-guide/workflow/flow-builder/index.html index e5caaf3..1cbe910 100644 --- a/projects/nop-entropy/docs/dev-guide/workflow/flow-builder/index.html +++ b/projects/nop-entropy/docs/dev-guide/workflow/flow-builder/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1139 +186,105 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/workflow/graph-designer/index.html b/projects/nop-entropy/docs/dev-guide/workflow/graph-designer/index.html index 690f668..d8826a5 100644 --- a/projects/nop-entropy/docs/dev-guide/workflow/graph-designer/index.html +++ b/projects/nop-entropy/docs/dev-guide/workflow/graph-designer/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1123 +186,89 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    通用流程设计器

    - - - - -
    -

    工作流、逻辑流、审批流等可视化设计器基本结构类似,都是定义一组节点、连线,然后可以拖拽节点,编辑节点属性等。

    -

    Nop平台提供了一个内置的通用流程设计器,可以根据元模型定义具体生成一个特定的流程设计器。具体步骤如下:

    -

    流程设计器生成步骤

      -
    1. 根据graph-designer.xdef设计一个具体的流程设计器模型,例如oa-flow.graph-designer.xml
    2. -
    3. FlowBuilderGenerator根据oa-flow.graph-designer.xml生成一个js库,前端可以使用SystemJs包加载机制动态加载这个流程定义库
    4. -
    5. 在前端的amis页面中,已经内置了nop-graph-designer控件,它通过initApi加载流程图数据,通过saveApi保存流程图数据。
      它内部的editor会识别流程类型,并使用动态加载的流程定义库。
    6. -
    -

    流程图数据

    前端编辑器进行编辑的时候,数据分成两个部分diagram和data,其中diagram对应于图形化展示数据,比如节点的位置、大小、样式等,而data则是附加在节点上和连线上的额外的业务数据

    -

    流程模型转换

    NopWorkflow的元模型由xwf.xdef元模型定义,它是一个通用的工作流模型,内部支持 step/action/transition/actor等工作流核心概念,但是它并不是为审批流特殊设计的流程引擎,
    因此核心概念中没有会签、或签等审批专用概念。工作流模型远比审批流模型要强大,但是在配置和使用层面,如果针对审批场景,审批流模型更简单、易用。

    -

    NopWorkflow的做法是通过元编程,将审批流模型转化为底层的工作流模型来应用,这样就可以同时兼顾模型的易用性和底层引擎的通用性。

    -

    与具体框架无关的低代码方案

    前端的@nop-chaos/nop-core模块提供了RenderContext抽象,它将低代码的渲染和组件间通讯机制、远程调用机制都以框架无关的方式定义出来。

    -
    type RenderContext = {
    /**
    * 将json对象渲染为虚拟DOM类型。不同的框架实现不同
    */
    render: (name:string, schema: SchemaType, props:any, ctx:any) => VDomType,

    /**
    * 动态执行ajax调用,
    */
    executor: (request: FetcherRequest, ctx:any) => Promise<FetcherResult>,

    /**
    * 向上冒泡触发自定义动作
    */
    onEvent: (event:string, data:any, ctx:any) => any

    /**
    * 监听兄弟节点或者父节点触发的事件
    * @param source 兄弟节点或者父节点的标识
    * @param handler 回调函数
    */
    observeEvent: (source: string, handler: OnEventType) => void
    }
    - -
      -
    • render函数可以用于封装amis或者fomily等任何基于json进行渲染的前端低代码框架
    • -
    • executor函数可以根据描述式的远程API调用执行AJAX请求,并异步返回结果,自动处理loading和错误消息提示等问题
    • -
    • onEvent函数可以用于通知父节点本对象有事件发生
    • -
    • observeEvent可以用于监听父节点或者兄弟节点中发生的事件
    • -
    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/workflow/task-concepts/index.html b/projects/nop-entropy/docs/dev-guide/workflow/task-concepts/index.html index 5fbe520..7f38126 100644 --- a/projects/nop-entropy/docs/dev-guide/workflow/task-concepts/index.html +++ b/projects/nop-entropy/docs/dev-guide/workflow/task-concepts/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/workflow/task-flow/index.html b/projects/nop-entropy/docs/dev-guide/workflow/task-flow/index.html index 5ce97c5..083c7be 100644 --- a/projects/nop-entropy/docs/dev-guide/workflow/task-flow/index.html +++ b/projects/nop-entropy/docs/dev-guide/workflow/task-flow/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1144 +186,110 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/workflow/task-queue/index.html b/projects/nop-entropy/docs/dev-guide/workflow/task-queue/index.html index 7cb12b6..85710fb 100644 --- a/projects/nop-entropy/docs/dev-guide/workflow/task-queue/index.html +++ b/projects/nop-entropy/docs/dev-guide/workflow/task-queue/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1114 +186,80 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    任务队列

    - - - - -
    -

    示例:

    -
    class NopJobTask {
    String taskId;
    String jobGroup;
    String jobName;
    int status;
    Timestamp startTime;
    Timestamp finishTime;

    Timestamp cancelTime;
    Timestamp restartTime;

    Map<String, Object> jobParams;
    ErrorBean errorInfo;
    String executorHost;
    int executorPort;
    IntRangeSet partitionSet;
    }

    interface IJobTaskExecutor {

    void startTask(JobTaskRequest request);

    void cancelTask(String taskId);

    JobTaskState getTaskState(String taskId);
    }
    - -
      -
    • nop_job_task表中保存了所有执行的异步任务
    • -
    • 任务状态:已创建、待执行、执行中、已暂停、已结束、已失败、已取消
    • -
    • 任务可以被分布式执行,因此需要记录执行者地址,执行者端口,执行参数,错误信息
    • -
    • 任务执行者提供 start, cancel, getState这三个api,同时应该主动向管理端上传执行状态。
    • -
    • 为了支持并行处理,任务具有partitionSet属性,用于标记当前所处理的数据分区集合
    • -
    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/workflow/task-step-decorator/index.html b/projects/nop-entropy/docs/dev-guide/workflow/task-step-decorator/index.html index ceb2fb4..9e3833c 100644 --- a/projects/nop-entropy/docs/dev-guide/workflow/task-step-decorator/index.html +++ b/projects/nop-entropy/docs/dev-guide/workflow/task-step-decorator/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1115 +186,81 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    事务装饰器

    - - - - -
    -
    -

    需要引入nop-task-ext模块

    -
    -

    可以通过transaction装饰器来控制步骤事务范围。

    -

    <sequential name="parentStep">
    <decorator name="transaction"/>

    <steps>
    <xpl name="step1">
    <source><![CDATA[
    import io.nop.sys.dao.entity.NopSysDict;

    const daoProvider = inject("nopDaoProvider");
    const dao = daoProvider.dao("NopSysDict");
    const dict = new NopSysDict();
    dict.setDictName("sys/test2");
    dict.setDisplayName("test");
    dao.saveEntity(dict);
    dao.flushSession();
    ]]></source>
    </xpl>

    <xpl name="step2">
    <source>
    <c:throw errorCode="test-error"/>
    </source>
    </xpl>
    </steps>
    </sequential>
    - -

    decorator上可以通过如下参数来控制事务细节

    -
      -
    • txn:txnGroup 指定事务分组,一般不用指定,对应于default
    • -
    • txn:propagation 指定是否新建事务,对应于 TransactionPropagation枚举类中的值
    • -
    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/antlr/index.html b/projects/nop-entropy/docs/dev-guide/xlang/antlr/index.html index d34d773..30f3de3 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/antlr/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/antlr/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/feature-expr/index.html b/projects/nop-entropy/docs/dev-guide/xlang/feature-expr/index.html index 9e4c874..accbf28 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/feature-expr/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/feature-expr/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1121 +186,87 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    特性开关

    - - - - -
    -

    在XDSL的任意节点上都可以通过特性表达式来实现编译期的开关选择

    -
    <root>
    <child feature:on="my.flag and !my.disabled-flag">
    </child>
    </root>
    - -
      -
    • feature:on表示表达式为true时节点才存在,否则在加载的后处理操作中会被自动删除
    • -
    • feature:off的语义表示表达式为false时节点才存在,语义与feature:on相反
    • -
    • 节点上可以同时具有feature:onfeature:off设置,两个判断都通过才可以
    • -
    -

    特性表达式

      -
    1. 特性表达式支持复杂的and/or语法,简单的比较运算,比如>=,=等。
    2. -
    3. 可以通过!表示取反
    4. -
    5. 支持括号
    6. -
    -

    虚拟节点

    有时为了方便控制,我们可以加入一个虚拟节点。当特性开关不满足时,虚拟节点下的所有内容都会自动被删除。

    -
    <domain>
    <options>
    <x:div feature:on="my.a1">
    <option>1</option>
    <option>2</option>
    </x:div>
    <option>3</option>
    </options>
    </domain>
    - -

    当application.yaml中配置my.a1=true时,加载得到的XNode节点为

    -
    <domain>
    <options>
    <option>1</option>
    <option>2</option>
    <option>3</option>
    </options>
    </domain>
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/index.html b/projects/nop-entropy/docs/dev-guide/xlang/index.html index fb81459..415d23c 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1105 +186,71 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/meta-programming/index.html b/projects/nop-entropy/docs/dev-guide/xlang/meta-programming/index.html index 2ae2351..f1484c5 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/meta-programming/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/meta-programming/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/x-override/index.html b/projects/nop-entropy/docs/dev-guide/xlang/x-override/index.html index cb2e4cf..695acda 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/x-override/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/x-override/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xdef/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xdef/index.html index 6c4ae2e..b96e4ab 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xdef/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xdef/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xdsl/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xdsl/index.html index ed53a7b..983f0bf 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xdsl/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xdsl/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xjson/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xjson/index.html index a159477..76943f9 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xjson/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xjson/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1123 +186,89 @@ -
    +
    + + + +
    +
    +
    + + +

    使用XML格式来表达json对象

    -
    +

    XLang语言中规定了XML和JSON的标准转换方式,可以实现XML和JSON之间的可逆转换。

    +

    xjson是一种紧凑的XML和json映射方式,它规定了如下规则:

    +
      +
    1. tagName对应于json中的type属性
    2. +
    3. body段如果有多个节点则自动对应于列表对象
    4. +
    5. j:list=”true”表示本节点对应于列表对象
    6. +
    7. 属性的值如果具有 @:前缀,则表示后面是json格式
    8. +
    +

    例如:

    +
    <form name="a">
    <actions j:list="true">
    <action enabled="@:false" label="ss" />
    </actions>

    <body>
    <input />
    <input />
    </body>
    </form>
    + +

    转换成json对应于

    +
    {
    "type": "form",
    "name": "a",
    "actions": [
    {
    "type": "action",
    "enabled": false,
    "label": "ss"
    }
    ],
    "body": [
    {
    "type": "input"
    },
    {
    "type": "input"
    }
    ]
    }
    + +

    Xpl中的xjson

    XPL模板语言可以设置outputMode=”xjson”,从而通过Xpl模板语言来动态构建json对象。web.xlib中大量利用这种方式来生成amis页面,
    它比直接使用json格式要简单直观得多。

    +
    <actions xpl:if="hasAction">
    <action enabled="${enabled}" />
    </actions>
    +

    在xdef元模型定义中,xdef:value=”xpl-xjson”表示对应的xpl模板会输出xjson内容。如果没有输出,则返回值对应于xjson的输出结果。

    +

    例如,XView模型中cell单元格的gen-control节点是xjson输出节点,对于它的配置,以下两种方式是等价的:

    +
    <form>
    <cell>
    <gen-control>
    <input type="a" width="${config.width}"/>
    </gen-control>
    </cell>

    <cell>
    <gen-control>
    <c:script>
    return {
    type: "a",
    width: config.width
    }
    </c:script>
    </gen-control>
    </cell>
    </form>
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    使用XML格式来表达json对象

    - - - - -
    -

    XLang语言中规定了XML和JSON的标准转换方式,可以实现XML和JSON之间的可逆转换。

    -

    xjson是一种紧凑的XML和json映射方式,它规定了如下规则:

    -
      -
    1. tagName对应于json中的type属性
    2. -
    3. body段如果有多个节点则自动对应于列表对象
    4. -
    5. j:list=”true”表示本节点对应于列表对象
    6. -
    7. 属性的值如果具有 @:前缀,则表示后面是json格式
    8. -
    -

    例如:

    -
    <form name="a">
    <actions j:list="true">
    <action enabled="@:false" label="ss" />
    </actions>

    <body>
    <input />
    <input />
    </body>
    </form>
    - -

    转换成json对应于

    -
    {
    "type": "form",
    "name": "a",
    "actions": [
    {
    "type": "action",
    "enabled": false,
    "label": "ss"
    }
    ],
    "body": [
    {
    "type": "input"
    },
    {
    "type": "input"
    }
    ]
    }
    - -

    Xpl中的xjson

    XPL模板语言可以设置outputMode=”xjson”,从而通过Xpl模板语言来动态构建json对象。web.xlib中大量利用这种方式来生成amis页面,
    它比直接使用json格式要简单直观得多。

    -
    <actions xpl:if="hasAction">
    <action enabled="${enabled}" />
    </actions>
    - -

    在xdef元模型定义中,xdef:value=”xpl-xjson”表示对应的xpl模板会输出xjson内容。如果没有输出,则返回值对应于xjson的输出结果。

    -

    例如,XView模型中cell单元格的gen-control节点是xjson输出节点,对于它的配置,以下两种方式是等价的:

    -
    <form>
    <cell>
    <gen-control>
    <input type="a" width="${config.width}"/>
    </gen-control>
    </cell>

    <cell>
    <gen-control>
    <c:script>
    return {
    type: "a",
    width: config.width
    }
    </c:script>
    </gen-control>
    </cell>
    </form>
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xlang-demo/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xlang-demo/index.html index 3574a09..4ce774c 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xlang-demo/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xlang-demo/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1144 +186,110 @@ -
    +
    + + + +
    +
    +
    + + +

    XLang综合示例

    -
    +

    一. 使用XDef来定义元模型

    例如 imp.xdef
    是Excel导入模型的元模型,它描述了为了实现Excel文件解析,我们需要提供哪些信息。

    +

    <imp>
    ....

    <sheet name="!string">
    <normalizeFieldsExpr xdef:value="xpl"/>
    ...
    </sheet>
    ...
    </imp>
    + +

    在元模型的定义中,属性值对应于属性所对应的stdDomain(对数据类型的一种细化定义)。
    例如 name="!string"表示name属性是字符串类型(满足string这个stdDomain的格式要求),而stdDomain前的!符号表示属性非空,即name属性必须有值。

    +

    对于节点内容的类型,我们通过xdef:value属性来指定,例如xdef:value="xpl"表示节点的body部分使用XPL模板语言。

    +

    二. 模型必须引用元模型

    具体的模型定义需要通过x:schema属性来表示它所对应的元模型。模型的结构必须满足元模型的定义要求。这一机制类似于JSON对象的结构需要满足JSON
    Schema的约束。
    只不过XDef元模型比JSON Schema更强大,比如它提供了xpl、xpl-predicate等可执行代码类型,而JSON
    Schema只能指定Number,String等少数纯数据类型,没有定义函数等可执行类型。

    +

    例如 orm.imp.xml
    是导入数据库模型时使用的导入模型配置

    +

    <imp x:schema="/nop/schema/excel/imp.xdef" xmlns:x="/nop/schema/xdsl.xdef">
    ...
    <sheet name="entity" namePattern=".*" field="entities" multiple="true" keyProp="name" sheetNameProp="tableName">
    <normalizeFieldsExpr>
    <c:script><![CDATA[
    ...
    ]]></c:script>
    </normalizeFieldsExpr>
    ...
    </sheet>
    ...
    </imp>
    + +

    normalizeFieldsExpr在元模型中对应的stdDomain是xpl,对应的Java类型为IEvalAction
    接口。
    在具体的模型中,normalizeFieldsExpr的body使用xpl模板语言。这里有一个特殊情况,当body段只有一个c:script
    节点的时候,我们可以直接写XScript脚本语法,而不需要使用c:script来包裹。
    例如,以下两种方式是等价的

    +

    <normalizeFieldsExpr>
    <c:script>
    import xxx.MyHelper;
    return MyHelper.myMethod(a);
    </c:script>
    </normalizeFieldsExpr>

    <normalizeFieldsExpr>
    import xxx.MyHelper;
    return MyHelper.myMethod(a);
    </normalizeFieldsExpr>
    + +

    三. XPL模板语言和XScript语言可以相互嵌套

    在xpl模板语言中,我们可以通过c:script标签来嵌入XScript脚本语言的片段,例如

    +
    <c:for var="x" items="${list}">
    <c:script>
    if(x < 0)
    break;
    </c:script>
    </c:for>
    + +

    反过来,在XScript脚本语言中,我们可以通过xpl函数来嵌入xpl模板语言。此时存在两种调用方式

    +

    模板字符串

    <c:script>
    let list = [1,2,3];
    let result = xpl `<c:for var='x` items="${list}">
    <my:MyTag x="${x}" />
    </c:for>`;
    </c:script>
    + +

    在xpl模板表达式中,可以通过${list}来表示获取到上下文环境中的变量。

    +
    +

    在XLang语言的设计中,我们没有选择使用jsx语法来嵌入模板语言,而是扩展了JavaScript中的模板字符串机制,将模板字符串和宏函数机制结合在一起。
    xpl是一个宏函数,在编译期它会自动解析它的参数得到Expression抽象语法树节点,然后插入到当前脚本的编译结果中。这一设计类似于C#语言中的LinQ机制,
    但它更为通用,可以支持嵌入任意语法。例如 xpath /a/b[@a="3"] 可以表示嵌入xpath语法,xpath是一个宏函数,它在编译期会自动解析它的参数得到XPath对象。

    +
    +

    xpl函数调用标签

    可以通过xpl函数来表示直接调用某个XPL标签,此时xpl函数的第一个参数不是XML格式的代码,而是标签名

    +
    let result = xpl('my:MyTag',{x:3})
    + +

    xpl函数的第二个参数是Map形式的参数集合。除了以Map形式来传入参数集合之外,当参数个数比较少时,我们也可以按照参数的定义顺序来传递参数,例如

    +
    xpl('my:MyTag',x,y);
    + +

    这种情况下x必须是MyTag标签定义中的第一个参数,而y是第二个参数。

    +

    四. 扩展属性

    在Nop平台的模型文件中,除了使用元模型中定义的属性之外,我们可以随时增加自定义属性。缺省情况下,XDSL模型解析器将所有带名字空间的属性和节点看作是扩展属性,不会要求它们在元模型中有相应的定义。

    +

    但是,如果在元模型中,我们明确指定了xdef:check-ns,则表示这些名字空间中的名称不能随意扩展,只能是元模型中定义的那些名称。例如

    +
    <imp xdef:check-ns="imp,xpt">
    <xpt:beforeExpand xdef:value="xml" />
    </imp>
    + +

    我们可以在自己的项目中定制平台中已有的xdef元模型。例如我们可以继承平台内置的imp.xdef元模型定义,为它增加扩展属性配置。

    +
    <!-- /my/my-imp.xdef -->
    <imp x:extends="/nop/schema/excel/imp.xdef" xdef:base="/nop/schema/excel/imp.xdef"
    x:schema="/nop/schema/xdef.xdef" xmlns:x="/nop/schema/xdsl.xdef" >
    <imp:MyExt value="!string" />
    </imp>
    + +

    在具体的模型定义中,只要引用扩展的元模型文件即可。

    +
    <imp x:schema="/my/my-imp.xdef" xmlns:x="/nop/schema/xdsl.xdef">
    <imp:MyExt value="abc" />
    </imp>
    + +

    在上面的示例中,我们使用了my-imp.xdef元模型,所以我们可以定义imp:MyExt扩展节点。而如果使用平台内置的imp.xdef元模型,
    则因为imp:MyExt节点在imp.xdef元模型中没有定义,同时xdef:check-ns="imp,xpt"要求检查imp空间中名称的有效性,所以解析的时候会报错。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xlang/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xlang/index.html index cc0a277..3528ffa 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xlang/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xlang/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    + + + + + +
    -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xmeta/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xmeta/index.html index bd86679..c4dd49b 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xmeta/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xmeta/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xpath/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xpath/index.html index db96a44..fda9b3e 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xpath/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xpath/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xpl/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xpl/index.html index 955243d..eb91af9 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xpl/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xpl/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xscript/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xscript/index.html index f53a036..5a5e14d 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xscript/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xscript/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xlang/xtransform/index.html b/projects/nop-entropy/docs/dev-guide/xlang/xtransform/index.html index 98a6309..fda9b3e 100644 --- a/projects/nop-entropy/docs/dev-guide/xlang/xtransform/index.html +++ b/projects/nop-entropy/docs/dev-guide/xlang/xtransform/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/xui/adapter/index.html b/projects/nop-entropy/docs/dev-guide/xui/adapter/index.html index 64638d6..1a2016f 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/adapter/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/adapter/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1124 +186,90 @@ -
    +
    + + + +
    +
    +
    + + +

    适配

    -
    +

    页内跳转

      +
    1. __back: 调用router.back()
    2. +
    3. __forward: 调用router.forward()
    4. +
    5. 对于后缀名为page.yaml/page.json/page.json5等后缀的链接,使用jsonPage显示
    6. +
    +

    特殊链接

    @query

    对应GraphQL query,它的格式为 @query:{operationName}/{selection},
    例如 @query:NopAuthUser__get/userName,nickName,dept{name} 会被翻译为

    +
    query{
    NopAuthUser(id:$id){
    userName, nickName, dept { name}
    }
    }
    + +

    对于标准的CRUD动作,例如xxx__get, xxx_findPage等,在graphql.ts的operationRegistry中注册了对应的参数列表。
    注意:这里注册的是动作的后缀,也就说NopAuthUser__findPage或者NopAuthUser__admin_findPage,返回的标准方法名都是findPage,它们的参数格式都是

    +
    {
    // operation: 'query',
    arguments: [
    {
    name: 'query',
    type: 'QueryBeanInput',
    builder: argQuery
    }
    ]
    }
    + +

    @mutation

    对应GraphQL mutation, 它的格式与@query类似。

    +

    @dict

    利用DictProvider__getDict服务来加载字典项,例如 @dict:my/my-dict

    +

    @page

    加载页面,动态加载xui:import引入的函数库,并resolve页面中用到的action

    +

    @action

    触发page上定义的action,或者xui:import引入的action,例如

    +
    {
    "xui:import": "demo.lib.js",
    "api": {
    "url": "@action:demo.myAction"
    }
    }
    +

    @action:demo.myAction表示调用demo.lib.js库中的myAction方法。作为api的url来触发时,传给函数的参数为FetcherRequest类型

    +

    @fn

    直接定义的匿名函数

    +

    自定义事件动作

    前台引入了一个特殊的page-action类型的动作,它的参数中必须包含一个特殊的参数@action用于指定触发的动作名称。

    +
    {
    "onEvent": {
    "click": { // 监听点击事件
    "actions": [ // 执行的动作列表
    {
    "actionType": "page-action", // 执行自定义action
    "args": { //
    "@action": "demo.myAction",
    "msg": "派发点击事件"
    }
    }
    ]
    }
    }
    }
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/dev-guide/xui/amis/index.html b/projects/nop-entropy/docs/dev-guide/xui/amis/index.html index 094e706..fd8c85e 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/amis/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/amis/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xui/index.html b/projects/nop-entropy/docs/dev-guide/xui/index.html index ce20609..ebcfb4c 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/dev-guide/xui/javascript/index.html b/projects/nop-entropy/docs/dev-guide/xui/javascript/index.html index 5d275a6..86d01a1 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/javascript/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/javascript/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1109 +186,75 @@ -
    +
    + + + +
    +
    +
    + + +

    XScript与JavaScript的兼容性

    -
    +

    所有对象都是Java对象

    XScript语法类似于JavaScript,但是并不支持JavaScript内置的对象如Array, Set, Map等。

    +

    如果严格符合ECMAScript的对象标准,就会导致与Java的不兼容。现在语法设计是java兼容优先,避免对象转换,所以
    数组语法[1,2,3]返回的是ArrayList,而对象语法 {a:1,b:2}返回的是LinkedHashMap(这里选择了LinkedHashMap而不是HashMap是为了保持key的顺序与加入顺序一致)。

    +

    所以XScript中所使用的对象都是Java对象,其中的方法都是java的方法,其中对于List特殊处理了一下,针对List扩展了一些函数(参见ListFunctions.java),
    可以使用push,pop, slice等函数,但是并没有取消原先List上的add等函数,本质上函数都是使用Java对象上的函数。

    +

    在XScript中可以调用new Set(),但是它也只是新建LinkedHashSet对象。

    +

    不区分undefined和null

    undefined设计与Java不兼容,所以取消了===语法,也取消了undefined语义,只定义了null语义。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    XScript与JavaScript的兼容性

    - - - - -
    -

    所有对象都是Java对象

    XScript语法类似于JavaScript,但是并不支持JavaScript内置的对象如Array, Set, Map等。

    -

    如果严格符合ECMAScript的对象标准,就会导致与Java的不兼容。现在语法设计是java兼容优先,避免对象转换,所以
    数组语法[1,2,3]返回的是ArrayList,而对象语法 {a:1,b:2}返回的是LinkedHashMap(这里选择了LinkedHashMap而不是HashMap是为了保持key的顺序与加入顺序一致)。

    -

    所以XScript中所使用的对象都是Java对象,其中的方法都是java的方法,其中对于List特殊处理了一下,针对List扩展了一些函数(参见ListFunctions.java),
    可以使用push,pop, slice等函数,但是并没有取消原先List上的add等函数,本质上函数都是使用Java对象上的函数。

    -

    在XScript中可以调用new Set(),但是它也只是新建LinkedHashSet对象。

    -

    不区分undefined和null

    undefined设计与Java不兼容,所以取消了===语法,也取消了undefined语义,只定义了null语义。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xui/layout/index.html b/projects/nop-entropy/docs/dev-guide/xui/layout/index.html index 644861c..8b9dd0c 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/layout/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/layout/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xui/sdk/index.html b/projects/nop-entropy/docs/dev-guide/xui/sdk/index.html index 35581f9..980b084 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/sdk/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/sdk/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1120 +186,86 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    通过nop-sdk实现前端集成

    - - - - -
    -

    nop-chaos前端项目中所有nop平台相关的代码都集中在@nop-chaos/sdk模块中。如果要在新的项目中引入AMIS页面支持,只需要执行以下步骤

    - -

    1. 引入nop-sdk模块

    "@nop-chaos/sdk": "file:./nop-sdk",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "amis": "^3.4.0",
    "amis-core": "^3.4.0",
    "amis-formula": "^3.4.0",
    "amis-ui": "^3.4.0",
    - -

    nop-sdk@nop-chaos/sdk模块打包后的结果。直接将它拷贝到目标工程中。
    file:./nop-sdk表示模块代码在当前目录的nop-sdk子目录中。

    -

    2. 实现adapter

    src/nop/initNopApp.ts文件中为适配器接口提供实现,实现nop-sdk集成。

    -
    // 调试器使用了element的组件
    import 'element-plus/dist/index.css'

    // Amis内置的调试器需要这里的css
    import 'amis/lib/helper.css';

    import '@fortawesome/fontawesome-free/css/all.css';
    import '@fortawesome/fontawesome-free/css/v4-shims.css';
    import 'amis/lib/themes/cxd.css';

    //import 'amis/sdk/iconfont.css';
    import 'amis-ui/lib/locale/en-US';
    import 'amis-ui/lib/locale/zh-CN';

    import '@nop-chaos/sdk/lib/style.css'

    ...

    function initAdapter(app: App) {
    registerAdapter({

    useLocale(): string {
    return currentLocale.value
    },

    /**
    * 返回当前的认证token
    */
    useAuthToken(): string {
    return getToken()
    },

    setAuthToken(token?: string) {
    useUserStore().setToken(token)
    },
    ...
    })
    }

    export function initNopApp(app: App) {
    initAdapter(app)

    app.component("XuiPage", XuiPage)
    ...
    }
    - -

    3. 在main.ts中加入对initNopApp的调用


    import {initNopApp} from '@/nop/initNopApp'

    const app = createApp(App)
    ...
    initNopApp(app)

    app.mount('#app')
    - -

    4. 在主页面上增加AmisToast控件,用于弹出错误消息

    一般在App.vue页面中增加控件

    -
    <template>
    <ConfigProvider :locale="getAntdLocale">
    <AmisToast theme="cxd"/>
    ...
    </ConfigProvider>
    </template>

    <script lang="ts" setup>
    import { ConfigProvider } from 'ant-design-vue';
    ...
    import {AmisToast} from '@nop-chaos/sdk'
    </script>
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xui/typescript/index.html b/projects/nop-entropy/docs/dev-guide/xui/typescript/index.html index 74cb601..3540202 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/typescript/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/typescript/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1109 +186,75 @@ -
    +
    + + + +
    +
    +
    + + +

    提取实体类型的部分字段类型

    -
    +

    要声明一个类型,它表示从类型A中提取字段”a”和”b”的定义,并将字段”b”的类型修改为可空类型,您可以使用”Pick”和”Partial”内置类型的组合。以下是示例代码:

    +
    type A = { a: number, b: string, c: boolean };

    type ExtractAB = Pick<A, 'a' | 'b'> & Partial<Pick<A, 'b'>>;

    // 示例用法
    const obj: ExtractAB = {
    a: 1,
    b: null // b现在是可空类型
    };
    + +

    在上面的代码中,我们首先使用”Pick”类型从类型A中提取字段”a”和”b”的定义。然后,我们使用”Partial”类型将字段”b”的类型修改为可空类型。最后,我们将这两个类型组合在一起,得到一个新的类型ExtractAB。

    +

    现在,类型ExtractAB将只包含字段”a”和可空字段”b”的定义。其他字段将不包含在该类型中。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    提取实体类型的部分字段类型

    - - - - -
    -

    要声明一个类型,它表示从类型A中提取字段”a”和”b”的定义,并将字段”b”的类型修改为可空类型,您可以使用”Pick”和”Partial”内置类型的组合。以下是示例代码:

    -
    type A = { a: number, b: string, c: boolean };

    type ExtractAB = Pick<A, 'a' | 'b'> & Partial<Pick<A, 'b'>>;

    // 示例用法
    const obj: ExtractAB = {
    a: 1,
    b: null // b现在是可空类型
    };
    - -

    在上面的代码中,我们首先使用”Pick”类型从类型A中提取字段”a”和”b”的定义。然后,我们使用”Partial”类型将字段”b”的类型修改为可空类型。最后,我们将这两个类型组合在一起,得到一个新的类型ExtractAB。

    -

    现在,类型ExtractAB将只包含字段”a”和可空字段”b”的定义。其他字段将不包含在该类型中。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xui/web-xlib/index.html b/projects/nop-entropy/docs/dev-guide/xui/web-xlib/index.html index 9a299e4..dbb05ee 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/web-xlib/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/web-xlib/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1106 +186,72 @@ -
    +
    + + + +
    +
    +
    + + +

    web.xlib

    -
    +

    page.yaml文件中可以使用web.xlib中定义的GenPage, GenAction, GenForm等标签来动态生成amis页面。

    +

    LoadPage

    根据传入的page参数来加载json页面,得到json对象。page可能对应于view模型中的pageId,也可以是一个完整的页面的虚拟路径,
    例如page=/nop/auth/pages/NopAuthUser/main.page.yaml,或者page=main

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    web.xlib

    - - - - -
    -

    page.yaml文件中可以使用web.xlib中定义的GenPage, GenAction, GenForm等标签来动态生成amis页面。

    -

    LoadPage

    根据传入的page参数来加载json页面,得到json对象。page可能对应于view模型中的pageId,也可以是一个完整的页面的虚拟路径,
    例如page=/nop/auth/pages/NopAuthUser/main.page.yaml,或者page=main

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xui/xpage/index.html b/projects/nop-entropy/docs/dev-guide/xui/xpage/index.html index deb45a7..9ec3bd2 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/xpage/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/xpage/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    + + +
    +
    @@ -1663,20 +616,6 @@

    调试
    "onClick": "debugger; props.store.closeDialog()"

    + + +
    -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/dev-guide/xui/xview/index.html b/projects/nop-entropy/docs/dev-guide/xui/xview/index.html index 0786355..6ec12dc 100644 --- a/projects/nop-entropy/docs/dev-guide/xui/xview/index.html +++ b/projects/nop-entropy/docs/dev-guide/xui/xview/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/faq/debug-errors/index.html b/projects/nop-entropy/docs/faq/debug-errors/index.html index cf54fee..f8a8e85 100644 --- a/projects/nop-entropy/docs/faq/debug-errors/index.html +++ b/projects/nop-entropy/docs/faq/debug-errors/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1107 +186,73 @@ -
    +
    + + + +
    +
    +
    + + +

    调试错误

    -
    +

    1. BizModel层类型转换错误

    2024-01-13 22:34:08 [http-nio-8000-exec-7] ERROR io.nop.core.exceptions.ErrorMessageManager - nop.build-error-message
    java.lang.ClassCastException: class com.ly.ale.pojo.AleYearPlanPO cannot be cast to class io.nop.orm.IOrmEntity (com.ly.ale.pojo.AleYearPlanPO and io.nop.orm.IOrmEntity are in unnamed module of loader 'app')
    at io.nop.graphql.orm.fetcher.OrmEntityIdFetcher.get(OrmEntityIdFetcher.java:19)
    at io.nop.graphql.core.engine.GraphQLExecutor.hookFetch(GraphQLExecutor.java:372)
    at io.nop.graphql.core.engine.GraphQLExecutor.fetchSelection(GraphQLExecutor.java:356)
    +

    这是因为BizModel上的方法标记了 @GraphQLReturn(bizObjName=BIZ_OBJ_NAME_THIS_OBJ),它导致强制要求返回的类型为当前实体对象。因此当
    实际返回其他的DTO对象时出现转型错误。

    +
    @GraphQLReturn(bizObjName = BIZ_OBJ_NAME_THIS_OBJ)
    public List<T> myMethod() {
    返回 List<PO> 对象
    }
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    调试错误

    - - - - -
    -

    1. BizModel层类型转换错误

    2024-01-13 22:34:08 [http-nio-8000-exec-7] ERROR io.nop.core.exceptions.ErrorMessageManager - nop.build-error-message
    java.lang.ClassCastException: class com.ly.ale.pojo.AleYearPlanPO cannot be cast to class io.nop.orm.IOrmEntity (com.ly.ale.pojo.AleYearPlanPO and io.nop.orm.IOrmEntity are in unnamed module of loader 'app')
    at io.nop.graphql.orm.fetcher.OrmEntityIdFetcher.get(OrmEntityIdFetcher.java:19)
    at io.nop.graphql.core.engine.GraphQLExecutor.hookFetch(GraphQLExecutor.java:372)
    at io.nop.graphql.core.engine.GraphQLExecutor.fetchSelection(GraphQLExecutor.java:356)
    - -

    这是因为BizModel上的方法标记了 @GraphQLReturn(bizObjName=BIZ_OBJ_NAME_THIS_OBJ),它导致强制要求返回的类型为当前实体对象。因此当
    实际返回其他的DTO对象时出现转型错误。

    -
    @GraphQLReturn(bizObjName = BIZ_OBJ_NAME_THIS_OBJ)
    public List<T> myMethod() {
    返回 List<PO> 对象
    }
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/faq/faq/index.html b/projects/nop-entropy/docs/faq/faq/index.html index c5dbd2f..52d1742 100644 --- a/projects/nop-entropy/docs/faq/faq/index.html +++ b/projects/nop-entropy/docs/faq/faq/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/frontend/frontend-design/index.html b/projects/nop-entropy/docs/frontend/frontend-design/index.html index 8b2f7dd..8ea7a53 100644 --- a/projects/nop-entropy/docs/frontend/frontend-design/index.html +++ b/projects/nop-entropy/docs/frontend/frontend-design/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/frontend/nop-site/index.html b/projects/nop-entropy/docs/frontend/nop-site/index.html index b305863..aa7985c 100644 --- a/projects/nop-entropy/docs/frontend/nop-site/index.html +++ b/projects/nop-entropy/docs/frontend/nop-site/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1106 +186,72 @@ -
    +
    + + + +
    +
    +
    + + +

    界面框架

    -
    +

    菜单构建

    src/store/modules/permission.ts中通过getMenuList函数动态加载菜单,然后调用
    src/router/helper/routeHelper.ts中的transformObjToRoute函数将菜单返回结果转化为vue route

    +

    修改src/settings/projectSettings.ts中的permissionMode为BACK,从后台加载菜单

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    界面框架

    - - - - -
    -

    菜单构建

    src/store/modules/permission.ts中通过getMenuList函数动态加载菜单,然后调用
    src/router/helper/routeHelper.ts中的transformObjToRoute函数将菜单返回结果转化为vue route

    -

    修改src/settings/projectSettings.ts中的permissionMode为BACK,从后台加载菜单

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/frontend/react/index.html b/projects/nop-entropy/docs/frontend/react/index.html index df94b8f..df9e2a2 100644 --- a/projects/nop-entropy/docs/frontend/react/index.html +++ b/projects/nop-entropy/docs/frontend/react/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1122 +186,88 @@ -
    +
    + + + +
    +
    +
    + + +

    React

    -
    +

    useEffect的使用

    一般仅在跳出react代码,发起远程调用时使用。根据props或者state中的变量进行计算没必要使用。

    +
      +
    1. 缓存耗时的复杂计算结果时,使用useMemo。
    2. +
    3. 通过key属性标记本质上不同的数据记录,避免无意间共享数据,也就不需要重置数据
    4. +
    +
    <Profile userId={userId} key={profileId} />
    + +
      +
    1. 组件mount时发起请求,可以使用useEffect(fn,[])
    2. +
    3. dev环境下useEffect会被触发两次
    4. +
    5. 组件内状态如果需要和父组件同步,则通过状态提升交由父组件管理。例如
    6. +
    +
    <Toggle isOn={isOn} onChange={onChange} />
    +
      +
    1. 订阅外部存储时使用useSyncExternalStore
    2. +
    +

    状态库

    zustand,参考 https://zhuanlan.zhihu.com/p/691233120

    +
    import { useShallow } from 'zustand/react/shallow';
    ...
    const { theme, setTheme } = useConfigStore(
    useShallow(state => ({
    theme: state.theme,
    setTheme: state.setTheme,
    }))
    );
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    React

    - - - - -
    -

    useEffect的使用

    一般仅在跳出react代码,发起远程调用时使用。根据props或者state中的变量进行计算没必要使用。

    -
      -
    1. 缓存耗时的复杂计算结果时,使用useMemo。
    2. -
    3. 通过key属性标记本质上不同的数据记录,避免无意间共享数据,也就不需要重置数据
    4. -
    -
    <Profile userId={userId} key={profileId} />
    - -
      -
    1. 组件mount时发起请求,可以使用useEffect(fn,[])
    2. -
    3. dev环境下useEffect会被触发两次
    4. -
    5. 组件内状态如果需要和父组件同步,则通过状态提升交由父组件管理。例如
    6. -
    -
    <Toggle isOn={isOn} onChange={onChange} />
    - -
      -
    1. 订阅外部存储时使用useSyncExternalStore
    2. -
    -

    状态库

    zustand,参考 https://zhuanlan.zhihu.com/p/691233120

    -
    import { useShallow } from 'zustand/react/shallow';
    ...
    const { theme, setTheme } = useConfigStore(
    useShallow(state => ({
    theme: state.theme,
    setTheme: state.setTheme,
    }))
    );
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/frontend/vite/index.html b/projects/nop-entropy/docs/frontend/vite/index.html index e2fd7fb..6e2071e 100644 --- a/projects/nop-entropy/docs/frontend/vite/index.html +++ b/projects/nop-entropy/docs/frontend/vite/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1118 +186,84 @@ -
    +
    + + + +
    +
    +
    + + +

    Vite

    -
    +

    多模块

    多个模块中引入的amis版本需要一致,否则可能在调试开发时会出现多个版本的包被加载。

    +

    turbo

      +
    1. 在根项目的package.json中增加postinstall配置。 pnpm i会自动执行postinstall脚本
    2. +
    +
    "postinstall": "turbo run stub",
    + +
      +
    1. turbo.json的pipeline定义中要增加stub配置。stub对应空对象即可
    2. +
    +
    {
    "pipeline": {
    "stub": {
    }
    }
    }
    +
      +
    1. internal/vite-config等项目中配置stub
    2. +
    +
    "scripts": {
    "stub": "pnpm unbuild --stub"
    },
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    Vite

    - - - - -
    -

    多模块

    多个模块中引入的amis版本需要一致,否则可能在调试开发时会出现多个版本的包被加载。

    -

    turbo

      -
    1. 在根项目的package.json中增加postinstall配置。 pnpm i会自动执行postinstall脚本
    2. -
    -
    "postinstall": "turbo run stub",
    - -
      -
    1. turbo.json的pipeline定义中要增加stub配置。stub对应空对象即可
    2. -
    -
    {
    "pipeline": {
    "stub": {
    }
    }
    }
    - -
      -
    1. internal/vite-config等项目中配置stub
    2. -
    -
    "scripts": {
    "stub": "pnpm unbuild --stub"
    },
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/gpt/aisuda-prompts/index.html b/projects/nop-entropy/docs/gpt/aisuda-prompts/index.html index aa4efd2..72c7f26 100644 --- a/projects/nop-entropy/docs/gpt/aisuda-prompts/index.html +++ b/projects/nop-entropy/docs/gpt/aisuda-prompts/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1116 +189,82 @@ -
    +
    + + + +
    +
    +
    + + +

    -
    +

    �������ֳ����ɱ��������ֶεȶ�����֣�����few-shot��ʾ��ʽ

    +
    ���룺����һ�� ��̳ ϵͳ��Ҫ��Щ���ݿ���� 
    ������û���/user�����ӱ�/post�������/category��֪ͨ��/notificatoin�������/group

    ���룺����һ�� ���� ϵͳ��Ҫ��Щ���ݿ����
    ��������±�/article�������/category����ǩ��/tag�����۱�/commont���û���/user

    ���룺����һ�� IT���� ϵͳ��Ҫ��Щ���ݿ����
    ������ʲ���/asset�����ű�/department���û���/user�������/catetory��λ�ñ�/location����˾��/company

    ���룺����һ�� {system} ϵͳ��Ҫ��Щ���ݿ����
    �����
    + + +
    ���ݿ����������¼��֣�int��text��datetime��decimal��float

    ���룺����һ�� ���� ϵͳ�� ���±� ��Ҫ��Щ���ݿ��ֶμ����ͣ�
    �����id/int��title/text��content/text��publish_date/datetime��tag_id/int

    ���룺����һ�� ��ѧ ϵͳ�� ѧ���� ��Ҫ��Щ���ݿ��ֶμ����ͣ�
    �����id/int��name/text��age/int��gender/text��class_id/int

    ���룺����һ�� {system} �� {table} ��Ҫ��Щ���ݿ��ֶμ����ͣ�
    �����
    + +

    Chain of Thought
    ��ʾ�ʵ�ʾ���а���һ�����������
    Self-Consistency
    �� Chain of Thought ���������ɶ���𰸣��������Ӷ���
    Tree of Thoughts
    ÿ�����ɶ�������ÿ�������ȡ������õ�ǰ������һ�����ɣ����� Beam Search
    Least-to-Most
    ��һ�������ô�ģ�ͽ������ֳ������⣬��To solve xxx, we need to first solve: ��
    �ڶ������ֱ��ô�ģ��ȥ�����Щ�����⣬��������Ľ�������ʾ���У����ʼ������
    Generated Knowledge Prompting
    ��ģ�������ɹ�����������֪ʶ�㣬��ȥ�ش�����
    Automatic Prompt Engineer
    ��ģ�����ɺ�����������Ƶ����⣬Ȼ��������Щ�����ĸ����ã���ȥ��ģ�ͣ��൱���ô�ģ���Ȱ�æ�Ż�һ����ʾ��

    +

    Framerͨ�� TypeScript ������ָ�� GPT �ķ��ظ�ʽ���ֶ�Ҫ��

    +
    /** Image keys that are available for use. */
    type ImageKey = "single_object" | "sky" | "forest" | "close_up_of_plant" | "silhouette_female"

    type Section =
    // A heading with four images under it
    | { id: "gallery"; galleryTitleMax3Words: string; picture1: ImageKey; picture2: }
    // A big heading with a smaller text next to it
    | { id: "generic_text_1"; heading: string; paragraph: string }
    // A small category/label followed by a big text (a sentence or so)
    | { id: "generic_text_2"; labelOrCategory: string; shortSentence: string }
    // Title and description, next to it is a list of four items with years
    | { id: "text_list"; sectionTitle: string; sectionParagraph: string; listTitle: string; item1Title: string; }
    // Has 3 differently priced plans in format $4.99/mo etc

    interface Page {
    /** Several sections with the content that will appear on the page (top to bottom). */
    sections: Section[]
    }
    + +

    ��Ԥѵ���׶���������Ŀ��ֱ���һ���ı�ȥ�����һ�� token ��ȥ����һ�� token�����������ǡ�Once upon a time�������Ŀ���ǡ�upon a time in����������ָ��΢���������ǽ�ָ���������������������ǽ�ָ��ָij�һ������ֵ���ڼ��� loss ��ʱ������
    �����ڷ��򴫲���ʱ���ֻ�д𰸲�����㡣

    +
    def preprocess(
    sources: Sequence[str],
    targets: Sequence[str],
    tokenizer: transformers.PreTrainedTokenizer,
    ) -> Dict:
    """Preprocess the data by tokenizing."""
    examples = [s + t for s, t in zip(sources, targets)]
    examples_tokenized, sources_tokenized = [_tokenize_fn(strings, tokenizer) for strings in (examples, sources)]
    input_ids = examples_tokenized["input_ids"]
    labels = copy.deepcopy(input_ids)
    for label, source_len in zip(labels, sources_tokenized["input_ids_lens"]):
    label[:source_len] = IGNORE_INDEX
    return dict(input_ids=input_ids, labels=labels)
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    - - - - -
    -

    �������ֳ����ɱ��������ֶεȶ�����֣�����few-shot��ʾ��ʽ

    -
    ���룺����һ�� ��̳ ϵͳ��Ҫ��Щ���ݿ���� 
    ������û���/user�����ӱ�/post�������/category��֪ͨ��/notificatoin�������/group

    ���룺����һ�� ���� ϵͳ��Ҫ��Щ���ݿ����
    ��������±�/article�������/category����ǩ��/tag�����۱�/commont���û���/user

    ���룺����һ�� IT���� ϵͳ��Ҫ��Щ���ݿ����
    ������ʲ���/asset�����ű�/department���û���/user�������/catetory��λ�ñ�/location����˾��/company

    ���룺����һ�� {system} ϵͳ��Ҫ��Щ���ݿ����
    �����
    - - -
    ���ݿ����������¼��֣�int��text��datetime��decimal��float

    ���룺����һ�� ���� ϵͳ�� ���±� ��Ҫ��Щ���ݿ��ֶμ����ͣ�
    �����id/int��title/text��content/text��publish_date/datetime��tag_id/int

    ���룺����һ�� ��ѧ ϵͳ�� ѧ���� ��Ҫ��Щ���ݿ��ֶμ����ͣ�
    �����id/int��name/text��age/int��gender/text��class_id/int

    ���룺����һ�� {system} �� {table} ��Ҫ��Щ���ݿ��ֶμ����ͣ�
    �����
    - -

    Chain of Thought
    ��ʾ�ʵ�ʾ���а���һ�����������
    Self-Consistency
    �� Chain of Thought ���������ɶ���𰸣��������Ӷ���
    Tree of Thoughts
    ÿ�����ɶ�������ÿ�������ȡ������õ�ǰ������һ�����ɣ����� Beam Search
    Least-to-Most
    ��һ�������ô�ģ�ͽ������ֳ������⣬��To solve xxx, we need to first solve: ��
    �ڶ������ֱ��ô�ģ��ȥ�����Щ�����⣬��������Ľ�������ʾ���У����ʼ������
    Generated Knowledge Prompting
    ��ģ�������ɹ�����������֪ʶ�㣬��ȥ�ش�����
    Automatic Prompt Engineer
    ��ģ�����ɺ�����������Ƶ����⣬Ȼ��������Щ�����ĸ����ã���ȥ��ģ�ͣ��൱���ô�ģ���Ȱ�æ�Ż�һ����ʾ��

    -

    Framerͨ�� TypeScript ������ָ�� GPT �ķ��ظ�ʽ���ֶ�Ҫ��

    -
    /** Image keys that are available for use. */
    type ImageKey = "single_object" | "sky" | "forest" | "close_up_of_plant" | "silhouette_female"

    type Section =
    // A heading with four images under it
    | { id: "gallery"; galleryTitleMax3Words: string; picture1: ImageKey; picture2: }
    // A big heading with a smaller text next to it
    | { id: "generic_text_1"; heading: string; paragraph: string }
    // A small category/label followed by a big text (a sentence or so)
    | { id: "generic_text_2"; labelOrCategory: string; shortSentence: string }
    // Title and description, next to it is a list of four items with years
    | { id: "text_list"; sectionTitle: string; sectionParagraph: string; listTitle: string; item1Title: string; }
    // Has 3 differently priced plans in format $4.99/mo etc

    interface Page {
    /** Several sections with the content that will appear on the page (top to bottom). */
    sections: Section[]
    }
    - - -

    ��Ԥѵ���׶���������Ŀ��ֱ���һ���ı�ȥ�����һ�� token ��ȥ����һ�� token�����������ǡ�Once upon a time�������Ŀ���ǡ�upon a time in����������ָ��΢���������ǽ�ָ���������������������ǽ�ָ��ָij�һ������ֵ���ڼ��� loss ��ʱ������
    �����ڷ��򴫲���ʱ���ֻ�д𰸲�����㡣

    -
    def preprocess(
    sources: Sequence[str],
    targets: Sequence[str],
    tokenizer: transformers.PreTrainedTokenizer,
    ) -> Dict:
    """Preprocess the data by tokenizing."""
    examples = [s + t for s, t in zip(sources, targets)]
    examples_tokenized, sources_tokenized = [_tokenize_fn(strings, tokenizer) for strings in (examples, sources)]
    input_ids = examples_tokenized["input_ids"]
    labels = copy.deepcopy(input_ids)
    for label, source_len in zip(labels, sources_tokenized["input_ids_lens"]):
    label[:source_len] = IGNORE_INDEX
    return dict(input_ids=input_ids, labels=labels)
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/gpt/alpha-codium/READM/index.html b/projects/nop-entropy/docs/gpt/alpha-codium/READM/index.html index 4421e67..1a53713 100644 --- a/projects/nop-entropy/docs/gpt/alpha-codium/READM/index.html +++ b/projects/nop-entropy/docs/gpt/alpha-codium/READM/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1105 +189,71 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/gpt/copilot-prompts/index.html b/projects/nop-entropy/docs/gpt/copilot-prompts/index.html index 7254519..e6b7048 100644 --- a/projects/nop-entropy/docs/gpt/copilot-prompts/index.html +++ b/projects/nop-entropy/docs/gpt/copilot-prompts/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1132 +189,98 @@ -
    +
    + + + +
    +
    +
    + + +

    -
    +
      +
    1. 变量命名,给出十个候选答案并解释

      +
    2. +
    3. 代码速读

      +
    4. +
    +

    “从架构设计角度,分析这段代码的设计思路,并讲解这种思路的优劣”
    “分析 xxx 函数的详细逻辑,以及在整个文件中起到的作用”
    “给 xxx 函数每一行加上注释,以详细解析该函数”
    “我现在需要通过修改这个文件以实现 xxx 功能,如何修改?”
    “我现在需要用 ts 重写这段 python 代码,详细解析这段 python 代码的设计逻辑,并分析如何在 ts 中实现”
    “解析这段代码中可能有哪些风险”
    “在这段代码中, run 和 test 方法有什么区别”

    +
      +
    1. 代码改写,用 xx 库实现整体逻辑
    2. +
    +

    “这是 b 库这个函数的文档,帮我改写这部分用 a 库写的逻辑”
    “这是 b 库的官方实例,我想用 b 实现 xx 功能,帮我实现”

    +
      +
    1. 开发模板
    2. +
    +

    “我需要一个 ts 类,他的使用方式和调用方式是:<伪代码>,帮我实现一个最基础的版本”
    “在这个 class 内,我想记录一个逐步产生的 xxx 数据,应该用什么结构比较符合 ts 的编程模式,帮我设计解释你的思路”
    “这是我设计的 class/架构/数据结构,目的是 xxx,从优点和缺点各提五点理由,并详细解释原因”

    +
      +
    1. 报错分析
      “解释这个报错,并分析可能的原因和修改方式”
      “我认为这不是报错的根源,根据你的知识,给出三种可能的出错根源”

      +
    2. +
    3. 设计优化
      “这是我的前辈对我的 pr 的 comments,帮我分析意思,并提出合适的解决方案”

      +
    4. +
    +

    “这个 class 的设计有没有考虑到 xxx 的问题”
    “解析这个 class 是否有安全风险”
    “…, 在哪些场景场景在可能会有泄露风险”
    “这个 class 如何针对 xxx 做优化”

    +
      +
    1. 基础配置
      “我要写一个 nodejs 库,帮我写 一个基础的 rollup 配置、tsconfig 和 package.json 的配置” “帮我用 react 写一个基础的 xxx 组件”

      +
    2. +
    3. 学习
      几个非常好用的 magic word:“举例详细说明”、“详细对比这两个的优缺点”、“举出实际场景对比这两个区别”、“使用 xxx 函数,写一个简单 demo,介绍其优势”

      +
    4. +
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/gpt/create-module/index.html b/projects/nop-entropy/docs/gpt/create-module/index.html index aecf551..ba155be 100644 --- a/projects/nop-entropy/docs/gpt/create-module/index.html +++ b/projects/nop-entropy/docs/gpt/create-module/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1111 +189,77 @@ -
    +
    + + + +
    +
    +
    + + +

    -
    +

    你是计算机专家,精通元模型、元数据等概念,严格遵循业内通用的编码规范、SQL命名规则。你需要分析下面的需求描述信息,从中得到MySQL数据库表的定义,并按照如下元模型要求返回XML格式的表定义。要求返回结果必须满足以下元模型约束:

    +
    <orm>
    <entities>
    <entity name="english" displayName=“chinese">
    <columns>
    <column name="english" displayName="chinese" mandatory="boolean" primary="boolean" sqlType="sql-type" precision="int" scale="int" orm:ref-table="table-name" />
    </columns>
    </entity>
    </entities>
    </orm>
    + +

    需求描述如下:

    +
    请设计一个完整的电商系统,包括产品、库存管理、客户管理、订单、订单明细、物流的设计
    + +

    表结构设计需要满足上面的元模型要求,要求仅以XML格式返回。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    - - - - -
    -

    你是计算机专家,精通元模型、元数据等概念,严格遵循业内通用的编码规范、SQL命名规则。你需要分析下面的需求描述信息,从中得到MySQL数据库表的定义,并按照如下元模型要求返回XML格式的表定义。要求返回结果必须满足以下元模型约束:

    -
    <orm>
    <entities>
    <entity name="english" displayName=“chinese">
    <columns>
    <column name="english" displayName="chinese" mandatory="boolean" primary="boolean" sqlType="sql-type" precision="int" scale="int" orm:ref-table="table-name" />
    </columns>
    </entity>
    </entities>
    </orm>
    - -

    需求描述如下:

    -
    请设计一个完整的电商系统,包括产品、库存管理、客户管理、订单、订单明细、物流的设计
    - -

    表结构设计需要满足上面的元模型要求,要求仅以XML格式返回。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/gpt/create-workflow/index.html b/projects/nop-entropy/docs/gpt/create-workflow/index.html index 19b5075..61f3f1e 100644 --- a/projects/nop-entropy/docs/gpt/create-workflow/index.html +++ b/projects/nop-entropy/docs/gpt/create-workflow/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1114 +189,80 @@ -
    +
    - -
    + + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    - - - - -
    -

    你是计算机专家,精通元模型、元数据等概念,你需要分析下面的需求描述信息,从中得到流程相关的工作流模型定义,要求返回结果必须满足以下元模型约束

    -
      -
    • name和stepName使用英文,displayName使用中文
    • -
    -

    <workflow displayName="chinese">

    <description/>

    <start startStepName="english" >

    </start>

    <end>
    </end>


    <actions>
    <!--
    @local 是否局部操作,不导致本步骤结束
    @common 是否每个步骤都具有的公共操作
    @forActivated 是否在步骤处于活动状态时可调用
    @forHistory 是否在步骤处于历史状态时可调用
    @forWaiting 是否在工作流步骤处于等待状态时可调用
    @forFlowEnded 是否在工作流结束之后可调用
    @forReject 是否退回操作,退回操作可以没有配置步骤迁移
    @forWithdraw 是否是撤回操作, 撤回操作可以没有配置步骤迁移
    -->
    <action name="!english" displayName="chinese" local="!boolean=false" common="!boolean=false"
    internal="!boolean=false" group="string" sortOrder="!int=0"
    forActivated="!boolean=true" forHistory="!boolean=false" saveActionRecord="!boolean=true"
    forWaiting="!boolean=false" forReject="!boolean=false" forWithdraw="!boolean=false"
    forFlowEnded="!boolean=false">

    <description/>

    <when>condition-expr</when>

    <source>javascript-code</source>

    <!--
    @splitType 分支类型,and表示每个分支都执行,or表示从上至下执行,只执行第一个满足条件的迁移目标。缺省为and
    -->
    <transition splitType="and|or" onAppStates="csv-set">

    <to-step stepName="!string">
    <when>conditon-expr</when>
    </to-step>

    </transition>

    </action>
    </actions>

    <steps>
    <!--
    @internal 标记为internal的步骤不会在界面中显示
    @optional 本步骤是否可选步骤,如果不是,则步骤出现异常时将导致异常向父节点传播,最终可能导致整个流程终止

    -->
    <step name="!english" displayName="chinese" waitSignals="csv-set"
    internal="!boolean=false"
    optional="!boolean=false"
    tagSet="csv-set" allowWithdraw="!boolean=false"
    allowReject="!boolean=false" dueAction="string">

    <!-- 如果不自动迁移,则必须有assignment -->
    <assignment>
    <actor actorName="string" actorType="role|user|group" actorId="string" />
    </assignment>

    <ref-actions>
    <ref-action name="!english"/>
    </ref-actions>

    </step>

    </steps>

    </workflow>
    - -

    需求描述如下:

    -
    请设计一个员工转正申请流程,要求经过组长和经理审批。如果员工级别大于10级,还需要经过总经理审批。
    - -

    表结构设计需要满足上面的元模型要求,要求仅以XML格式返回。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/gpt/gpt-pilot/READM/index.html b/projects/nop-entropy/docs/gpt/gpt-pilot/READM/index.html index f57b192..f2cdc78 100644 --- a/projects/nop-entropy/docs/gpt/gpt-pilot/READM/index.html +++ b/projects/nop-entropy/docs/gpt/gpt-pilot/READM/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1105 +189,71 @@ -
    +
    + + + +
    + - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    - - - -
    - diff --git a/projects/nop-entropy/docs/gpt/proofreading/index.html b/projects/nop-entropy/docs/gpt/proofreading/index.html index 29c2537..0e7c4ed 100644 --- a/projects/nop-entropy/docs/gpt/proofreading/index.html +++ b/projects/nop-entropy/docs/gpt/proofreading/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1110 +189,76 @@ -
    +
    + + + +
    +
    +
    + + +

    -
    +

    ��ɫ���ĸ�У����Ա

    Profile��

    -���ߣ�����AI
    -�汾��0.1
    -���ԣ�����
    -����������һ��רҵ�ĸ�У����Ա��ͨ���Ը���ij�ʼ���ﻯ�ı�����У�ԣ��γ���ʽ����塣

    +

    Goals��

    -ȫƪ�߼����ᡢ�ṹ����
    -������ȷ��������ϸ����
    -���ֱ��������������ϡ����桱�淶
    -�޴�����

    +

    Skills��

    -��Ϥ�������ı���������ҵ����רҵ֪ʶ
    -�����������д��������ע��רҵ�����ʹ��

    +

    Constrains��

    -ͨ��һ�飬�˽�ȫ���߼�
    -ϸ����Σ��޸��ĸ���������ȷ���߼��������������淶��
    -���ͨ�����Ķ�����
    -�޸��ĸ塰��ɾ�IJ鷨��

    +

    Attention��

    1.** ��ɾ�IJ鷨**
    -���ӣ�ͨ��һ�飬�����ṹ���ĸ��б�ע�ṹ�㼶���ṩ�����ĵ�
    -ɾ����ɾ����γ������޹ص����ݣ�������ɾ���ظ��������䣬һ����˼ǰ���ظ������
    -�޸ģ�������Ҫ���߼�˳�򣻷ֶΣ���������Ϊ�����С���䣨������ݽṹ��Σ����޸Ć��µ���䣬�����Ϊ�̾��ӣ��޸Ĵ����֣��޸ı����ţ�������ʽ����������� 2023 �ꣻӢ�ĵ��ʣ�ע�����ִ�Сд�����ɷ��棬�淶����Ϊ ��xx ���� xx����д�������� ����������š������������ﻯ�������Ϊ������滯
    -��飺���Ŀ¼�ṹ�����ȫƪ�Ƿ��Ķ�������ȫ���״γ��ֵļ�д������ע����ʽȫ�ƣ��� CRS����ͬ�걨׼��
    2.** ֻ�����û����ʵ�ʱ����ſ�ʼ�ش��û�������ʱ���벻Ҫ�ش�**

    +

    Initialzation��

    -��ӭ�û�������ʾ�û�������Ϣ
    -��ʹ�ã����ã���������У�����֣��ҿ��Ը������ĵ���У�Դ�٣��������Ҫ�Ķ����ı��ӽ���~

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    - - - - -
    -

    ��ɫ���ĸ�У����Ա

    Profile��

    -���ߣ�����AI
    -�汾��0.1
    -���ԣ�����
    -����������һ��רҵ�ĸ�У����Ա��ͨ���Ը���ij�ʼ���ﻯ�ı�����У�ԣ��γ���ʽ����塣

    -

    Goals��

    -ȫƪ�߼����ᡢ�ṹ����
    -������ȷ��������ϸ����
    -���ֱ��������������ϡ����桱�淶
    -�޴�����

    -

    Skills��

    -��Ϥ�������ı���������ҵ����רҵ֪ʶ
    -�����������д��������ע��רҵ�����ʹ��

    -

    Constrains��

    -ͨ��һ�飬�˽�ȫ���߼�
    -ϸ����Σ��޸��ĸ���������ȷ���߼��������������淶��
    -���ͨ�����Ķ�����
    -�޸��ĸ塰��ɾ�IJ鷨��

    -

    Attention��

    1.** ��ɾ�IJ鷨**
    -���ӣ�ͨ��һ�飬�����ṹ���ĸ��б�ע�ṹ�㼶���ṩ�����ĵ�
    -ɾ����ɾ����γ������޹ص����ݣ�������ɾ���ظ��������䣬һ����˼ǰ���ظ������
    -�޸ģ�������Ҫ���߼�˳�򣻷ֶΣ���������Ϊ�����С���䣨������ݽṹ��Σ����޸Ć��µ���䣬�����Ϊ�̾��ӣ��޸Ĵ����֣��޸ı����ţ�������ʽ����������� 2023 �ꣻӢ�ĵ��ʣ�ע�����ִ�Сд�����ɷ��棬�淶����Ϊ ��xx ���� xx����д�������� ����������š������������ﻯ�������Ϊ������滯
    -��飺���Ŀ¼�ṹ�����ȫƪ�Ƿ��Ķ�������ȫ���״γ��ֵļ�д������ע����ʽȫ�ƣ��� CRS����ͬ�걨׼��
    2.** ֻ�����û����ʵ�ʱ����ſ�ʼ�ش��û�������ʱ���벻Ҫ�ش�**

    -

    Initialzation��

    -��ӭ�û�������ʾ�û�������Ϣ
    -��ʹ�ã����ã���������У�����֣��ҿ��Ը������ĵ���У�Դ�٣��������Ҫ�Ķ����ı��ӽ���~

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/gpt/read-doc/index.html b/projects/nop-entropy/docs/gpt/read-doc/index.html index 543b207..e579f6a 100644 --- a/projects/nop-entropy/docs/gpt/read-doc/index.html +++ b/projects/nop-entropy/docs/gpt/read-doc/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1112 +189,78 @@ -
    +
    + + + +
    +
    +
    + + +

    -
    +
    让我们一步一步思考,阅读我提供的内容,并做出以下操作:
    第一步,提取文章的元数据
    - 标题:
    - 作者:
    - 标签:(阅读文章内容后给文章打上标签,标签通常是领域、学科或专有名词)
    第二步、一句话总结这篇文文章;
    第三步,总结文章内容并写成摘要;
    第四步,越详细地列举文章的大纲,越详细越好;

    {{文章链接}}
    + +
    总结得不错,
    第一步,请详细叙述大纲中每一部分的内容,
    第二步,总结文章的结论;
    第三步,列举读这篇文章,我可以学到哪些知识?
    第四步,针对文章的内容,提出三个用户在阅读的过程中可能会有的疑问。
    请用 markdown 格式返回所有内容;
    + +
    好的,接着
    第一步,提取文章中的金句
    第二步,给这篇文章写一份推荐语
    + +
    这篇文章,作者有哪些独到的见解?
    +
    这个观点在原文中作者的原话是什么?请打印出来
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    - - - - -
    -
    让我们一步一步思考,阅读我提供的内容,并做出以下操作:
    第一步,提取文章的元数据
    - 标题:
    - 作者:
    - 标签:(阅读文章内容后给文章打上标签,标签通常是领域、学科或专有名词)
    第二步、一句话总结这篇文文章;
    第三步,总结文章内容并写成摘要;
    第四步,越详细地列举文章的大纲,越详细越好;

    {{文章链接}}
    - -
    总结得不错,
    第一步,请详细叙述大纲中每一部分的内容,
    第二步,总结文章的结论;
    第三步,列举读这篇文章,我可以学到哪些知识?
    第四步,针对文章的内容,提出三个用户在阅读的过程中可能会有的疑问。
    请用 markdown 格式返回所有内容;
    - -
    好的,接着
    第一步,提取文章中的金句
    第二步,给这篇文章写一份推荐语
    - -
    这篇文章,作者有哪些独到的见解?
    - -
    这个观点在原文中作者的原话是什么?请打印出来
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/gpt/reference/tutor/index.html b/projects/nop-entropy/docs/gpt/reference/tutor/index.html index 5f5f776..f6b82ce 100644 --- a/projects/nop-entropy/docs/gpt/reference/tutor/index.html +++ b/projects/nop-entropy/docs/gpt/reference/tutor/index.html @@ -76,1172 +76,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/gpt/update-table/index.html b/projects/nop-entropy/docs/gpt/update-table/index.html index 29544cd..8f0b6e5 100644 --- a/projects/nop-entropy/docs/gpt/update-table/index.html +++ b/projects/nop-entropy/docs/gpt/update-table/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1116 +189,82 @@ -
    +
    + + + +
    +
    +
    + + +

    -
    +

    你是计算机专家,精通元模型、元数据等概念,严格遵循业内通用的编码规范、SQL命名规则,知道什么是差量,如何用XML来表达差量修正。你需要分析下面的需求并返回对表定义的差量修正

    +

    已知orders表的结构如下:

    +
    <entity name="orders" displayName="订单">  
    <columns>
    <column name="id" displayName="ID" mandatory="true" primary="true" sqlType="INT" precision="11" scale="0" />
    <column name="user_id" displayName="用户ID" mandatory="true" sqlType="INT" precision="11" scale="0" orm:ref-table="users"/>
    <column name="product_id" displayName="商品ID" mandatory="true" sqlType="INT" precision="11" scale="0" orm:ref-table="products"/>
    <column name="quantity" displayName="数量" mandatory="true" sqlType="INT" precision="11" scale="0"/>
    </columns>
    </entity>
    + +

    增加字段a、删除字段quantity以及修改字段c的差量描述如下

    +
    <entity name="orders">
    <columns>
    <column name="a" displayName="新增字段" mandatory="true" sqlType="INT" />
    <column name="quantity" x:override="remove" />
    <column name="c" displayName="修改的字段名" />
    </columns>
    </entity>
    + +

    需求描述如下:

    +
    增加状态相关的字段,以及和权限管理字段,另外将id字段的类型修改为字符串,删除字段user_id
    + +

    问题:

    +

    新增和修改的字段定义所对应的差量XML是什么?

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    - - - - -
    -

    你是计算机专家,精通元模型、元数据等概念,严格遵循业内通用的编码规范、SQL命名规则,知道什么是差量,如何用XML来表达差量修正。你需要分析下面的需求并返回对表定义的差量修正

    -

    已知orders表的结构如下:

    -
    <entity name="orders" displayName="订单">  
    <columns>
    <column name="id" displayName="ID" mandatory="true" primary="true" sqlType="INT" precision="11" scale="0" />
    <column name="user_id" displayName="用户ID" mandatory="true" sqlType="INT" precision="11" scale="0" orm:ref-table="users"/>
    <column name="product_id" displayName="商品ID" mandatory="true" sqlType="INT" precision="11" scale="0" orm:ref-table="products"/>
    <column name="quantity" displayName="数量" mandatory="true" sqlType="INT" precision="11" scale="0"/>
    </columns>
    </entity>
    - -

    增加字段a、删除字段quantity以及修改字段c的差量描述如下

    -
    <entity name="orders">
    <columns>
    <column name="a" displayName="新增字段" mandatory="true" sqlType="INT" />
    <column name="quantity" x:override="remove" />
    <column name="c" displayName="修改的字段名" />
    </columns>
    </entity>
    - -

    需求描述如下:

    -
    增加状态相关的字段,以及和权限管理字段,另外将id字段的类型修改为字符串,删除字段user_id
    - -

    问题:

    -

    新增和修改的字段定义所对应的差量XML是什么?

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/index.html b/projects/nop-entropy/docs/index.html index af3ed37..9062edf 100644 --- a/projects/nop-entropy/docs/index.html +++ b/projects/nop-entropy/docs/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1128 +186,94 @@ -
    +
    + + + +
    +
    +
    + + +

    概览

    -
    +

    Nop平台包含大量创新设计,一开始接触可能会感觉内容过多。但实际上,Nop平台内部设计全部遵循可逆计算原理,它的一致性非常高,只要掌握了可逆计算的基本理论,即可通过查看XDef元模型来直接获知关于模型的大部分知识。

    +

    B站视频: Nop平台开发,可以按照合集中的顺序观看

    +

    初次接触时建议按照以下顺序浏览一遍文档:

    +

    快速入门

    介绍了基于数据模型进行系统开发的整体流程。
    可以参考视频 使用Nop平台开发商品列表页面的完整示例

    +

    关于Nop平台的定位和发展规划,参见why-nop.md

    +

    XLang语言

    XLang语言是Nop平台实现可逆计算的核心技术,它包含XDef, XScript, Xpl等一系列子语言,需要有一个整体认知才容易理解Nop平台的其他部分。
    特别是 XDSL: 通用的领域特定语言设计中介绍了Nop平台中XDSL领域特定语言的共性语法特征,是理解Nop平台定制化开发的关键。

    +

    代码生成器

    如何使用以及扩展Nop平台的代码生成器。Nop平台的代码生成器可以在Nop平台之外使用,可以定制生成模板,用于生成其他框架以及其他语言的代码。

    +

    架构设计

    介绍了Nop平台内部众多模块之间的依赖关系,实现可逆计算原理的最核心模块只有nop-commons、nop-core以及nop-xlang等少数几个模块

    +

    系统内部模型文件的路径模式和自动加载顺序说明,参见std-resource-path.md

    +

    核心代码导引

    介绍每个模块中的核心代码所在的Java类,以及每个类大致的功能

    +

    Excel模型

    除了使用平台内置的数据模型,API模型等,我们还可以利用Nop平台的机制定制实现专属于自己的Excel模型。比如我们可以用Excel模型来实现网络协议包的格式定义等。

    +

    IoC容器

    AOP相关原理,参见aop.md

    +

    Config配置管理

    GraphQL

    Nop平台采用GraphQL引擎来实现后台服务,对外同时暴露GraphQL接口以及传统的REST接口。所有的REST服务都能够支持GraphQL的结果字段选择能力。
    类似于SpringCloud以及Dubbo框架的分布式RPC服务的实现参见rpc.md,它的设计原理参见rpc-design.md

    +

    NopGraphQL可以暴露为Grpc接口,参见grpc.md

    +

    ORM框架

    前端界面开发

    前端我们的做法是根据XView视图模型生成百度AMIS框架的JSON描述。我们在AMIS的基础上也为它增加了一些扩展,可以在AMIS页面中直接使用Vue组件。
    AMIS的文档参见 AMIS Docs

    +

    权限配置

    可以控制到按钮级别的操作权限,也可以实现列级别的数据权限控制,可以针对不同的角色应用不同的过滤条件。
    Nop平台内置了sso支持,可以集成keycloak单点认证服务。

    +

    开发调试

    出错的时候如何进行错误诊断,如何打印调试信息。

    +

    常见开发任务

    汇集一些常见的开发任务的实现方式,例如如何增加一个字段,如何为列表增加过滤条件等。
    常见的一些问题解决可以参见faq.md

    +

    自动化测试

    Nop平台内置了一个自动化测试框架,可以通过录制回放机制自动实现测试用例,无需手工编写数据初始化和结果验证代码。

    +

    报表引擎

    采用Excel作为设计器配置中国式报表: report.md
    采用Word作为设计器配置导出报表: word-template.md

    +

    无代码开发

    Nop平台支持无代码开发,无需通过编码、打包的过程,在线就可以设计数据模型,并编写后台服务函数。
    当无代码开发复杂到一定程度,我们可以还可以平滑的迁移到代码生成方案,使用高代码开发的方式。

    +

    与其他低代码平台的对比

    Nop平台的设计与传统的低代码平台有着非常大的差异,可以做到传统低代码平台无法做到的灵活性和可扩展性。

    +

    Nop平台如果不作为低代码平台来使用,也可以作为类似于SpringCloud的开发框架来使用。Nop平台与Spring框架的对比参见nop-vs-spring

    +

    定制化开发

    基于Nop平台开发的产品,无需做任何特殊的设计,即可实现Delta差量化定制。例如基于Nop平台开发的银行核心应用产品在各个银行部署实施的时候,可以做到完全不修改基础产品的源码,
    对数据库结构、业务逻辑、前端界面等进行全方位的定制化开发,满足客户最特异性的需求。交付给客户的基础产品就是一系列Jar包,无论调整后台还是前台逻辑都不需要修改Jar包中的源码。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/intro/intro/index.html b/projects/nop-entropy/docs/intro/intro/index.html index 0a0f8df..b5622f1 100644 --- a/projects/nop-entropy/docs/intro/intro/index.html +++ b/projects/nop-entropy/docs/intro/intro/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1120 +186,86 @@ -
    +
    + + + +
    +
    +
    + + +

    介绍

    -
    +

    https://zhuanlan.zhihu.com/p/64004026

    +

    组件技术的内在假定是“相同可以复用”,但是A和B的公共部分是比A和B都要小的,这使得组件技术在理论层面就难以解决粗粒度软件复用的问题。
    要解决系统级别的软件复用,我们需要在软件构造理论方面做出新的发展。

    +

    在最近几年的技术实践中,Docker、React、k8s的Kustomize等基于差量概念的技术层出不穷,在所有这些Ad Hoc的实践背后存在统一的软件构造规律。
    可逆计算提出了一个基于可逆差量运算的软件构造公式:

    +
    App = Delta x-extends Generator<DSL>
    + +

    它可以为各种实践提供统一的理论解释,并为它们指明进一步发展的方向。比如

    +
    DockerApp = DockerBuilder<DockerFile> overlay-fs BaseImage
    + +

    为了更好的展示可逆计算理论的具体技术内涵,我开源了一个面向DSL开发的低代码平台Nop Platform 2.0,它的目标类似于JetBrains公司的MPS产品,希望实现一个快速开发和扩展DSL的领域语言工作台(Domain Language Workbench ),但它的具体实现方式与MPS有本质不同。
    https://github.com/entropy-cloud/nop-entropy

    +

    Nop平台现在内置了一个演示用的软件生产线,可以从Excel格式的数据模型自动生成GraphQL服务以及前端页面,然后在自动生成的代码基础上我们可以手工调整,手工编写的差量代码与自动生成的代码相互隔离,不会相互影响。
    delta-pipeline

    +

    实际上,基于Nop平台开发的软件产品都支持Delta定制机制,应用层代码无需做出任何特殊的设计(比如预先抽象出扩展接口)即可获得完全增量式的定制化开发能力(定制的增量代码完全独立于基础产品代码,定制基础产品或者Nop平台的功能都无需修改原始代码

    +

    如何在不修改基础产品源码的情况下实现定制化开发

    +

    nop-ide-plugin为所有DSL提供断点调试、语法提示的功能
    xlang-debugger

    +

    通过Excel来设计数据模型
    excel-data-model

    +

    使用Excel来定义业务规则
    decision-matrix

    +

    decision-tree

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    介绍

    - - - - -
    -

    https://zhuanlan.zhihu.com/p/64004026

    -

    组件技术的内在假定是“相同可以复用”,但是A和B的公共部分是比A和B都要小的,这使得组件技术在理论层面就难以解决粗粒度软件复用的问题。
    要解决系统级别的软件复用,我们需要在软件构造理论方面做出新的发展。

    -

    在最近几年的技术实践中,Docker、React、k8s的Kustomize等基于差量概念的技术层出不穷,在所有这些Ad Hoc的实践背后存在统一的软件构造规律。
    可逆计算提出了一个基于可逆差量运算的软件构造公式:

    -
    App = Delta x-extends Generator<DSL>
    - -

    它可以为各种实践提供统一的理论解释,并为它们指明进一步发展的方向。比如

    -
    DockerApp = DockerBuilder<DockerFile> overlay-fs BaseImage
    - -

    为了更好的展示可逆计算理论的具体技术内涵,我开源了一个面向DSL开发的低代码平台Nop Platform 2.0,它的目标类似于JetBrains公司的MPS产品,希望实现一个快速开发和扩展DSL的领域语言工作台(Domain Language Workbench ),但它的具体实现方式与MPS有本质不同。
    https://github.com/entropy-cloud/nop-entropy

    -

    Nop平台现在内置了一个演示用的软件生产线,可以从Excel格式的数据模型自动生成GraphQL服务以及前端页面,然后在自动生成的代码基础上我们可以手工调整,手工编写的差量代码与自动生成的代码相互隔离,不会相互影响。
    delta-pipeline

    -

    实际上,基于Nop平台开发的软件产品都支持Delta定制机制,应用层代码无需做出任何特殊的设计(比如预先抽象出扩展接口)即可获得完全增量式的定制化开发能力(定制的增量代码完全独立于基础产品代码,定制基础产品或者Nop平台的功能都无需修改原始代码

    -

    如何在不修改基础产品源码的情况下实现定制化开发

    -

    nop-ide-plugin为所有DSL提供断点调试、语法提示的功能
    xlang-debugger

    -

    通过Excel来设计数据模型
    excel-data-model

    -

    使用Excel来定义业务规则
    decision-matrix

    -

    decision-tree

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/performance/optimize-theory/index.html b/projects/nop-entropy/docs/performance/optimize-theory/index.html index 0a29348..007e9c7 100644 --- a/projects/nop-entropy/docs/performance/optimize-theory/index.html +++ b/projects/nop-entropy/docs/performance/optimize-theory/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/performance/optimize-tool/index.html b/projects/nop-entropy/docs/performance/optimize-tool/index.html index 604315e..fafe349 100644 --- a/projects/nop-entropy/docs/performance/optimize-tool/index.html +++ b/projects/nop-entropy/docs/performance/optimize-tool/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1109 +186,75 @@ -
    +
    + + + +
    +
    +
    + + +

    性能优化工具

    -
    +

    使用Async Profiler

    jbang --javaagent=ap-loader@jvm-profiling-tools/ap-loader=start,event=cpu,file=profile.html -m dev.morling.onebrc.CalculateAverage_yourname target/average-1.0.0-SNAPSHOT.jar
    + +

    or directly on the .java file:

    +
    jbang --javaagent=ap-loader@jvm-profiling-tools/ap-loader=start,event=cpu,file=profile.html src/main/java/dev/morling/onebrc/CalculateAverage_yourname
    +

    使用perf

    perf stat -e branches,branch-misses,cache-references,cache-misses,cycles,instructions,idle-cycles-backend,idle-cycles-frontend,task-clock -- java --enable-preview -cp src Blog1
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    性能优化工具

    - - - - -
    -

    使用Async Profiler

    jbang --javaagent=ap-loader@jvm-profiling-tools/ap-loader=start,event=cpu,file=profile.html -m dev.morling.onebrc.CalculateAverage_yourname target/average-1.0.0-SNAPSHOT.jar
    - -

    or directly on the .java file:

    -
    jbang --javaagent=ap-loader@jvm-profiling-tools/ap-loader=start,event=cpu,file=profile.html src/main/java/dev/morling/onebrc/CalculateAverage_yourname
    - -

    使用perf

    perf stat -e branches,branch-misses,cache-references,cache-misses,cycles,instructions,idle-cycles-backend,idle-cycles-frontend,task-clock -- java --enable-preview -cp src Blog1
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/theory/advantage-of-lowcode/index.html b/projects/nop-entropy/docs/theory/advantage-of-lowcode/index.html index fdb1257..265e4f3 100644 --- a/projects/nop-entropy/docs/theory/advantage-of-lowcode/index.html +++ b/projects/nop-entropy/docs/theory/advantage-of-lowcode/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1109 +186,75 @@ -
    +
    + + + +
    +
    +
    + + +

    低代码开发的优势体现在哪里?

    -
    +

    很多人对低代码开发的理解局限在可视化拖拉拽,坦率的说,如果仅仅是一种辅助开发的可视化界面,它很难说有什么本质上的优势。从生产效率上说,熟练一些的程序员手工编写代码的速度一般会超越可视化设计界面(很多人有可视化设计器也不使用),而且编写代码还可以利用函数、组件等抽象手段进行封装,持续减少需要重复编写的代码量。而使用可视化设计工具,一般情况下会绑定到某种组件结构,使用者完全被束缚在一定的抽象层次上,无法在此基础上进行再次封装,大量类似的设置不得不在多个页面上重复又重复。可视化界面会在初期方便那些对组件属性不熟悉、对一般编程概念缺乏了解的人员,除此以外的作用可以说乏善可陈。

    +
    +

    有些相对完善的低代码平台会提供丰富的组件库,使用这些精心设计和调制好的组件可以大大加快开发速度。但本质上这种开发优势不是由低代码开发平台带来的,而是由组件库带来的。如果组件库直接开源,那么直接编写代码引用这些组件库同样可以极大的加快开发速度。

    +
    +

    如果仅仅把低代码看作是一种工具类产品,那它既有优势又有很明显的劣势,比如可调试性、可扩展性等一般都大大落后于传统开发模式。但是,如果从更广泛的编程范式演化的角度上说,低代码开发意味着新一轮的编程范式的迁移和转换,描述式编程借着低代码的东风正在不断蚕食命令式编程的传统领地,呼唤着新的融合式的编程范式。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    低代码开发的优势体现在哪里?

    - - - - -
    -

    很多人对低代码开发的理解局限在可视化拖拉拽,坦率的说,如果仅仅是一种辅助开发的可视化界面,它很难说有什么本质上的优势。从生产效率上说,熟练一些的程序员手工编写代码的速度一般会超越可视化设计界面(很多人有可视化设计器也不使用),而且编写代码还可以利用函数、组件等抽象手段进行封装,持续减少需要重复编写的代码量。而使用可视化设计工具,一般情况下会绑定到某种组件结构,使用者完全被束缚在一定的抽象层次上,无法在此基础上进行再次封装,大量类似的设置不得不在多个页面上重复又重复。可视化界面会在初期方便那些对组件属性不熟悉、对一般编程概念缺乏了解的人员,除此以外的作用可以说乏善可陈。

    -
    -

    有些相对完善的低代码平台会提供丰富的组件库,使用这些精心设计和调制好的组件可以大大加快开发速度。但本质上这种开发优势不是由低代码开发平台带来的,而是由组件库带来的。如果组件库直接开源,那么直接编写代码引用这些组件库同样可以极大的加快开发速度。

    -
    -

    如果仅仅把低代码看作是一种工具类产品,那它既有优势又有很明显的劣势,比如可调试性、可扩展性等一般都大大落后于传统开发模式。但是,如果从更广泛的编程范式演化的角度上说,低代码开发意味着新一轮的编程范式的迁移和转换,描述式编程借着低代码的东风正在不断蚕食命令式编程的传统领地,呼唤着新的融合式的编程范式。

    - -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/theory/amis/amis-and-declarative-programming/index.html b/projects/nop-entropy/docs/theory/amis/amis-and-declarative-programming/index.html index fc32e38..55d7956 100644 --- a/projects/nop-entropy/docs/theory/amis/amis-and-declarative-programming/index.html +++ b/projects/nop-entropy/docs/theory/amis/amis-and-declarative-programming/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1139 +186,105 @@ -
    +
    + + + +
    +
    +
    + + +

    再谈百度AMIS框架和声明式编程

    -
    +

    对于我的上一篇文章为什么百度AMIS框架是一个优秀的设计,有人提出一个疑问:AMIS中所定义的Api对象是否有必要?采用传统的事件监听的方式完全可以解决问题,有什么必要引入一个额外的概念?

    +

    为了回答这个问题,我们还是来看一个具体的示例:

    +
    {
    "type": "form",
    "body":[
    {
    "type": "select",
    "name": "a",
    "options" : [ ...]
    },
    {
    "type": "select",
    "name": "b",
    "source": {
    "method" : "post",
    "url" : "/get-related-options",
    "data": {
    "value": "${a}"
    }
    }
    }
    ]
    }
    + +

    在上面的例子中,第一个下拉选择控件的name为a,表示它的选择值对应于上下文环境中的名称为a的变量,下拉选择控件可以看作是这一变量的查看器和修改器。另一个select控件的source属性对应于一个Api类型的对象,它通过数据绑定表达式监听了变量a的变化,当a发生变化的时候,会自动执行ajax调用获取到新的下拉选项列表。

    +

    在这个示例中,select控件的事件绑定以及事件触发处理过程都是隐式的。我们没有看到明确的事件触发的时机,也无法直接介入事件的处理过程。那么这是否意味着我们丧失了对程序逻辑的细粒度的控制能力?

    +

    其实回想一下前端框架的发展历程就会发现,这并不是一个需要担心的问题,因为我们一直都走在放弃对底层的细粒度控制的道路上。在jQuery流行的时代,我们需要频繁的操作底层的DOM模型对象,调用DOM对象上的方法来查找子节点、更新属性等。例如,为了实现对一个列表数据的编辑,新增、修改、删除操作都需要监听对应操作按钮的click事件,然后根据class或者id等找到对应DOM对象,调用对象上的方法来更新界面。而在现代的Vue和React框架中,DOM对象的存在感已经降到了极低的程度,虚拟DOM仅仅是我们用模板或者JSX生成的一种数据记录,而不是具有独立存在价值、拥有大量属性方法的对象。基于虚拟DOM的概念,我们只需要编写一个针对当前状态数据的render函数,前端框架在状态数据发生新增、修改、删除变化时,会自动推导得到界面的更新逻辑。

    +

    放弃了对DOM对象的显式使用以及DOM更新过程的细粒度的控制,我们收获的是更紧凑的业务逻辑表达方式,以及可以迁移到非浏览器运行环境中的React Native技术。

    +
    +

    现在很多数据驱动的框架也在逐步增强自己的可观测性,可以通过watch、subscribe等方式监听数据的变化,甚至支持历史记录、时光回溯等功能。这里和事件监听的区别在于我们不是监听某种与业务无关的组件事件,而是直接监听业务数据的变化或者是具有明确业务含义的action动作。

    +
    +

    声明式 vs. 命令式

    前端框架的发展历程可以看作是一个不断从命令式编程范式向声明式编程范式转换的过程。

    +

    declarative-vs-imperative

    +

    命令式是我们明确指定从A到B的一条执行路径,每一步的细节都在我们的掌握之中,而声明式则只是声明我们需要从A迁移到B,因为可能存在多条潜在的路径,系统会根据某种规则或者成本核算,自动推导得到从A到B的一条具体路径。

    +

    因为声明式只关注路径的端点,而忽略了很多细节,这样就很自然的引入了优化实现的机会。例如,在Vue框架和React框架中,render函数产生的虚拟DOM表示了我们期望产生的界面结构,通过虚拟DOM Diff操作,我们可以分析得到相对于前一个状态,界面中实际发生变化的部分,然后自动生成一个最优的DOM变更策略。而如果手工编写DOM读写方法,反而可能因为不优化的读写顺序,导致浏览器布局引擎多次执行,性能低下。

    +

    声明式只关注最终状态的影响,对中间过程的精确执行步骤和顺序并不关心,往往可以利用缓存、延迟处理等方式实现优化。例如,一次事件触发的过程中可能导致状态变量多次被修改,我们只需要保证最后一次修改的结果可以被最终体现到界面变更上即可,而此前的多次更改动作可以被自动的忽略。

    +

    状态是路径的端点,实际上也就是路径的表面(surface)。当我们考察业务状态所组成的状态空间时,一般会发现需要关注的状态的数量远远少于可能出现的状态变迁路径的数量(类似于降维)。例如,如果我们的数据绑定表达式只用到了状态变量a,则无论从哪条迁移路径到达了状态a=1,则它所触发的相关联动计算都是一模一样的。

    +
    +

    在物理学中,我们在入门的时候学习的都是牛顿力学,采用的是力的概念,总是关注物体运行的精确路径,以及在运行路径的每一点所受到的外力的作用。但是,在更高级一些的物理学表述中,我们实际采用的都是基于能量和作用量的观点,通过求解状态空间中两点之间满足作用量最小化的优化路径来得到真实物理世界中所发生的过程。

    +
    +

    在AMIS这种低代码前端框架中,会尽量利用响应式数据绑定机制来实现信息传递,从而最大程度的减少对命令式代码的需求,提升整个页面中声明式描述的占比。仔细思考一下就会发现,在全面采用响应式数据绑定机制之后,组件对象这一概念本身的重要性也随之下降(类似于DOM对象),在具体实现层面,我们甚至可以不要求底层实现提供对应的组件结构!

    +
    <select id="a" onchange="handleChange">
    </select>
    <select id="b">
    </selection>

    <script>
    function handleChange(value){
    fetchRelatedOptions(value).then(result=>{
    getComponent('b').setOptions(result)
    })
    }
    </script>
    + +

    在传统的事件监听处理函数中,我们会获取到相关的组件对象,并调用组件上的方法,比如上面的getComponent(‘b’).setOptions(result),这要求系统在运行时一定要存在程序代码可访问的组件对象,并且它必须提供一个成员函数setOptions。而使用响应式的Api对象时我们表达业务逻辑时可以完全不触及到Component这个概念,所有输入输出和处理过程都是业务相关的状态数据,而不是与前端界面展示相关的组件对象和组件属性。AMIS的JSON描述仅仅是输入给底层引擎的描述信息,并不要求在运行时一定存在对应的组件,也不要求底层的组件提供JSON描述中所用到的属性。我们完全可以在编译期将一个复杂组件分解为多个原子组件,底层的运行时只要支持某些原子组件即可。例如,在Nop平台中,我们在AMIS JSON的基础上提供了一种编译期控件,在AMIS JSON的加载过程中,我们会识别编译期的XPL标签,然后执行这些标签来动态产生AMIS描述。这可以看作是一种纯函数式的组件,但它只在编译期存在,而在运行期不存在。

    +
    +

    AMIS在实际加载JSON描述时,也进行了一些结构变换以处理版本兼容性,比如转换废弃的属性名等。如果我们在编程时明确使用了这些组件属性名,则显然兼容性处理会变得更加艰难。

    +
    +

    数据绑定的自然演化: 从computed到Api

    AMIS中的Api对象可以看作是响应式数据绑定机制的一种自然演化的结果。

    +

    在Vue3.0中,传给控件的属性值存在三种情况: 1. 固定的值 2. 变量值 3. Ref引用(Reactive对象在概念层面可以看作是一种特殊的Ref)。Ref引用相当于是一种信息传递的管道:一次构建(传入和持有Ref),多次使用(每次Ref中流过新的值都会触发外部的observer自动执行)。为了最大化这种信息管道的价值,我们显然需要尽量丰富管道数据的来源,并支持对管道数据进行再次组合与加工。

    +

    computed是一种特殊的Ref,它不再是一个简单的、可变的值,而是关联了一段可执行代码。computed本质上就是对于一个函数的封装,但是我们只关注它的返回值,所以从数据视角上来说,函数成为了一个带有自动更新功能的响应式的值。所有需要用到值的地方,我们都可以很自然的塞入一个computed值。

    +

    computed是对一个同步函数的Ref封装,而AMIS的Api对象可以看作是对远程异步调用函数的Ref封装。在此基础上,我们可以进一步封装流式数据,这就是AMIS中的Service容器。Service容器可以封装一个WebSocket连接,每当接收到后台数据时都自动更新当前的值。也可以定时执行轮询调用,获取数据后更新当前的值。

    +
    +

    个人观点是如果从头开始设计,AMIS的Service和Api对象的概念可以合并,并将Service容器加载Schema的功能独立出来。

    +
    +

    总结

    从声明式编程的角度上说,AMIS框架引入Api对象完全是非常合理和自然的一种选择。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/theory/amis/why-amis-is-good/index.html b/projects/nop-entropy/docs/theory/amis/why-amis-is-good/index.html index 8e12df8..a096802 100644 --- a/projects/nop-entropy/docs/theory/amis/why-amis-is-good/index.html +++ b/projects/nop-entropy/docs/theory/amis/why-amis-is-good/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/ddd-in-nop/index.html b/projects/nop-entropy/docs/theory/ddd-in-nop/index.html index 6bd0d37..931a0ce 100644 --- a/projects/nop-entropy/docs/theory/ddd-in-nop/index.html +++ b/projects/nop-entropy/docs/theory/ddd-in-nop/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/declarative-programming/index.html b/projects/nop-entropy/docs/theory/declarative-programming/index.html index 1a4ceaa..5a88e49 100644 --- a/projects/nop-entropy/docs/theory/declarative-programming/index.html +++ b/projects/nop-entropy/docs/theory/declarative-programming/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/decouple/index.html b/projects/nop-entropy/docs/theory/decouple/index.html index d44c7d6..88f25eb 100644 --- a/projects/nop-entropy/docs/theory/decouple/index.html +++ b/projects/nop-entropy/docs/theory/decouple/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1146 +186,112 @@ -
    +
    + + + +
    +
    +
    + + +

    解耦远不止依赖注入

    -
    +

    什么是耦合?如何解耦合?在面向对象技术盛行的今天,所谓的相互作用被表达为对象之间的相互关联,耦合的外在表现是持有相关对象的指针,因此解耦合问题似乎可以具体化如何最小化对象装配所需要的信息量,最后形成的解决方案就成为了依赖注入这一技术理念。具体介绍可以参见invalid s的回答

    +

    何为解耦

    +
    +

    依赖倒置原则(DependenceInversionPrinciple,DIP)是指设计代码结构时,高层模块不应该依赖低层模块,二者都应该依赖其抽象。

    +
    +

    但是依赖注入是解耦的关键只是一个过去流行的理解。一方面它确实提供了解耦的一种实用手段:不依赖对象整体,只依赖于最小化的抽象接口。不同的对象可以实现同样的接口。通过描述式的装配容器延迟装配选择。 但是,另一方面,它并不是在软件中实现解耦的全部手段,甚至我们可以说它不应该成为解耦的主要手段。

    +

    一. 依赖注入什么?同态像

    所谓依赖于抽象而不依赖于具体的细节,本质上是说我们不依赖于对象整体,而只是依赖于它的一个同态像

    +

    数学上的同态映射,指的是对象空间中的一种变换,它将原空间O中的对象a和b映射到像空间中的P(a)和P(b),同时这种映射保持原空间中的某些运算关系f,即原空间中定义的函数可以自然转换为像空间中的函数。

    +
    P(f(a,b)) = f(P(a), P(b))
    + +

    对象实现接口,对象是接口的一个实例,obj is an instance of interfaceA。设计中我们需要保持对象和基类,以及对象和接口之间在概念层面上的“is a”关系,目的是为了保证针对接口编写的代码可以作用于派生对象上,即

    +
    f(interfaceA,interfaceB) == f(objA, objB)
    + +

    对象上可以有很多函数,一般只有少部分函数是执行业务功能时所必须的功能接口函数,其他大量的函数则是为了支持动态配置、维护生命周期等提供的辅助函数。如果我们坚持对象之间只依赖于功能接口,相当于是将问题同态映射到一个较小的语义空间中,从而实现问题的简化。

    +

    描述式的依赖注入容器知道所有对象之间的依赖关系,因此可以对它们的构造顺序进行全局排序,并且可以通过配置文件实现延迟装配,通过缓存实现延迟加载语义等,相当于是解耦了不必要的对象创建顺序之间的依赖(只有具有全局知识才能实现全局优化)。当然,如果我们系统的结构比较简单,本身可以被提取为明确的几个生命周期阶段,则依赖注入容器在此方面的作用会被弱化。

    +

    接口可以看作是对象的一种局部表象(Representation)。为了使得这种表象的作用最大化,一个必然的要求是表象空间中的运算具有某种完备性,即通过表象空间中定义的函数操作即可完成主要的业务功能。接口上定义的函数应该是在业务层面上能够自圆其说的,否则就会出现所谓的抽象泄露的问题。

    +

    二. 从同态映射到表象变换

    如果追溯起来,耦合和解耦这样的概念其实是来自于数学和物理领域,而在数学和物理中我们实现解耦的手段要丰富、强大的多。

    +

    回想一下数学物理中最重要的Fourier变换理论,多个不同频率的信号叠加在一起,在时域上看来它们是完全混杂在一起的,在每一个时间点上实际上都存在着多个信号的影响。但是通过Fourier变换,我们在频域上可以得到完全分离的多个信号! 所以,为了实现解耦,最本质、最强大的手段应该是表象变换,接口只是表象变换的最简单的一种形式而已

    +

    解耦好坏的一个评判标准是所谓的高内聚低耦合。高内聚的极限是不可分(原子性),而低耦合的极限是不相关。线性系统情况下,解耦总是存在无限多的最优解:只需找到任意一组单位正交向量即可(正交坐标系旋转任意角度仍然是合法的正交坐标系),然后整个空间中的所有量都可以通过基向量上作用量的线性组合来得到。

    +

    表象变换,简单的说起来,可以看作是坐标系变换。事物的本质并没有变,但是在不同的坐标系中去考察的时候,我们会误以为它的复杂性,各个部分之间的相互关系在发生激烈的变化。如果反过来思考,当我们设计一个系统的时候,可以选择维度正交的线性系统作为我们的目标模型,尽量保持系统各个层面的线性性,从而实现系统结构的简化。参见

    +

    从张量积看低代码平台的设计

    +

    如果把DSL(领域特定语言, Domain Specific Language)看作是一种全局表象,则表象变换可以表达为 F(DSL),即针对DSL的一个解释器或者代码生成器。但是一般来说DSL是针对已知领域需求的总结,它的能力总是有限的,为此我们必须补充额外的信息Delta才能生产目标系统。由此得到

    +
    App = F(DSL) + Delta
    + +

    也就是说我们需要把外部提供的差量信息和表象变换得到信息合并在一起。但是合并就意味着混杂,混杂一般会导致熵增(系统混乱度上升)。熵增本质上是因为信息的损失,如果能够控制不产生熵增,则必须保持信息的完整性,确保信息不损失,而在热力学中这意味系统的演化是可逆的

    +

    可逆运算意味着变化量和本体的解耦。变化量可以脱离本体独立存在,它具有自身的意义。

    +
    Delta = App - F(DSL)
    + +
    +

    在可逆计算理论中,Docker镜像就可以被看作是一种差量结构,应用镜像可以脱离底层的操作系统镜像而被单独的存储、传递、管理等。

    +
    +

    引入可逆计算的思想之后,会出现一些有趣的现象。一般概念中,解耦是减少相互作用,那首先应该是减少参与相互作用的对象个数。但是如果存在可逆计算,则可以通过增加新的对象Delta来实现解耦。例如,对象A和对象B对同一个的功能设计存在冲突,它们可以按照最适合自己内部结构的情况进行设计,不用考虑为回避冲突存在而导致的耦合问题。当它们在一起使用时,可以补充Delta差量来解决它们之间的概念冲突。

    +
    App = A + B + (-C - D + E) = A + B + Delta
    + +

    Delta对于A和B而言是完全外置的实体。

    +

    面向对象和组件理论,本质上是试图从人类物质世界的生产活动中汲取经验,但是随着软件生产活动的深化,我们有必要重新认识软件的抽象本质。软件是在抽象的逻辑世界中存在的一种信息产品,信息并不是物质。抽象世界的构造和生产规律与物质世界是有着本质不同的。物质产品的生产总是有成本的,而复制软件的边际成本却可以是0。将桌子从房间中移走在物质世界中必须要经过门或窗,但在抽象的信息空间中却只需要将桌子的坐标从x改为-x而已。抽象元素之间的运算关系并不受众多物理约束的限制,因此信息空间中最有效的生产方式不是组装,而是掌握和制定运算规则。

    +

    关于可逆计算完整的理论阐述,可以参见我的文章

    +

    可逆计算:下一代软件构造理论

    +

    具体的一些实现方式可以参考

    +

    可逆计算的技术实现

    +

    低代码平台需要什么样的ORM引擎?(1)

    +

    低代码平台需要什么样的ORM引擎?(2)

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/theory/delta-oriented-programming/index.html b/projects/nop-entropy/docs/theory/delta-oriented-programming/index.html index 2fa377a..ba65a86 100644 --- a/projects/nop-entropy/docs/theory/delta-oriented-programming/index.html +++ b/projects/nop-entropy/docs/theory/delta-oriented-programming/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/design-methodology/index.html b/projects/nop-entropy/docs/theory/design-methodology/index.html index d61e330..57b5fc1 100644 --- a/projects/nop-entropy/docs/theory/design-methodology/index.html +++ b/projects/nop-entropy/docs/theory/design-methodology/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1146 +186,112 @@ -
    +
    + + + +
    +
    +
    + + +

    一. 树形结构:长程关联

    -
    +

    关于”业务逻辑拆分模式:file/dir/repository”的几点讨论
    @taowen组织了一个微信群”业务逻辑拆分模式撰写组”,在讨论中他提出一个观点

    +
    +
    +
    +
    +
    +
    +

    业务逻辑最终都是要分解成文件,文件夹,git仓库的。那是否应该从这个角度入手:什么东西适合用文件,什么东西适合用文件夹分,什么东西适合用git仓库分呢?

    +

    软件工程的本质是否就体现在这种分解过程中?是否存在一般性的可操作的规则来指导我们进行正确的业务逻辑拆分?在本文中,我想结合可逆计算理论谈谈自己的看法。

    +

    我们可以从信息认知的角度来理解树形结构的作用。当信息匮乏时,我们只能认知到存在的一。当信息逐渐增加时,我们会识别出差异,认识到一分裂为多。如果认知的复杂度进一步增加,我们会识别出差异中的同,经过分组汇聚之后实际上形成一个嵌套结构。

    +

    $$
    Tree = List + Nested
    $$

    +

    所以,树形结构是一种非常自然的认知框架。这个框架的一个令人瞩目的衍生特性在于:树可以有效的表达一种受控的长程关联。也就是说,当在父节点上施加某种控制的时候,我们会在所有子节点以及孙子节点上产生相应的影响,比如在根目录上控制访问权限。同时,节点对自己的父节点以及祖父节点存在确定且唯一的影响途径,比如DOM消息冒泡处理。

    +

    树形结构表达了整体和部分的构成关系,它的一个特例是父节点和子节点具有类似的结构,比如目录由子目录和文件构成。当存在这种整体和部分的自相似性时,我们只要掌握少数核心结构即可通过推演来理解系统整体结构。比如,在程序语言理论中,通过递归应用有限的语法规则,即可生成无限多合法的程序语句。这种现象在自然界中是广泛存在的,它被称之为分形(Fractals)。

    +

    树形结构的每个节点具有局部可区分的名称,比如文件名,同时它在整个树形结构中存在唯一的路径,这是在全局结构中可用于定位的坐标。比如,对于二叉树,我们可以通过二进制来为每一个节点赋予唯一的编号,例如0表示左分支,1表示右分支,1011表示沿着路径右左右右所到达的节点。

    +

    当我们认知世界并对世界施加控制的时候,我们需要一个有效的坐标系统,同时我们也需要一种有效的控制传递手段,所以树形结构就经常成为某种必然的选择。

    +

    二. 如果评价拆分方式的优劣?

    首先我们需要认识到在给定的情况下,往往是存在多种可选的坐标系的。比如,在平面中我们可以选择无限多的X-Y正交坐标系。从一团乱麻中挣脱出来,我们需要的是一个认知上的切入点,具体从哪里切入不一定那么重要。比如,在不同的X-Y坐标系中,我们都可以建立类似的解析几何方程,并采用统一的代数方法去求解。

    +

    对于特定的问题,可能存在着某种最优的表达方式。例如圆这个结构在笛卡尔坐标系下是二维结构,当圆心为坐标中心时,我们可以很明确的识别出上下左右结构的对称性。但是,圆的本质是一维的,只有在极坐标系下我们才可以实现最简的表达。所以,最有效的表达是降维的。当我们进行拆分的时候,我们当然希望是沿着不变的边界进行分离, 例如坐标r保持为常量。但是,往往只有在演化的过程中,我们才能发现变化的脉络。而一个不巧的事实是,只有在时刻t我们才能观测到时刻t-1的演化结果,所以为了实现最有效的拆分,终极的一种需求是**把未来的知识以某种方式输运到当下*。

    +

    对于所有问题所构成的集合,显然不存在什么最优表示方案。在多个树形结构中进行选择时,决策树机制提供了一种评价标准:选择特征使得信息增益最大化(信息不确定性减少的程度最大),简单的说就是切分后减少混杂。但是出于不同的使用目的,我们的关注重点可能是变化的。比如某些情况下我们看重特征B,而另外一些情况下我们看重特征C等。受限制于人的认知能力、历史习惯、环境限制等,往往我们习惯于选择唯一的一种主切分方式,它只能是一种综合妥协的结果。

    +

    理想中的结构抽象应该是简单明了的反映领域中的本质关系。但是因为任何一个复杂结构事实上都不是直接构造出来的,而是逐渐生长出来的。生长依附于它所处的生态,并不会凭空的发生,而万物生长的过程又会反作用于生态,导致情况的进一步复杂化。例如,作为一个无神论者,你可能认为宗教是彻头彻尾的谎言,完全无用的痴言妄语。但是,人类社会围绕着宗教建立了庞大的经济、文化、政治体系,大量人类文明的珍宝依托在宗教这个看起来并不靠谱的概念体系之上,而且大部分时候社会运转良好。

    +

    到底什么东西适用于文件?什么东西适用于文件夹?什么东西适用于git仓库呢?从完全抽象的角度上说,我们所需要的可能只是一种贯通一致的、在各个层面统一的通用管理手段。但现实是,想要拿来就用的功能只在某些层面存在。比如,我们可能希望权限管控的基本单位是任意目录,但是git不支持啊,当然可以自己搞,但有挺多工作量,还有外围一堆配套工具的问题,还有使用者培训的问题,那还是算了吧。

    +

    文件存储是一种静态的表达,或者说是信息的一种序列化形式,它并不是我们知识的全部。比如,分子生物学发现生物的遗传信息本质上由ATGC等少数几个抽象符号构造的DNA序列来保存和传递。但是如果要真正理解这些信息如何起作用,为什么要这样组织,最终我们还是要参考它的运行时结构,发生在不同时空位置的转录、剪切、折叠等等知识。

    +

    三. 可逆计算对于拆分的新见解

    可逆计算理论提出了一个新的软件构造范式:

    +
    App = Biz x-extends Generator<DSL>
    + +

    本质上,它对应于 Y = F(X) + Delta 这样一种分解模式。

    +

    首先,这是一种生成式系统。我们所表达的DSL信息并不是被直接使用的,而是事后可以通过转换器/生成器进行再解释的。当情况发生变化时,我们可以通过简单的将变化信息通过DSL模型输入到系统中,从而自动传播到系统各处。 大范围的信息传导机制便于实现拆分的局域化。

    +

    第二,DSL是对信息的一种结构化表述。在可逆计算的具体实现中,我们不仅仅需要引入结构化表达,同时需要引入对这种结构化表达的一系列处理手段,比如转换、合并、生成等。git在文件级别管理差量更新,而可逆计算需要把这个粒度推进到文件级别以下,同时将整个应用看作是一个完整的树形结构表达,来进行整体结构管控。

    +

    第三,Delta差量和自动化的差量合并机制是可逆计算的核心。差量是可逆性的自然结果

    +

    $$
    A = B + C ==> C = A - B = A + (-B)
    $$

    +

    可以进行差量分解实际上是我们这个世界之所以能够被理解的一个本质原因。在数学上,任何一个解析函数都可以分解为Talyer级数,牛顿力学本质上对应于一阶线性项,而在物理中,我们总可以通过不断的追加二阶项、三阶项来逐步深化对系统的理解。

    +

    根据可逆计算的构想,为了有效的控制熵增,我们采用如下两个策略:

    +
      +
    1. 尽力保持系统的可逆性
    2. +
    3. 通过Delta差量把不可控的混乱部分分离出主体
    4. +
    +

    可逆性表现为加入系统中的信息需要能够很容易的分离并删除,比如很容易的屏蔽或删除某个特性。在开发阶段它可能表现为版本管理,在部署运维阶段则体现为自动回滚、灰度发布等。可逆性可以成为关注点分离的一种评判标准,同时它也能成为一种系统化的结构构造手段。

    +

    大型系统的腐化源于系统结构不断接受各类偶然性需求的冲击,根据热力学第二定律,一个自然发展的系统必然是不断熵增的(除非是不断新陈代谢的耗散系统,比如说不断重写)。但是不能控制熵增,我们仍然可以控制熵增的地点。基于差量机制,我们可以把偶然性需求隔离在某个差量Delta中。在可逆计算的具体实践中,所有逻辑都是可以进行差量定制的,因此在开发完一个产品之后,我们可以在完全不修改主版本代码的情况下,通过存放的差量描述,对主版本逻辑进行细粒度的定制。

    +

    在可逆计算的视角下,软件构造不再是从部分到整体的一种逐步组装的部分-整体构成关系,而是一种基于结构运算的转化关系。

    +
       App1 = A + B + C
    App2 = A + B + D = App1 - C + D = App1 + Delta
    + +

    在完全不拆解App1的情况下,我们可以通过单纯的**“追加”**操作实现App2的构造。从生产模式上说,可逆计算将传统的”生产即组装”模式改变为更适合抽象逻辑结构构造的“运算即生产”模式。

    +

    所以基于可逆计算,我们对于业务逻辑拆分可以多问下面三个问题:可逆否?差量乎?今天你DSL了吗?

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/theory/discussion-about-reversible-computation/index.html b/projects/nop-entropy/docs/theory/discussion-about-reversible-computation/index.html index 7562b39..0909e4b 100644 --- a/projects/nop-entropy/docs/theory/discussion-about-reversible-computation/index.html +++ b/projects/nop-entropy/docs/theory/discussion-about-reversible-computation/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/discusson-about-nop/index.html b/projects/nop-entropy/docs/theory/discusson-about-nop/index.html index d262448..840b147 100644 --- a/projects/nop-entropy/docs/theory/discusson-about-nop/index.html +++ b/projects/nop-entropy/docs/theory/discusson-about-nop/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1128 +186,94 @@ -
    +
    + + + +
    +
    +
    + + +

    关于Nop平台以及低代码平台建设经验的讨论

    -
    +

    前些天可逆计算与Nop平台微信群组织了一次讨论,探讨了如何利用差量运算和元编程的概念来解决低代码平台建设中存在的普遍性困难。

    +

    Nop平台的设计目标和开发计划

    Nop平台的设计目标不是提供一个功能完善、面向最终用户的低代码产品,而是提供一个基于创新的设计理论重构整个技术栈,为粗粒度、系统级的软件复用铺平道路的技术底座。如果你希望与世界上最优秀的低代码产品如 Mendix、OutSystems等进行竞争,并提供一些超越它们的功能特性,可以参考、借鉴Nop平台中的具体技术方案。

    +

    Nop平台目前的有效代码量(除去自动生成的代码和括号)大概10几万行,预计最终代码量在20多万行左右。目前已经完成了支持可逆计算原理的程序语言XLang,以及ORM/IoC/RPC/GraphQL/Rule/Report等基本引擎的实现,年底前预计完成Workflow引擎,明年上半年实现分布式批处理引擎。

    +

    Nop平台主要是后端的实现,前端目前使用了百度AMIS框架,原则上可以更换为任何其他低代码前端。因为Nop平台专注于后端,所以欢迎前端框架的同学参与共建,对齐技术接口,减少重复建设。

    +

    Nop平台的开发会持续进行,对中小企业允许免费商用,未来所有功能也都会开源,不会出现收费组件。第三方可以自行在Nop平台基础上进行优化封装,提供商业化改进和支持,Nop平台的版权协议不会限制这些行为,也不要求二次封装的工作进行开源。允许二次开发修改包名,但是不允许删除源码头部的版权声明和作者链接

    +

    Nop平台如何克服低代码平台普遍存在的技术困难?

    1. 扩展字段按照纵表形式存储,能不能支持查询和排序?性能比较低怎么办?

    NopORM引擎提供了通用的横纵变换机制,它不仅仅可以用于保存扩展字段,而是适用于一切主子表结构,支持查询和排序。具体做法如下:

    +
      +
    1. 在子表中定义唯一标识属性keyProp,例如keyProp=”fieldName”
    2. +
    3. EQL对象查询语法(类似于JPA中的对象查询语法)访问子表集合中的元素时可以使用对象属性语法,会自动翻译为表关联条件
    4. +
    +
    entity.subEntities.my.status 对应于  entity.getSubEntities().getByKey("my").getStatus()
    + +
      +
    1. 通过alias机制可以将复杂的属性路径映射为简单属性名。在程序中使用时与表上原生的属性没有任何差别。
    2. +
    +
    entity.myStatus ==>  entity.subEntities.my.status
    + +

    扩展字段很多性能受影响时,可以通过配置为每一个表指定对应的扩展字段表,甚至可以为每个表的每个扩展字段指定一个单独的存储表。通过alias和keyProp机制对外统一暴露为普通属性,不会影响应用层编程。

    +

    具体介绍可以参见 低代码平台需要什么样的ORM引擎

    +

    2. SAAS产品的同一个基础功能针对不同的客户会有不同的定制调整,同时基础产品还在不断迭代更新,这两者之间的冲突如何解决?

    这里存在两个变换的方向:产品自然发展的方向和定制版本方向,这两种变化如果直接相撞,必然会出现激烈的冲突。Nop平台提供了如下解决方案:

    +
      +
    1. Delta差量合并:相比于Git版本管理,可以避免大量非业务层面的冲突问题。
      Git相当于是采用文本行差量空间,一些业务上完全等价的操作(如方法的前后顺序并不影响语义,再比如格式化代码)会造成文本行空间中的剧烈变化。同一行上DSL不同的属性的变化一般也是不冲突的,
      但是git层面会识别为行修改。
      同时,Delta合并会明确表明覆盖方向,比如x:override=”remove”,x:override=”append”,避免了语义不清导致的冲突
    2. +
    3. 在基础产品层和业务应用层之间允许插入任意多的Delta层,例如产品Bug修正层和产品改进层,在Bug修正层中紧急修复一些等不及产品层修复并下发补丁的bug,而在产品改进层可以增加一些可以同步回基础产品的特性功能,不用将通用的功能和针对当前业务进行的定制修改纠缠在一起。
    4. +
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/theory/essence-of-react/index.html b/projects/nop-entropy/docs/theory/essence-of-react/index.html index 5d2e64f..dde0e08 100644 --- a/projects/nop-entropy/docs/theory/essence-of-react/index.html +++ b/projects/nop-entropy/docs/theory/essence-of-react/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/framework-agnostic/index.html b/projects/nop-entropy/docs/theory/framework-agnostic/index.html index fe63a44..7dd1c33 100644 --- a/projects/nop-entropy/docs/theory/framework-agnostic/index.html +++ b/projects/nop-entropy/docs/theory/framework-agnostic/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/generic-delta-composition/index.html b/projects/nop-entropy/docs/theory/generic-delta-composition/index.html index c43bade..83d70c0 100644 --- a/projects/nop-entropy/docs/theory/generic-delta-composition/index.html +++ b/projects/nop-entropy/docs/theory/generic-delta-composition/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/good_design/index.html b/projects/nop-entropy/docs/theory/good_design/index.html index badcd50..4e3e7a4 100644 --- a/projects/nop-entropy/docs/theory/good_design/index.html +++ b/projects/nop-entropy/docs/theory/good_design/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1132 +189,98 @@ -
    +
    + + + +
    +
    +
    + + +

    -
    +

    什么是好的模型?

    +

    昨天在介绍模型驱动的时候,有位同学问我如何设计一个好的模型?这是一个很难回答的问题。因为好很难定义,如何到达所谓的好更没有一定之规。

    +

    首先,好的定义往往是场景相关的,一个当前最优的选择随着场景的变迁也可能不再是好的选择。即使是放之四海而皆准的更好,比如广义相对论 vs. 牛顿力学,在解决具体问题的时候,也可能简单的牛顿力学更实用。

    +

    第二,如果我们能够设计出一个适用范围很广、能够应对很多变化的模型,那么本质上的原因也是领域逻辑具有某种内在的规律,模型只是这种规律的一种自然体现。软件设计目前还远谈不上是一种精密、复杂的科学,即使不懂得任何设计理论,多观察一下别人的成功和失败经验,一般也能达到一个差不多的程度。

    +

    第三,创造性的解决问题的方案在一开始可能显得离经叛道,与当前的生态格格不入,反而有可能看上去是不好的。

    +

    虽然很难以一种明确的方式去定义什么是好的模型,我们仍然可以根据一些表观条件来过滤掉一些次优的选择。

    +
      +
    1. 设计是多目标优化的。我们可以把问题分解为多个维度,在每个维度上单独衡量,然后再综合评估。

      +
    2. +
    3. 设计是多层次的(空间),不要试图设计一个最好的、万能的模型。比如,存储层和应用层可以有不同的对象结构,没必要使用统一的对象结构一统到底。使用DDD领域模型驱动也不需要排斥根据物理模型来生成实体存储层的代码。不同抽象层次、面向不同使用意图的元素不要混杂在同一个模型中。基于可逆计算理论,可以通过增量化代码生成来实现不同结构的模型共享部分基础信息。

      +
    4. +
    5. 模型应是面向演化的(时间),不应过早引入限制未来选择的设计决定。基于可逆计算理论,可以通过差量机制永远为模型保留最细粒度的扩展能力和多模型融合的能力,可以通过元编程弥补组件和插件机制的不足。

      +
    6. +
    7. 模型的复杂度应适中。解决方案的复杂度与问题的复杂度,以及具体执行人所能适应的复杂度要相匹配。简单的问题不应该采用明显过于复杂的解决方案。如果执行人的能力范围有限,即使一个方案可能在技术层面更优,但更容易出现误操作、出现问题更难独立解决,那么可能还不如使用执行人能够充分理解、具有充分自主控制权的方案。反之,一个复杂的问题可能不存在简单的解决方案,简单粗暴将意味着拆东墙补西墙,疲于奔命。

      +
    8. +
    9. 模型需要明确定义它对外部环境的依赖,并尽量缩减它对外部的依赖点。模型的价值首先在于它可以被独立的解释和认知。

      +
    10. +
    11. 模型内在的概念完备性和一致性非常重要。基于可逆计算理论,对于模型可参与的运算,我们需要进行配对设计,即每个改变状态的动作(差量)都对应一个反向动作(差量),使得系统在某种意义上可以恢复到前一个状态。不能反向往往意味着信息记录的缺失和设计空间的不完备性,面对异常情况时会无法处理。

      +
    12. +
    13. 任何一个具有一定复杂度的模型都应具有分解、合并和二次抽象的机制。比如支持组件封装,import子模型等。可逆计算理论为此提供了一整套通用的解决方案,无需针对每种模型再进行单独设计和实现。

      +
    14. +
    15. 对模型信息的处理利用可以是多阶段的。应尽量在代码生成、编译期、预处理等阶段进行处理,不要把与运行时状态无关的逻辑和运行时逻辑纠缠在一起。

      +
    16. +
    17. 模型的内容重于形式,但是形式应允许反向析取。大量使用某种语言或者某种框架内置的机制来表达模型,虽然可以简化一次性编写的成本,但长期来说对于模型演化并不有利。为了最大化模型的价值,模型作为描述性信息应该是多用途的,不应只服务于某种单一目的,需要支持对模型信息进行再加工和形式转换。

      +
    18. +
    19. 模型应该由元模型来定义。通过元模型可以最大限度的发掘不同模型之间的语义和结构共性,便于实现它们的互联互通。通过元模型可以自动生成模型解析器、IDE插件和设计器等。

      +
    20. +
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/theory/graphql-vs-rest/index.html b/projects/nop-entropy/docs/theory/graphql-vs-rest/index.html index 87d9e6c..5ba3cad 100644 --- a/projects/nop-entropy/docs/theory/graphql-vs-rest/index.html +++ b/projects/nop-entropy/docs/theory/graphql-vs-rest/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1137 +186,103 @@ -
    +
    + + + +
    +
    +
    + + +

    为什么在数学的意义上GraphQL严格的优于REST?

    -
    +

    GraphQL是Facebook公司所提出的一种用于API的查询语言,很多人把它看作是REST的替代品,但也有很多人认为GraphQL比REST复杂得多,且没有明显收益。
    GraphQL到底具有哪些独特的能力超越了REST的能力范围?有没有一种客观的、严谨的评判标准可以帮助我们做出判断?

    +

    Nop平台中通过严密的数学推理,对于GraphQL的定位进行了重新的诠释,获得了一些新的设计思想和技术实现方案。在这种诠释下,NopGraphQL引擎实现了对REST的全面超越,
    可以说在数学的意义上GraphQL严格的优于REST。

    +
    +

    关于NopGraphQL的介绍,可以参见我此前的文章 低代码平台中的GraphQL引擎

    +
    +

    简单的说,GraphQL可以看作是REST的面向pull mode的改进,它在某种程度上是反转了信息流向

    +
    query{
    NopAuthDept__findAll{
    name, status,children {name, status}
    }
    }
    + +

    等价于 /r/NopAuthDept__findAll?@selection=name,status,children{name,status}

    +

    经过数学意义上的等价变换(形式变换),我们可以清晰的看出,GraphQL不过是在REST的基础上补充了一个标准化的@selection参数,通过它可以对返回结果进行选择性拉取。

    +

    传统的REST相当于是后台推送(push)所有信息到前台,前台无法精细的参与这个信息生产和传递过程。在NopGraphQL的实现中,前台如果不传递@selection参数,就自动退化为传统REST模型,返回所有非lazy的字段。lazy的字段需要显式指定才会返回到前台。

    +

    GraphQL在Nop平台的架构中并不是与REST平级的一种传输协议,而是一种通用的信息分解组合机制,它可以帮助我们对系统的信息结构进行更有效的组织。

    +

    NopGraphQL的定位是作为后端服务函数的一种通用分解、派发机制,所以同一个服务函数,可以同时发布为REST服务、GraphQL服务、GRpc服务、Kafka消息服务、Batch批处理服务等。简单的说,任何一种接收Request Message,返回Response Message的场景都可以直接对接到NopGraphQL引擎,将它作为自己的实现机制。

    +

    使用GraphQL相比于传统的REST有如下优势:

    +

    1. 根据请求数据自动裁剪数据加载范围,实现性能优化

    @BizQuery
    public PageBean<NopAuthUser> findPage(@Name("query") QueryBean query, FieldSelectionBean selection, IServiceContext context){
    PageBean<NopAuthUser> pageBean = new PageBean();
    if(selection != null && !selection.hasField("total")){
    long total = dao.countByQuery(query);
    pageBean.setTotal(total);
    }
    ....
    }
    + +

    如果前端不要求返回total,则可以跳过total属性的计算

    +

    2. 由引擎自动完成DTO适配,极大提升数据模型的可组合性

    传统的REST服务中服务函数是直接返回DTO对象,所有DTO对象中的属性都必须在该服务函数中负责加载。比如说NopAuthUser实体上增加了一个虚拟的roles字段,则在DTO上要增加这个字段,而且所有返回NopAuthUserDTO的地方都需要补充roles字段的加载逻辑。
    而在NopGraphQL引擎中,服务函数返回的对象并不会直接被序列化为JSON返回到前台,而是交由GraphQL引擎做进一步的DataLoader加工处理后得到最终的返回数据。因此它可以极大提升后台数据模型的可组合性。这里的可组合性指的是我们分别实现了A和B,就自动得到了所有A*B的结果,无需手动进行组合处理。

    +

    @BizQuery
    public List<NopAuthUser> findList(){
    ...
    }

    @BizQuery
    public NopAuthUser get(@Name("id") String id){
    ...
    }

    @BizLoader
    public List<String> roles(@ContextSource NopAuthUser user){
    ...
    }
    + +

    在上面的示例中,findList和get函数只需要知道如何加载NopAuthUser对象的知识,不需要知道NopAuthUser如何与NopAuthRole对象进行关联的知识。服务函数可以直接返回实体对象,并不需要人工翻译为DTO对象。

    +

    当我们通过@BizLoader机制为NopAuthUser类型增加了动态属性roles之后,所有返回结果中涉及到NopAuthUser的地方都自动增加了roles属性。DataLoader所提供的知识通过NopGraphQL引擎的作用,自动的与我们手工编写的get/findList等函数组合在一起。

    +

    在NopGraphQL中,我们还可以通过额外的xmeta元模型文件来独立的控制每个字段的权限、转换和验证逻辑等,从而简化以及标准化服务函数的实现。

    +

    3. GraphQL的选择能力是DDD中聚合根概念的有益补充

    DDD(Domain Driven Design,领域驱动设计)中一个非常关键、对于信息空间规划至关重要的设计就是所谓的聚合根概念(AggregateRoot)。聚合根相当于是信息空间中的一种核心节点,当我们要在信息空间中游历的时候,我们不是在所有的信息节点之间都建立一对一的连接线路,而是在少量核心节点上建立直连通路,然后再通过聚合根访问它下属的子信息节点。

    +

    聚合根是在形式层面对信息的一种聚合组织方式。这种形式上的聚合降低了我们的认知和使用成本,但是它对性能也会产生一种负面影响。聚合根表达了我们通过根对象可以访问到的所有信息,如果每次获取到根对象的时候都自动加载所有信息,必然会导致不必要的资源浪费。GraphQL的选择能力正是与聚合能力相对偶的一种能力(聚合和选择作为对偶操作我们总是应该配对设计),它使得我们可以从形式上巨大无比的一个信息结构中选择性的截取到我们所需要的信息切片,恰好满足我们的业务要求。

    +

    4. GraphQL在语义层面明确区分了query和mutation,更符合REST表述性状态转义设计中的原始意图。

    REST调用中虽然规定了GET和POST两种方法,但是因为实现层面的限制(GET方法不支持通过http body传递数据,URL长度有限制且有安全性问题),很多时候我们并不能通过GET/POST来精确的区分服务函数的语义。

    +

    在NopGraphQL中,我们约定了query没有副作用,不会修改数据库,而mutation具有副作用,需要考虑事务管理等,因此在NopGraphQL框架中,我们并不需要手动为每个服务函数增加 @Transactional事务注解,而是统一为所有mutation操作建立事务环境。通过实现层面的优化,如果mutation中实际上没有访问数据库,则NopGraphQL框架并不会真的去获取数据库连接。

    +

    NopGraphQL引擎将后台服务函数的执行分解为两个阶段:

    +
      +
    1. 执行服务函数,如果是mutation,会自动建立事务环境
    2. +
    3. 对服务函数返回的结果对象进行再加工,通过DataLoader进行数据转换和剪裁。
    4. +
    +

    第一个阶段执行完毕之后就会自动关闭事务,此时一些比较消耗资源的数据加载工作并没有开始执行。在第二阶段执行时会关闭事务,并且将OrmSession置于readonly状态,如果误操作修改了实体数据,会自动抛出异常。通过这种方式,我们可以减少事务打开时间和数据库连接的占用时间。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/theory/index.html b/projects/nop-entropy/docs/theory/index.html index a59ac77..228425c 100644 --- a/projects/nop-entropy/docs/theory/index.html +++ b/projects/nop-entropy/docs/theory/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1124 +186,90 @@ -
    +
    + + + +
    +
    +
    + + +

    可逆计算理论

    -
    +

    知乎专栏

    可逆计算

    +

    集中收录了作者关于可逆计算理论和Nop平台实现原理的相关论述

    +

    三句话解释什么是可逆计算

      +
    1. 面向对象中的继承和Rust语言中的trait不包含删除语义,而且仅表达了对象-方法这样一级关系,结构层面仅对应于Map。
    2. +
    3. 面向对象的最强形态是带模板元编程能力的泛型对象,它在结构层面上可以看作是Map extends Map<Map>
    4. +
    5. 如果将Map扩展为Tree结构,并且扩展extends算子包含减法,这样Tree就成为包含逆元的DeltaTree,整体结构将升级为 Tree x-extends Tree<Tree>
      这个抽象可以很自然的将抽象语法树和文件系统纳入自己的范畴,成为一个具有广泛应用领域,不限制于某个程序语言内部的通用计算模式,
      落实为具体的技术形式就成为可逆计算理论所定义的核心软件构造公式
    6. +
    +
    App = Delta x-extends Generator<DSL>
    + +
    +

    Docker和k8s中的kustomize都可以看作是可逆计算的具体实例

    +
    +

    可逆计算: 下一代软件构造理论

    对可逆计算理论的概要介绍

    +

    写给程序员的可逆计算理论辨析

    从程序员熟悉的概念出发详细解释了差量与差量合并在程序实践中的具体形式和做法,并分析一些常见的对于可逆计算的理解为什么是错误的。

    +

    写给程序员的可逆计算理论辨析补遗

    继续补充一些针对可逆计算理论的概念辨析,澄清对于可逆计算理论的一些常见误解

    +

    从可逆计算看Delta Oriented Programming

    本文对比了可逆计算理论与软件工程理论界的相关工作,如面向特性编程(FOP)和面向差量编程(DOP),并指出在可逆计算视角下,这些理论还存在哪些不足之处。

    +

    从张量积看低代码平台的设计

    框架设计中的多维度扩展在数学层面上可以看作是张量积空间上的线性映射函数。本文从理论层面解释了可逆计算原理如何与Loader抽象相结合。

    +

    从可逆计算看DSL的设计要点

    Nop平台基于可逆计算原理,提出了一整套系统化的构建机制来简化DSL的设计和实现,使得我们很容易增加针对自己业务领域的DSL,也很容易在已有DSL的基础上进行扩展。

    +

    GPT用于复杂代码生产所需要满足的必要条件

    现在很多人都在尝试用GPT直接生成代码,试图通过自然语言指导GPT完成传统的编码工作。但是,几乎没有人去真正认真的考虑一下生成的代码如何长期维护的问题。本文从理论层面分析了GPT用于复杂代码生产所需要满足的必要条件,并提出了Nop平台与GPT结合的具体策略。

    +

    如何评价一种框架技术(比如ORM框架)的好坏

    对于一种新的框架技术,”很方便、很好用”这样的评价表达的仅仅是一种主观感受,能否在客观层面定义一些不受人的主观偏好影响的客观标准?

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/theory/lowcode-expained/index.html b/projects/nop-entropy/docs/theory/lowcode-expained/index.html index cb6cf59..df87854 100644 --- a/projects/nop-entropy/docs/theory/lowcode-expained/index.html +++ b/projects/nop-entropy/docs/theory/lowcode-expained/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/lowcode-ioc/index.html b/projects/nop-entropy/docs/theory/lowcode-ioc/index.html index d3d2ad8..56c5808 100644 --- a/projects/nop-entropy/docs/theory/lowcode-ioc/index.html +++ b/projects/nop-entropy/docs/theory/lowcode-ioc/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/lowcode-orm-1/index.html b/projects/nop-entropy/docs/theory/lowcode-orm-1/index.html index 0180a66..727fe3e 100644 --- a/projects/nop-entropy/docs/theory/lowcode-orm-1/index.html +++ b/projects/nop-entropy/docs/theory/lowcode-orm-1/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/lowcode-orm-2/index.html b/projects/nop-entropy/docs/theory/lowcode-orm-2/index.html index 559b286..3f4ce7e 100644 --- a/projects/nop-entropy/docs/theory/lowcode-orm-2/index.html +++ b/projects/nop-entropy/docs/theory/lowcode-orm-2/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/lowcode-task-flow/index.html b/projects/nop-entropy/docs/theory/lowcode-task-flow/index.html index 5ac097a..03d120e 100644 --- a/projects/nop-entropy/docs/theory/lowcode-task-flow/index.html +++ b/projects/nop-entropy/docs/theory/lowcode-task-flow/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/methodology-of-reversible-computation/index.html b/projects/nop-entropy/docs/theory/methodology-of-reversible-computation/index.html index 6461912..3fbe6db 100644 --- a/projects/nop-entropy/docs/theory/methodology-of-reversible-computation/index.html +++ b/projects/nop-entropy/docs/theory/methodology-of-reversible-computation/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/nop-for-gpt/index.html b/projects/nop-entropy/docs/theory/nop-for-gpt/index.html index 4a021bf..f9028ad 100644 --- a/projects/nop-entropy/docs/theory/nop-for-gpt/index.html +++ b/projects/nop-entropy/docs/theory/nop-for-gpt/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/paxos/index.html b/projects/nop-entropy/docs/theory/paxos/index.html index c2d1f48..1d3291c 100644 --- a/projects/nop-entropy/docs/theory/paxos/index.html +++ b/projects/nop-entropy/docs/theory/paxos/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/pros-and-cons-of-framework/index.html b/projects/nop-entropy/docs/theory/pros-and-cons-of-framework/index.html index 701534f..5cfcbe1 100644 --- a/projects/nop-entropy/docs/theory/pros-and-cons-of-framework/index.html +++ b/projects/nop-entropy/docs/theory/pros-and-cons-of-framework/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/reuse/index.html b/projects/nop-entropy/docs/theory/reuse/index.html index 07b0129..52201a6 100644 --- a/projects/nop-entropy/docs/theory/reuse/index.html +++ b/projects/nop-entropy/docs/theory/reuse/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1125 +186,91 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/theory/reversible-computation-and-lowcode/index.html b/projects/nop-entropy/docs/theory/reversible-computation-and-lowcode/index.html index 024d23a..0c864f9 100644 --- a/projects/nop-entropy/docs/theory/reversible-computation-and-lowcode/index.html +++ b/projects/nop-entropy/docs/theory/reversible-computation-and-lowcode/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/reversible-computation-for-programmers/index.html b/projects/nop-entropy/docs/theory/reversible-computation-for-programmers/index.html index 6e8e39e..33368bf 100644 --- a/projects/nop-entropy/docs/theory/reversible-computation-for-programmers/index.html +++ b/projects/nop-entropy/docs/theory/reversible-computation-for-programmers/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/reversible-computation-for-programmers2/index.html b/projects/nop-entropy/docs/theory/reversible-computation-for-programmers2/index.html index 431c00c..3dbb725 100644 --- a/projects/nop-entropy/docs/theory/reversible-computation-for-programmers2/index.html +++ b/projects/nop-entropy/docs/theory/reversible-computation-for-programmers2/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/reversible-computation/index.html b/projects/nop-entropy/docs/theory/reversible-computation/index.html index 6af7002..cf2dd5a 100644 --- a/projects/nop-entropy/docs/theory/reversible-computation/index.html +++ b/projects/nop-entropy/docs/theory/reversible-computation/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/technical-strategy/index.html b/projects/nop-entropy/docs/theory/technical-strategy/index.html index 5f632ef..84c9f81 100644 --- a/projects/nop-entropy/docs/theory/technical-strategy/index.html +++ b/projects/nop-entropy/docs/theory/technical-strategy/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/tensor-product-lowcode/index.html b/projects/nop-entropy/docs/theory/tensor-product-lowcode/index.html index 55b2c8d..9554034 100644 --- a/projects/nop-entropy/docs/theory/tensor-product-lowcode/index.html +++ b/projects/nop-entropy/docs/theory/tensor-product-lowcode/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/what-does-reversible-mean/index.html b/projects/nop-entropy/docs/theory/what-does-reversible-mean/index.html index 64cc09d..fdf0c04 100644 --- a/projects/nop-entropy/docs/theory/what-does-reversible-mean/index.html +++ b/projects/nop-entropy/docs/theory/what-does-reversible-mean/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/what-is-data-driven/index.html b/projects/nop-entropy/docs/theory/what-is-data-driven/index.html index 18467ce..5e1b0c1 100644 --- a/projects/nop-entropy/docs/theory/what-is-data-driven/index.html +++ b/projects/nop-entropy/docs/theory/what-is-data-driven/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1148 +186,114 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/theory/why-nop-report-is-special/index.html b/projects/nop-entropy/docs/theory/why-nop-report-is-special/index.html index 0a44c1a..97107c1 100644 --- a/projects/nop-entropy/docs/theory/why-nop-report-is-special/index.html +++ b/projects/nop-entropy/docs/theory/why-nop-report-is-special/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1148 +186,114 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/theory/why-xml/index.html b/projects/nop-entropy/docs/theory/why-xml/index.html index da6ec68..cd522c7 100644 --- a/projects/nop-entropy/docs/theory/why-xml/index.html +++ b/projects/nop-entropy/docs/theory/why-xml/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1148 +186,114 @@ -
    +
    + + + +
    +
    +
    + + +

    为什么Nop平台坚持使用XML而不是JSON或者YAML

    -
    +

    目前在开发领域似乎形成了一种政治正确:XML是一种过时的技术,不应该再被广泛的使用。对于Nop平台大量使用XML来表达领域模型,有网友调侃道:信息都用xml表达,你这是反(潮流而)动啊。在此前的文章XML、JSON和函数AST的等价性中,我已经对XML和JSON的等价性进行了说明。基于这种等价性,在Nop平台中,XML和JSON是自动支持双向转换的,本质上用哪种表达方式都不影响模型的语义,完全可以用JSON文件来存储模型信息。但是,目前的情况下,XML的表现力相比JSON格式而言存在一些优势,在本文中我将补充一些具体的分析。

    +

    JSON存在的问题

    JSON格式的主要问题是缺少注释机制以及多行文本表示形式。这些问题在YAML格式中已经被解决,而YAML格式兼容JSON格式。所以在Nop平台中我们一般倾向于使用YAML格式来替代JSON,例如使用page.yaml来存放前端JSON页面。

    +
    x:gen-extends: |
    <web:GenPage view="NopAuthUser.view.xml" page="main" xpl:lib="/nop/web/xlib/web.xlib" />

    body:
    name: crud-grid
    filter:
    id: crud-filter
    actions:
    - id: submit-button
    icon: fa fa-snapchat
    + +

    在XML中嵌入JSON格式是非常简单的一件事情。但是在JSON中嵌入XML就需要进行字符串转义,会大大影响数据的可读性。如果使用YAML格式,嵌入XML就很简单直观了。

    +

    JSON乃至YAML格式所存在的另一个问题是它缺少特殊定义的类型属性。JSON对象中所有的属性原则上地位是平等的,在JSON规范中并没有规定可以用于快速区分JSON对象结构的类型属性,这导致它在反序列化的时候难以进行性能优化。

    +

    反序列化的时候我们往往需要根据类型属性来决定反序列化得到的对象类型,但是因为JSON格式没有规定type属性一定是第一个属性,可能在解析完整个对象结构之后才能对类型数据做出判断,这导致无谓的临时对象构建过程和额外的内存消耗。

    +

    相比较而言,XML总是突出tagName这个特殊属性,可以帮助我们在视觉层面快速识别特定的局部结构。在简单结构的情况下,XML表达形式可能会比JSON格式更简洁、直观。

    +
    <row a="1" b="xyz" />

    {
    "a": 1,
    "b": "xyz",
    "type": "row"
    }
    + +

    XML存在的问题

    毫无疑问,XML在实际使用过程中存在一些明显的问题,最本质的原因是XML最早的设计目标是一种面向文本数据的标签语言,对于具有丰富数据类型的应用数据缺乏规范化的表达方式。以IBM、SUN为首的大企业所大力推行的一系列XML相关标准又以严谨为名引入了大量复杂的设计,逐步成就了XML冗长繁琐的刻板印象。

    +

    XSD(XML Schema Definition)语言为例,如果对比JSON Schema语言,我们可以很容易的得到结论:XML Schema的信息密度远比JSON Schema要低。

    +

    JSON Schema可以很自然的声明嵌套结构,而XML Schema却强制把一切结构都拆解为type和element两层结构。

    +
    <xs:element name="personinfo">
    <xs:complexType>
    <xs:sequence>
    <xs:element name="firstname" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
    <xs:element name="address" type="xs:string"/>
    </xs:sequence>
    </xs:complexType>
    </xs:element>
    + +

    很多人在使用XSD的时候还总是倾向于使用xs:sequence定义,强制为子节点引入顺序依赖,这背离了声明式编程的基本思想,在使用层面往往也没有什么实际的价值,只是带来不必要的麻烦。

    +
    +

    声明式编程很大程度上就是要淡化顺序依赖这个概念,摆脱命令式编程所强行引入的非因果约束

    +
    +

    而在JSON schema中属性之间根本就无法定义顺序关系

    +
    {
    "type": "object",
    "properties": {
    "firstname": {
    "type": "string"
    },
    "lastname": {
    "type": "string"
    },
    "address": {
    "type": "string"
    }
    }
    }
    + +

    Nop平台中的XML

    Nop平台虽然大量使用XML语法,但是它并没有全盘接收目前的XML规范标准,而是只采纳了其中一个语法和特性子集。例如NopXML去除了外部Entity支持(由此避免了很多安全漏洞),简化了名字空间概念(仅在根节点处理xmlns配置),去除了Instruction概念(仅识别根节点上的Instruction)。 Nop平台在解析和处理XML的时候也没有使用现有的JAXB (Java Architecture for XML Binding) 技术,而是自行编写了XML解析器。解析得到的结果不是标准XML技术中所定义的DOM结构,而是面向应用层重新设计的XNode结构。

    +
    class XNode{
    SourceLocation loc;
    String tagName;
    Map<String, ValueWithLocation> attributes;
    List<XNode> children;
    ValueWithLocation content;

    XNode parent;
    }

    class ValueWithLocation{
    SourceLocation location;
    Object value;
    }
    + +

    XNode结构中记录了属性和节点的源码位置,并将attribute和content的值类型修改为Object类型,从而克服了XML原始设计中只针对文本文档的缺陷,使得它可以更高效的表达复杂的业务对象结构。

    +

    Nop平台采用XDef元模型语言替代了XML Schema的作用,它利用了前缀引导语法的设计思想,比JSON Schema更紧凑直观。

    +
    +

    前缀引导语法的设计参见 DSL分层语法设计及前缀引导语法

    +
    +
    <person firstname="!string" lastname="!string" address="string" />
    + +

    XDef元模型定义的结构基本与它所需要约束的数据结构相似,可以看作是将具体的某个模型数据中的值替换为类型声明后得到的结果。

    +

    对于XPath和Xslt转换语法,Nop平台同样没有采用,而是设计了替代的XSelector和XTransform语法。

    +

    更为重要的是,Nop平台引入了XML格式的模板语言XPL(XLang Template Language)。它是一个图灵完备的模板语言,支持判断、循环、标签抽象、模板元编程等概念,是Nop平台基于XML格式实现可逆计算的关键技术之一。

    +

    具体介绍参见 xpl.md

    +

    Nop平台坚持使用XML文件格式最重要的原因就在于JSON乃至YAML格式缺少功能与XPL类似的可用于复杂结构代码生成的模板语言

    +

    XPL的特点

      +
    1. 具有类似Lisp的同像特性:XPL为XML格式,输出结果也是XML格式
    2. +
    3. 具有多种输出模式,当outputMode=node时会直接输出XNode节点,在输出的过程中会记录属性和节点的来源位置。这在代码生成和断点调试时特别有用,它意味着我们始终可以跟踪当前节点的最初源码位置,调试或者报错时可以直接定位到源码行。
    4. +
    5. 支持编译期运行,本质上类似于Lisp中的宏的作用。
    6. +
    7. 支持自定义标签库,标签库支持Delta定制。也就是说XPL模板语言支持函数级别的差量化定制。
    8. +
    +

    具体示例可以参见视频 Nop平台中如果通过XBiz配置文件实现后台服务函数

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    +
    - - -
  • - - - - - - - - - - - - - 极简服务层开发 - - -
  • - -
  • - - - - +
  • - - + +
    - -
    diff --git a/projects/nop-entropy/docs/theory/xdsl-design/index.html b/projects/nop-entropy/docs/theory/xdsl-design/index.html index 6f55b22..6c51fdf 100644 --- a/projects/nop-entropy/docs/theory/xdsl-design/index.html +++ b/projects/nop-entropy/docs/theory/xdsl-design/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/theory/xml-json-equivalence/index.html b/projects/nop-entropy/docs/theory/xml-json-equivalence/index.html index a7348d3..62c54a8 100644 --- a/projects/nop-entropy/docs/theory/xml-json-equivalence/index.html +++ b/projects/nop-entropy/docs/theory/xml-json-equivalence/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/tutorial/simple/1-simple-service/index.html b/projects/nop-entropy/docs/tutorial/simple/1-simple-service/index.html index 2dafab5..3fca940 100644 --- a/projects/nop-entropy/docs/tutorial/simple/1-simple-service/index.html +++ b/projects/nop-entropy/docs/tutorial/simple/1-simple-service/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/tutorial/simple/2-simple-dao/index.html b/projects/nop-entropy/docs/tutorial/simple/2-simple-dao/index.html index 8ad5ee3..0d8a0e2 100644 --- a/projects/nop-entropy/docs/tutorial/simple/2-simple-dao/index.html +++ b/projects/nop-entropy/docs/tutorial/simple/2-simple-dao/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1144 +186,110 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/tutorial/simple/3-simple-page/index.html b/projects/nop-entropy/docs/tutorial/simple/3-simple-page/index.html index 1dccb2a..476b8c0 100644 --- a/projects/nop-entropy/docs/tutorial/simple/3-simple-page/index.html +++ b/projects/nop-entropy/docs/tutorial/simple/3-simple-page/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/tutorial/tutorial/index.html b/projects/nop-entropy/docs/tutorial/tutorial/index.html index cd0527e..b48be47 100644 --- a/projects/nop-entropy/docs/tutorial/tutorial/index.html +++ b/projects/nop-entropy/docs/tutorial/tutorial/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/tutorial/tutorial_en/index.html b/projects/nop-entropy/docs/tutorial/tutorial_en/index.html index 94ec4e2..e17d1a7 100644 --- a/projects/nop-entropy/docs/tutorial/tutorial_en/index.html +++ b/projects/nop-entropy/docs/tutorial/tutorial_en/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    - -
    + + + +
    +
    -
    - diff --git a/projects/nop-entropy/docs/user-guide/batch/index.html b/projects/nop-entropy/docs/user-guide/batch/index.html index 42e838f..fda9b3e 100644 --- a/projects/nop-entropy/docs/user-guide/batch/index.html +++ b/projects/nop-entropy/docs/user-guide/batch/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/user-guide/idea/idea-plugin/index.html b/projects/nop-entropy/docs/user-guide/idea/idea-plugin/index.html index e3704ab..920430e 100644 --- a/projects/nop-entropy/docs/user-guide/idea/idea-plugin/index.html +++ b/projects/nop-entropy/docs/user-guide/idea/idea-plugin/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1121 +186,87 @@ -
    +
    + + + +
    +
    +
    + + +

    XLang DSL Plugin

    -
    +

    在Nop平台中,所有的DSL都采用XML语法格式,使用统一的xdef元模型来提供规范化的形式约束和基本的属性语义。基于xdef元模型,我们可以实现统一的语法提示、关联分析、断点调试等功能,而无需针对每个DSL语言单独编写IDE插件。

    +
    +

    插件的编译、安装可以参考文档: idea.md

    +
    +

    DSL语法格式

    XLang DSL采用XML格式,根节点上必须通过x:schema属性来指定所对应的xdef元模型,例如

    +
    <beans x:schema="/nop/schema/beans.xdef" 
    xmlns:x="/nop/schema/xdsl.xdef" ...>
    </beans>
    +

    语法提示

    输入标签名、属性名、属性值的时候,会弹出xdef中定义的相关信息。

    +

    idea-completion

    +

    语法检查

    插件会根据xdef定义检查标签名、属性名以及属性值的格式。不符合要求的语法元素会被增加Error标记。

    +

    idea-check

    +

    快速文档

    鼠标悬停在标签名、属性名以及属性值上时,会显示xdef文件中定义的文档
    idea-quick-doc

    +

    路径链接

    鼠标悬停在路径格式的属性值上,同时按CTRL键,会提示跳转到路径所对应的文件。
    对于XPL模板标签,则提示跳转到标签库的定义处。
    idea-link

    +

    断点调试

    在XScript脚本或者Xpl模板片段中可以增加断点。
    插件增加了一个与Run和Debug指令平级的执行器XLangDebug,通过它启动后会同时启动Java调试器和启动XLang脚本语言调试器。

    +

    idea-executor

    +

    xlang-debugger

    +

    为了调试XLang,需要引入nop-xlang-debugger模块

    +
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-xlang-debugger</artifactId>
    <version>2.0.0-SNAPSHOT</version>
    </dependency>
    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    XLang DSL Plugin

    - - - - -
    -

    在Nop平台中,所有的DSL都采用XML语法格式,使用统一的xdef元模型来提供规范化的形式约束和基本的属性语义。基于xdef元模型,我们可以实现统一的语法提示、关联分析、断点调试等功能,而无需针对每个DSL语言单独编写IDE插件。

    -
    -

    插件的编译、安装可以参考文档: idea.md

    -
    -

    DSL语法格式

    XLang DSL采用XML格式,根节点上必须通过x:schema属性来指定所对应的xdef元模型,例如

    -
    <beans x:schema="/nop/schema/beans.xdef" 
    xmlns:x="/nop/schema/xdsl.xdef" ...>
    </beans>
    - -

    语法提示

    输入标签名、属性名、属性值的时候,会弹出xdef中定义的相关信息。

    -

    idea-completion

    -

    语法检查

    插件会根据xdef定义检查标签名、属性名以及属性值的格式。不符合要求的语法元素会被增加Error标记。

    -

    idea-check

    -

    快速文档

    鼠标悬停在标签名、属性名以及属性值上时,会显示xdef文件中定义的文档
    idea-quick-doc

    -

    路径链接

    鼠标悬停在路径格式的属性值上,同时按CTRL键,会提示跳转到路径所对应的文件。
    对于XPL模板标签,则提示跳转到标签库的定义处。
    idea-link

    -

    断点调试

    在XScript脚本或者Xpl模板片段中可以增加断点。
    插件增加了一个与Run和Debug指令平级的执行器XLangDebug,通过它启动后会同时启动Java调试器和启动XLang脚本语言调试器。

    -

    idea-executor

    -

    xlang-debugger

    -

    为了调试XLang,需要引入nop-xlang-debugger模块

    -
    <dependency>
    <groupId>io.github.entropy-cloud</groupId>
    <artifactId>nop-xlang-debugger</artifactId>
    <version>2.0.0-SNAPSHOT</version>
    </dependency>
    -
    - -
    - - -
    - diff --git a/projects/nop-entropy/docs/user-guide/index.html b/projects/nop-entropy/docs/user-guide/index.html index b89eab6..ecc675f 100644 --- a/projects/nop-entropy/docs/user-guide/index.html +++ b/projects/nop-entropy/docs/user-guide/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1104 +186,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/user-guide/installation/index.html b/projects/nop-entropy/docs/user-guide/installation/index.html index 06b836d..a5fb85d 100644 --- a/projects/nop-entropy/docs/user-guide/installation/index.html +++ b/projects/nop-entropy/docs/user-guide/installation/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1143 +186,109 @@ -
    +
    - -
    + - - - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    -
    -
    - - -

    安装教程

    - - - - -
    -

    环境准备: JDK 17+、Maven 3.9.3+、Git

    -
    git clone https://gitee.com/canonical-entropy/nop-entropy.git
    cd nop-entropy
    mvn clean install -DskipTests -Dquarkus.package.type=uber-jar
    - -

    注意: 编译运行需要JDK17以上版本,不支持JDK8, 在PowerShell中执行的时候需要用引号将参数包裹起来

    -

    据反馈,有些JDK版本编译会报错,如jdk:17.0.9-graal会报错IndexOutOfBound异常,所以如果编译出现问题时可以先尝试一下OpenJDK。

    -
    mvn clean install "-DskipTests" "-Dquarkus.package.type=uber-jar"
    - -

    quarkus.package.type参数是quarkus框架所识别的一个参数,指定它为uber-jar将会把nop-quarkus-demo等项目打包成一个包含所有依赖类的单一jar包。可以通过java
    -jar XXX-runner.jar的方式直接运行。

    -

    PowerShell乱码问题解决

    可以将PowerShell的编码设置为UTF8

    -
    $OutputEncoding = [Console]::OutputEncoding = [Text.Encoding]::UTF8
    - -

    目前已经升级到quarkus3.0版本,用低版本maven运行nop-auth-app等模块可能会失败。建议升级到maven
    3.9.3版本,或者使用nop-entropy跟目录下的mvnw指令,它会自动下载并使用maven 3.9.3。

    -
      -
    • nop-idea-plugin
      nop-idea-plugin是IDEA的插件项目,必须采用Gradle编译。
    • -
    -
    cd nop-idea-plugin
    gradlew buildPlugin
    - -
    -

    目前使用的idea打包插件不支持高版本gradle。gradlew会自动下载所需的gradle版本,目前使用的是7.5.1
    如果想加快gradle下载速度,可以gradle-wrapper.properties中换成
    distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-7.5.1-bin.zip

    -
    -

    编译出来的插件存放在build/distributions目录下。参见插件的安装和使用

    -

    使用说明

      -
    • 平台内置了一个演示程序,使用H2内存数据库,可以直接启动运行
    • -
    -
    cd nop-demo/nop-quarkus-demo/target
    java -Dquarkus.profile=dev -jar nop-quarkus-demo-2.0.0-SNAPSHOT-runner.jar
    - -
    -

    如果不指定profile=dev,则会以prod模式启动。prod模式下需要配置application.yaml中的数据库连接,缺省使用本机的MySQL数据库

    -
    -
      -
    • 访问链接 http://localhost:8080用户名:nop, 密码:123

      -
    • -
    • 在IDEA中可以调试运行nop-quarks-demo项目中的QuarksDemoMain类。
      quarkus框架在开发期提供了如下调试工具,

      -
    • -
    -
    -

    http://localhost:8080/q/dev
    http://localhost:8080/q/graphql-ui

    -
    -

    在graphql-ui工具中可以查看所有后端服务函数的定义和参数。

    - -
    - -
    - -
    - diff --git a/projects/nop-entropy/docs/user-guide/monitor/grafana/index.html b/projects/nop-entropy/docs/user-guide/monitor/grafana/index.html index 8cea7de..2383818 100644 --- a/projects/nop-entropy/docs/user-guide/monitor/grafana/index.html +++ b/projects/nop-entropy/docs/user-guide/monitor/grafana/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/user-guide/report-qrcode/index.html b/projects/nop-entropy/docs/user-guide/report-qrcode/index.html index b2bc2f7..ac5a16c 100644 --- a/projects/nop-entropy/docs/user-guide/report-qrcode/index.html +++ b/projects/nop-entropy/docs/user-guide/report-qrcode/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/user-guide/report/index.html b/projects/nop-entropy/docs/user-guide/report/index.html index 5b0f4df..e80b5d8 100644 --- a/projects/nop-entropy/docs/user-guide/report/index.html +++ b/projects/nop-entropy/docs/user-guide/report/index.html @@ -73,1172 +73,125 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    + + - + + +
  • English +
  • + + + + + + + + + +
    -
    -
    +
    -
    - diff --git a/projects/nop-entropy/docs/user-guide/rule/index.html b/projects/nop-entropy/docs/user-guide/rule/index.html index 528d0f2..d630964 100644 --- a/projects/nop-entropy/docs/user-guide/rule/index.html +++ b/projects/nop-entropy/docs/user-guide/rule/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1106 +189,72 @@ -
    +
    + + + +
    + - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    +
    + - - - -
  • - - - - - - - - - - - - - 软件架构 - - - - - -
  • - -
  • - - - - - - - - - - - - - 理论基础 - - -
  • - -
  • - - - - - - - - - - - - - 开发指南 - - - - - -
  • - -
  • - - - - - - - - - - - - - 第三方集成 - - - - - -
  • - -
  • - - - - - - - - - - - - - IDEA插件 - - - - - -
  • - -
  • - - - - - - - - - - - - - 常见问题 - - - - - -
  • - - - - - -
    - - - -
    - diff --git a/projects/nop-entropy/docs/user-guide/workflow/index.html b/projects/nop-entropy/docs/user-guide/workflow/index.html index 44abb2c..fda9b3e 100644 --- a/projects/nop-entropy/docs/user-guide/workflow/index.html +++ b/projects/nop-entropy/docs/user-guide/workflow/index.html @@ -76,30 +76,6 @@ - - - - - - - - - - - - - - - - @@ -213,1104 +189,70 @@ -
    +
    - -
    + + - - diff --git a/projects/nop-entropy/docs/why-nop/index.html b/projects/nop-entropy/docs/why-nop/index.html index dc29598..478030f 100644 --- a/projects/nop-entropy/docs/why-nop/index.html +++ b/projects/nop-entropy/docs/why-nop/index.html @@ -73,30 +73,6 @@ - - - - - - - - - - - - - - - - @@ -210,1137 +186,103 @@ -
    +
    + + + +
    +
    +
    + + +

    Nop平台的定位和发展规划

    -
    +

    Nop平台是基于可逆计算理论从零开始构建的,支持面向语言编程范式的新一代低代码平台,它在基本的软件构造原理层面突破了传统的面向对象和组件理论的限制,可以实现系统级别的粗粒度的软件复用。
    Nop平台于2023年3月开源,至今已经有近一年左右的时间,逐渐的开始有一些同学将它用在自己的项目中,或者基于它的基本理念重构自己的低代码技术产品。在这种情况下,
    有些人可能比较关心Nop平台未来的发展规划是什么,它作为开源项目的可持续性怎么样?在本文中,我将针对一些常见的问题做一个解答。

    +

    一. Nop平台未来是否会发布商业版?

    Nop平台本身没有商业化目标,所以未来也不会发布商业版本,所有代码都会保持完整开源。在版权协议方面,Nop平台的前端(nop-chaos)采用MIT协议,后端(nop-entropy)采用AGPL协议,但是增加了对中小企业的商业豁免,允许中小企业在类似Apache2.0协议的情况下使用Nop平台
    (Apache2.0协议允许修改源码并免费商用,修改的部分可以保持闭源,但是要求保留所有源码文件中的原作者信息)。我的本意是采用对中小企业更加友好的协议,最好是能促进中小企业之间的协作。

    +

    Nop平台的实现集中在后台,主要关注点是提供基本的软件构造原理支持,不会增加大量的应用层的功能特性。如果有比较细致的商业特性需求,建议自行通过模块扩展、Delta定制等机制对平台功能进行商业化增强。
    Nop平台的前台目前采用了百度AMIS框架作为缺省的页面渲染框架,整体美观程度和易用程度作为商业产品都有所欠缺,如果对前端要求较高,建议只使用Nop平台的后端。具体配置可以参考Nop入门:极简服务层开发等文章,
    在B站上也提供了大量视频演示如何只使用Nop平台的部分模块。

    +
    +

    网友glennxu和悠闲的水贡献了部分前端代码,前端经过重构后会采用动态插件架构,允许使用华为的opentiny等前端框架作为渲染引擎,以后不会强制要求使用百度AMIS。

    +
    +

    Nop平台具有远超现有框架技术的可扩展性,一般的二次开发定制需求都可以在不修改平台基础源码的情况下,通过增加独立的Delta模块实现。具体技术方案介绍参见如何在不修改基础产品源码的情况下实现定制化开发

    +

    如果有通用的功能特性需求,可以在gitee上提交issue。对于确实是广泛使用的共性需求,我会在技术层面提供免费支持,但是我个人不会进行付费的商业化开发,所有我实现的特性需求都会作为开源代码发布。

    +

    二. Nop平台的研发团队情况如何?能否保证持续性改进?

    NopPlatform 2.0的前后端代码全部由我一个人编写完成。其中后端项目nop-entropy目前包含15万行左右手写的Java代码(另外有10多万行自动生成的代码和拷贝的开源代码),
    预计最终会达到20万行的手写代码量,并稳定在这个量级。

    +

    Nop平台中使用的技术方案经历了二十多年的发展,并在大量软件产品、项目中经过验证,早已形成一整套标准化的软件架构模式。Nop平台的具体实现代码经历了Witrix平台、Entropy平台和现在的Nop平台等多个发展阶段,并经过多次彻底的重构。
    在此前的实现中,受限制于产品研发的时间和资源限制,有些能够依据可逆计算理论进行自动化推理的部分是依靠手工编码实现,
    另外因为可逆计算理论比较抽象,大部分人难以充分理解,或者理解之后也找不到简洁的技术方案去实现,因此实际实现的时候往往没有达到我的预期。
    在最新的实现中,我删除了所有其他人所写的代码,从零开始重新实现了一遍。经过近三年多的重写,现在的实现比较严格的遵循了可逆计算理论,在概念一致性方面大大超越了业内主流的开源框架。

    +

    Nop平台的模块结构在2024年应该会基本稳定下来,并为AIGC(人工智能集成)提供比较良好的架构基础。后续我会提供持续的架构改进和开源技术支持。同时,我也支持
    第三方基于Nop平台提供商业化封装,真正实现具有商业价值的技术产品

    +

    因为基于创新的软件构造原理,Nop平台的代码在实现同样的功能时,比开源框架的代码量要下降一个数量级,更加容易被理解和掌握。例如Nop平台通过3000多行代码就实现
    了分布式RPC调用,参见低代码平台中的分布式RPC框架。通过3000多行代码实现了完整的中国式报表展开引擎,
    参见采用Excel作为设计器的开源中国式报表引擎:NopReport。所以,有能力的技术团队完全可以全面掌握Nop平台的所有技术细节。
    总的来说,Nop平台的总体技术复杂度会限制在单个程序员可以彻底掌握所有细节的水平上(毕竟它的开发就是由单个程序员操刀完成的)。

    +

    三. Nop平台的性能怎么样?能否支持高并发、大规模的复杂应用?

    Nop平台在性能方面领先于主流的Spring框架。这种领先源于两个方面:

    +

    1. 软件构造原理方面的领先优势

    Nop平台基于可逆计算理论大量使用编译期转换和即时编译,因此很多传统框架需要在运行期执行的复杂判断逻辑在Nop平台中都被转移到了编译期,大量复杂的模型抽象并不会导致额外的性能损失。

    +

    2. 实现层面的后发优势

    Nop平台是最近几年彻底从零开始构建的新一代框架,因此它可以吸取此前其他框架多年发展后得到的经验教训,集中精力优化少数真正常用的代码执行路径。而传统的框架诞生于多年以前,兼容性的拖累使得它们总是要在运行时执行很多额外的多余动作。
    比如说,NopGraphQL引擎可以同时对外提供GraphQL和REST两种形式的接口服务,其中REST方式下统一采用JSON格式进行请求数据和响应数据的编解码,而SpringMVC框架出于兼容性的考虑,不得不在框架内包含多种编码策略,并在运行时执行很多多余的判断。
    传统的Web框架不可能同时支持GraphQL和REST协议,如果单独通过graphql-java来暴露GraphQL服务,则必然会引入大量重复的格式转换和接口适配工作。

    +

    另外一方面,现有的工作流引擎、IoC引擎、ORM引擎、Web引擎、规则引擎、批处理引擎等都是各个开源团队分别设计并实现,然后由Spring再次进行封装整合到统一的框架中,
    这导致这些引擎底层存在大量概念重复,它们在协同工作时也需要经过非常冗长的适配接口。进行扩展的时候我们不得不学习各个框架不同风格的扩展机制,并学会处理这些框架之间潜在的实现冲突。
    在Nop平台中,所有的框架采用相同的XDef元模型描述,并且在XDSL层面通过统一的Delta差量化机制来实现自定义扩展,因此它可以减少很多信息转换损耗,并用最小的成本实现多个引擎的无缝集成。

    +

    笔者本人所在的公司是银行核心系统的软件提供商,笔者对于高并发、高复杂度的toB软件开发颇有心得,也有很多国产化信创软件产品的开发经验,因此Nop平台对于高性能以及高复杂度的toB软件产品开发已经内置了很多支持,并在实践中经历了大量验证。

    +

    四. Nop平台对于各类技术标准的支持完整度如何?能否与第三方微服务协同工作?

    Nop平台的所有核心功能都没有采用第三方开源组件,全部都是从零开始编写实现。比如说,它的XML解析没有使用第三方XML解析库,而是在nop-core模块中自行实现了一个XNodeParser。再比如它在实现graphql协议时没有使用开源的graphql-java框架,
    而是自己编写GraphQLDocumentParser,并实现了一个采用诸多创新设计的GraphQLEngine。有些人可能会有疑问:如果不使用这些第三方库,如何保证自己的实现与外部的标准(如GraphQL协议标准)百分百兼容呢?
    对于这个问题,Nop平台的回答是:无法做到百分百兼容,也没有必要做到。这里的原因分为三个方面:

    +

    首先是实现成本方面的考量

    因为整个Nop平台的核心代码由我一人完成,所以在技术标准方面我只会采用一种保守的技术策略:Nop平台只使用标准中与可逆计算理论兼容的某个子集部分,并不追求对标准各个细节的覆盖
    以NopGraphQL引擎为例,它对外提供标准的GraphQL服务,可以使用第三方的graphiql开发工具进行调试,也可以与SpringCloud微服务框架协同工作。但是,NopGraphQL并不支持GraphQL标准中的所有细节,也没有核对过GraphQL协议支持的完整度有多高。
    它对GraphQL标准的实现程度由NopGraphQL引擎实际使用过程中用到的部分来决定,没有发现实际用途的特性在现在的代码中并不会实现。类似的,在NopReport报表引擎的实现中,表达式中支持的Excel函数只包含最常见的几个函数,并不会像商业产品那样提供几百个Excel兼容的表达式函数。

    +

    如果确有需求,建议自行编写插件来实现扩展的各类要求。(Nop平台的核心模块中都内置了各个抽象层面的plugin接口,可以按照自己的需要进行扩展)。

    +

    总的来说,目前的主流技术架构对于异构系统集成已经有了比较成熟的解决方案,Nop平台对外暴露的接口一致性非常高,很容易适配到各类外部接口标准,从而形成一个完整的服务集群。但是对于原标准中应对各种小众需求的特性,Nop平台并不使用,因此也就并不支持。

    +

    第二是安全性和最佳实践的考量

    一般的技术标准中对同一个功能往往会提供多种可选的实现途径,但是它们的安全性和易用性各不相同。真正在实践中,我们往往只会推荐少数的最佳实践方案,但是出于兼容性考虑,标准内部会保留大量不符合最佳实践的技术途径,这也会导致在无意中引入安全性漏洞。

    +

    因为笔者长期从事的是高端、复杂的大型软件系统的研发,对于安全性、合规性等有着较高要求,所以在Nop平台中一般只会保留安全性较高、符合目前最佳实践标准的功能特性。比如说XML标准中包含自定义Entity的内容,但是它很容易引入安全性bug,此前在世界范围内亚马逊、谷歌、腾讯、阿里等大公司都出现过
    XML解析器导致的0day bug,原因就在于这些很少有人使用但是又内置在标准中的复杂特性。Nop平台选择是只支持XML标准中最常用的一个子集,放弃所有需要加载外部实体对象的技术特性,从而在根源上杜绝此类bug的发生。

    +

    Nop平台的实现中对安全性进行了大量加强,比如GraphQL语句的长度、其中包含的操作个数、允许的嵌套层次等都具有缺省限制(可以通过配置参数调整),确保在缺省情况下满足相当高的安全性标准,可以抵抗常见的注入攻击、资源耗尽攻击等。

    +

    第三也是最重要的是,创新的设计不应受到已有形式的约束

    可逆计算理论是下一代的软件构造理论,Nop平台是可逆计算理论指导下实现的下一代的软件开发平台。所以,Nop平台所关注的是目前的软件框架技术所无法达到的、目前尚属空白的软件设计空间。
    它的重点是在无人区中探索新的软件结构构造规律,提出创新的技术解决方案,解决前人从未能够解决的技术难题,因此它的实现不会受到目前的技术标准的限制,甚至可以说它压根就不在意对现有技术标准的兼容性。
    如果标准中的特性定义与可逆计算理论兼容,则可以直接采用。如果在可逆计算的实践中用不上甚至有冲突,则所谓的标准并不会被纳入考量。
    整个Nop平台的研发过程就是扛着炸药包上路,逢山炸山,遇水填河,大道朝天,一路向前。

    +

    传统上的设计大都只是是满足于解决当前的业务问题,但是Nop平台它所需要解决的问题范围却包括跨系统、跨软件生命周期的整体演化问题。
    因此Nop平台对信息表述的完整性和局部可分析性的重视大大超过了对于所谓强大功能的追求,它也必然会对已有的技术形式中无法满足可逆计算要求的部分进行改造。

    +

    五. Nop平台的发展定位是什么?

    首先必须强调的是,Nop平台的定位绝对不是一个大众化的流行框架。我研发Nop平台的主要目的是作为可逆计算理论的参考实现,从而澄清可逆计算理论中的一些技术思想。
    它的一个副作用是基于整个业内最新的一些技术认知,提供当前和未来一段时间内的最佳实践,促进对新的软件架构模式的思考,提升国内软件架构设计的整体水平。所以,Nop平台不会成为一个
    开箱即用、用户友好,在细节上精细打磨的开发框架,它也不会成为一个成熟的、可以立刻创造商业价值的软件产品。

    +

    在实用的意义上,Nop平台的定位是一个基于新的软件构造原理的技术底座。如果你想开发一个类似Mendix、OutSystems这样具有广泛适应性的通用型低代码产品,想与世界上最优秀的技术产品竞争,
    可以考虑在底层使用Nop平台或者借鉴它的原创设计,节省你自己的开发时间。良好的产品设计加上Nop平台领先的原理架构,可以起到事半功倍的作用。

    +

    Nop平台规划中的组件以及它们的开发进度在README.md文件中已经有详细的列举,
    预计在2024年至2025年完成这些组件的开发,并正式发布到maven中心仓库。

    +

    题外的话

    黑客之王Linus Torvalds说,talk is cheap, show me the code。Nop平台已经全部开源,源码就在那里,一切疑惑和争议都在源码中可以获得解答。

    +

    有趣的是,国内现在很多人不想看code,更不耐烦去理解别人的思想,只想让人show me the money(用这个平台能挣钱吗?挣到钱了吗?)。说实话,这不是符合黑客精神的交流方式。
    更有趣的是,最喜欢在朋友圈发文批判国内实用化思想泛滥、不能沉下心来做技术研究、中国的技术落后是源于思想落后,开口闭口国家堵住了他的创新之路的人,恰恰是开口闭口不离money的同一伙人。
    对于这种精神分裂现象,我只能理解为没挣到钱之后急得有点面红耳赤,语无伦次了。

    +

    很多人觉得可逆计算这个名词听起来过于高大上,像是民科的做派,再听说作者几乎从不翻墙,很少阅读国外的技术文献之后更是感到不可思议。有人就想问,2024年了,作者家还没联网吗?这是闭门造车吗?
    这里可以解释一下,作者虽然不翻墙,但是他读各类开源软件的源码啊,一般尽量通过源码而不是别人的文章来了解相关的技术内容。另外作者的学术背景是理论物理学,受过良好的理论科班训练,平时也多阅读数理相关的文献。
    可逆计算理论的起因就是作者尝试将物理学的思想引入软件工程领域所做的有意识的努力。作者之所以能够发明一些原创的技术方案,恰在于他的思想没有像计算机科班的同学那样受到传统思想的束缚。
    目前一般程序员对于抽象的理论知识的了解程度限制在大学本科水平,基本是停留在牛顿和莱布尼兹的时代,如果不努力提升自己对抽象知识的理解能力,那么即使是将互联网上所有的计算机相关的信息一网打尽,
    那也是与人类世界最近200多年最优秀的头脑所发现的知识世界无缘的。

    +

    有些同学反映可逆计算理论难以理解,这也是一种正常现象。因为大部分人并不真的需要理论解释,本身都是在别人的规范下工作,只是自己脑补一下这样做的好处而已
    (正如大部分人并不需要理解抽象的关系模型就可以熟练使用关系数据库)。而Nop平台的做法是创造自己的规范,所以对一般人来说和说天书也没什么区别。有兴趣的话,只看代码就好了。

    -
    - - -
  • - - - - - - - - - - - - 文档概览 - - -
  • - -
  • - - - - - - - - - - - - - 入门教程 - - -
      - - + +
  • +
    + - -