

Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9332.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验


Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9332.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验
函数的触发和定时在很多场景中会用到,也是一个oinone的基础能力。比如我们的流程产品中在定义流程触发时就会让用户选择模型触发还是时间触发,就是用到了函数的触发与定时能力。 整体链路示意图(如下图4-1-10-1 所示),本文只讲trigger里的两类任务,一个是触发任务,一个是定时任务,异步任务放在4.1.11【函数之异步执行】一文中单独去介绍。 图4-1-10-1 整体链路示意图 一、触发任务TriggerTaskAction(举例) 触发任务的创建,使用pamirs-middleware-canal监听mysql的binlog事件,通过rocketmq发送变更数据消息,收到MQ消息后,创建TriggerAutoTask。 触发任务的执行,使用TBSchedule拉取触发任务后,执行相应函数。 注意:pamirs-middleware-canal监听的数据库表必须包含触发模型的数据库表。 Step1 下载canal中间件 下载pamirs-middleware-canal-deployer-3.0.1.zip,去.txt后缀为pamirs-middleware-canal-deployer-3.0.1.zip,解压文件如下: 图4-1-10-2 下载canal中间件 Step2 引入依赖pamirs-core-trigger模块 pamirs-demo-api增加pamirs-trigger-api <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-api</artifactId> </dependency> 图4-1-10-3 pamirs-trigger-api依赖包 DemoModule在模块依赖定义中增加@Module(dependencies={TriggerModule.MODULE_MODULE}) @Component @Module( name = DemoModule.MODULE_NAME, displayName = "oinoneDemo工程", version = "1.0.0", dependencies = {ModuleConstants.MODULE_BASE, CommonModule.MODULE_MODULE, UserModule.MODULE_MODULE, TriggerModule.MODULE_MODULE} ) @Module.module(DemoModule.MODULE_MODULE) @Module.Advanced(selfBuilt = true, application = true) @UxHomepage(PetShopProxy.MODEL_MODEL) public class DemoModule implements PamirsModule { ……其他代码 } 图4-1-10-4 模块依赖中增加Trigger模块 pamirs-demo-boot 增加pamirs-trigger-core和pamirs-trigger-bridge-tbschedule的依赖 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-bridge-tbschedule</artifactId> </dependency> 图4-1-10-5 增加pamirs-trigger-core和pamirs-trigger-bridge-tbschedule的依赖 修改pamirs-demo-boot的applcation-dev.yml 修改pamris.event.enabled和pamris.event.schedule.enabled为true pamirs_boot_modules增加启动模块:trigger pamirs: event: enabled: true schedule: enabled: true rocket-mq: namesrv-addr: 127.0.0.1:9876 boot: init: true sync: true modules: – base – common – sequence – resource – user – auth – message – international – business – trigger – demo_core 图4-1-10-6 启动模块中增加trigger模块 Step3 启动canal中间件 canal的库表需要手工建 create schema canal_tsdb collate utf8mb4_bin 图4-1-10-7 canal的建库语句 CREATE TABLE IF NOT EXISTS `meta_snapshot` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `gmt_create` datetime NOT NULL COMMENT '创建时间', `gmt_modified` datetime NOT NULL COMMENT '修改时间', `destination` varchar(128) DEFAULT NULL COMMENT '通道名称', `binlog_file` varchar(64) DEFAULT NULL COMMENT 'binlog文件名', `binlog_offest` bigint(20) DEFAULT NULL COMMENT 'binlog偏移量', `binlog_master_id` varchar(64) DEFAULT NULL COMMENT 'binlog节点id', `binlog_timestamp` bigint(20) DEFAULT NULL…
我们常说“在今天所有的不确定性当中,数字化是最大的确定性”,数字化一定会全面改造所有的行业更是确定的。在菜鸟九年的探索中,我们最大的感受是“未来,任何一个物流企业都会是一个技术公司,真正拉开差距的是:技术与实体产业的结合有多深”。菜鸟“简单极致,贴地疾飞”的技术文化也深刻体现了这一点——好的技术要能解决实际问题。数字化并不是简单地上线一个或几个系统,这是一个贴近业务持续迭代的过程,伴随着这个过程,我相信会诞生非常多的创新技术。 在本书中我看到了工程思维在推进技术创新的缩影,把难的问题转化为简单的问题,用成熟实用的技术分而解之。高性能的微服务框架、CDM、元数据、低代码、无代码等,都是当下非常热门的技术课题,Oinone把这一切都有机地结合起来,形成了一种具备先进理念的全新一代软件产品,每一个特性都贴合企业数字化遇到的实际问题。Oinone的产品设计,把“大道至简,软件自造”贯穿始终,用最简单的方式,帮助企业驾驭数字化,相信会给企业带来不一样的体验。 就跟本书提到的“「企业视角由内部管理转向业务在线、生态在线(协同)带来一系列新的诉求」这一大背景下,以及云、端等新技术的发展,对研发人员的需求越来越大,同时要求越来越高,低代码平台是提升研发效率,降低研发成本的核心手段”,低代码已经不是需不需要的问题,而是怎么选的问题。菜鸟网络自身也在推进自有低代码开发平台,我们有幸邀请本书作者陈鹏程来到菜鸟网络进行了分享交流,收获非常大。如您正在选型低代码开发平台,向您推荐这本书,低无一体的Oinone肯定会打动您。 菜鸟网络CTO李强(在宽)
在分布式开发中,每个人基本只负责自己相关的模块开发。所以每个研发就都需要一个环境,比如一般公司会有(N个)项目环境、1个日常环境、1个预发环境、1个线上环境。在整项目环境的时候就特别麻烦,oinone的好处是在于每个研发可以通过boot工程把需要涉及的模块都启动在一个jvm中进行开发,并不依赖任何环境,在项目开发中,特别方便。但当公司系统膨胀到一定规模,大到很多人都不知道有哪些模块,或者公司出于安全策略考虑,或者因为启动速度的原因(毕竟模块多了启动的速度也会降下来)。本文就给大家介绍oinone与经典分布式组织模式的兼容性 一、模块启动的最小集 我们来改造SecondModule模块,让该模块的用户权限相关都远程走DemoModule Step1 修改SecondModule的启动工程application-dev.yml文件 除了base、second_core两个模块保留,其他模块都去除了。 pamirs: boot: init: true sync: true modules: – base – second_core 图4-4-1 SecondModule的application-dev.yml仅配置两个模块 Step2 去除boot工程的依赖 去除SecondModule启动工程的pom依赖 <!– <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-resource-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-user-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-auth-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-message-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-international</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-business-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-apps-core</artifactId> </dependency> –> 图4-4-2 去除boot工程多余的依赖 Step3 重启SecondModule 这【远程模型】和【远程代理】均能访问正常 图4-4-3 远程模型和远程代理菜单均能访问正常 Step4 SecondModule增加对模块依赖 我们让SecondModule增加用户和权限模块的依赖,期待效果是:SecondModule会对用户和权限的访问都会走Dome应用,因为Demo模块的启动工程中包含了user、auth模块。 修改pamirs-second-api的pom文件增加对user和auth的api包依赖 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-user-api</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-auth-api</artifactId> </dependency> 图4-4-4 修改pamirs-second-api的pom文件 修改SecondModule类,增加依赖定义 @Module( dependencies = {ModuleConstants.MODULE_BASE, AuthModule.MODULE_MODULE, UserModule.MODULE_MODULE} ) 图4-4-5 配置SecondModule的依赖 Step5 修改RemoteTestModel模型 为RemoteTestModel模型增加user字段 @Field.many2one @Field(displayName = "用户") private PamirsUser user; 图4-4-6 为RemoteTestModel模型增加user字段 Step6 重启系统看效果 mvn install pamirs-second工程,因为需要让pamirs-demo工程能依赖到最新的pamirs-second-api包 重启pamirs-second和pamirs-demo 两个页面都正常 图4-4-7 示例效果一 图4-4-8 示例效果二 二、PmetaOnline的NEVER指令(开发时环境共享) 我们在4.1.2【模块之启动指令】一文中介绍过 “-PmetaOnline指令”,该参数用于设置元数据在线的方式,如果不使用该参数,则profile属性的默认值请参考服务启动可选项。-PmetaOnline参数可选项为: NEVER – 不持久化元数据,会将pamirs.boot.options中的updateModule、reloadMeta和updateMeta属性设置为false MODULE – 只注册模块信息,会将pamirs.boot.options中的updateModule属性设置为true,reloadMeta和updateMeta属性设置为false ALL – 注册持久化所有元数据,会将pamirs.boot.options中的updateModule、reloadMeta和updateMeta属性设置为true oinone的默认模式下元数据都是注册持久化到DB的,但当我们在分布式场景下新开发模块或者对已有模块进行本地化开发时,做为开发阶段我们肯定是希望复用原有环境,但不对原有环境照成影响。那么-PmetaOnline就很有意义。让我们还没有经过开发自测的代码产生的元数据仅限于开发本地环境,而不是直接影响整个大的项目环境 PmetaOnline指令设置为NEVER(举例) Step1 为DemoCore新增一个DevModel模型 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(DevModel.MODEL_MODEL) @Model(displayName = "开发阶段模型",summary="开发阶段模型,当PmetaOnline指令设置为NEVER时,本地正常启动但元数据不落库",labelFields={"name"}) public class DevModel extends AbstractDemoCodeModel{ public static final String MODEL_MODEL="demo.DevModel"; @Field(displayName = "名称") private String name; } 图4-4-9 为DemoCore新增一个DevModel模型 Step2 为DevModel模型配置菜单 @UxMenu("开发模型")@UxRoute(DevModel.MODEL_MODEL) class DevModelProxyMenu{} 图4-4-10 为DevModel模型配置菜单 Step3 启动Demo应用时指定-PmetaOnline 图4-4-11 启动Demo应用时指定-PmetaOnline Step4 重启系统看效果 查看元数据 图4-4-12 DB查看元数据变化 菜单与页面能正常操作 图4-4-13 开发模型菜单可正常操作 图4-4-14 开发模型详情页面可正常操作 Step5 Never模式需注意的事项 业务库需设定为本地开发库,这样才不会影响公共环境,因为对库表结构的修改还是会正常进行的 如果不小心影响了公共环境,需要对公共环境进行重启恢复 系统新产生的元数据(如:例子中的【开发模式】菜单)不受权限管控 三、分布式开发约定 设计约定 跨模块的存储模型间继承,在部署时需要跟依赖模块配置相同数据源。这个涉及模块规划问题,比如业务上的user扩展模块,需要跟user模块一起部署。…
模块(module) 概念 在 Oinone 系统的架构中,模块(module)是核心组成元素之一,可以被理解为域(domain)的一个具象化概念。模块的来源有两种:一种是基于后端代码定义,另一种是通过无代码新增。具体的代码定义方式,请参考“[占位符]”,而无代码定义的相关信息则可在“[占位符]”找到。在 Oinone 体系中,模块对应两种实体:模块和应用。 模块: 这是一类特定能力的集合,它可以依赖其他模块,也可以被其他模块依赖。 应用: 它是一种特殊的模块,具备模块的所有特性,并在此基础上可被终端用户访问。 使用 在前端开发中,module通常以应用的形式出现,它们往往对前端用户保持透明。在接下来的讨论中,我们主要围绕应用来探讨module的使用。从应用的角度出发,我们可以在前端开发中识别出以下几种典型使用场景,并通过具体的业务案例来加以说明 应用菜单扩展: 实现自定义母版来定义特定应用的菜单 表格布局扩展: 用于自定义布局的工具,以定义特定应用的表格布局 在这些场景中,我们着重实现了应用层面的隔离,确保每个模块都能在应用的维度上独立运作 查找 在实际业务开发中,有3个方式可以找到应用 浏览器url查找(查找速度快,可能不准) 图3-5-7-1 浏览器url查找模块(module) 接口返回查找 第一步找到截图类似请求 图3-5-7-2 接口找到viewActionQuery 第二步根据返回找应用 图3-5-7-3 接口返回查找模块(module) vue调试器选中对应的组件查找 图3-5-7-4 vue调试器查找模块(module) 推荐使用浏览器url查找,若与预期不符,可用另外两种方式查找 模型(model) 概念 在 Oinone 系统的架构中,模型(model)是另一个关键核心组成部分。模型在业务层面主要体现之一为数据库的实体表,它是承载业务实现的基础结构。要了解模型的详细介绍,请参考“[占位符]”,前端所用的模型,对应后端代码定义来说,代表的是模型的编码。 关于模型的定义,我们提供了两种方法: 代码定义: 对于需要通过编程实现的模型定义,您可以参考“[占位符]”来了解具体的代码实现方法; 无代码定义:如果您倾向于使用无代码工具来定义模型,具体的操作和流程可以在“[占位符]”中找到 使用 在前端开发中,模型是前端运行的必要条件,以下场景中,模型不直接感知: 视图渲染 页面之间跳转交互 与后端交互 以下场景中,模型会直接决定前端的渲染逻辑 母版扩展:为某模型扩展母版 布局扩展:为某模型扩展布局 页面扩展:为某模型扩展个性化页面 字段扩展: 扩展字段时加上模型的范围 动作扩展: 扩展动作时加上模型的范围 以上场景中,涵盖了前端工作的方方面面,在OInone体系中,模型不止是后端运行得基础,同样也决定了前端如何运行,那这样做有什么好处呢? 前后端几乎不需要联调,联调的协议用模型来承载 前端无需定义路由、权限埋点 查找 在实际业务开发中,有3个方式可以找到模型 浏览器url查找 图3-5-7-5 浏览器url查找模型(model) 接口返回查找 第一步找到类似截图请求 图3-5-7-6 接口找到viewActionQuery 第二步根据返回找模型 图3-5-7-7 接口找到viewActionQuery vue调试器选中对应的组件查找 图3-5-7-8 vue调试器查找模型(model) 动作(action) 概念 动作(action)定义了终端用户得交互,它描述了前端与前端、前端与后端之间的交互。 动作涵盖了前端以下部分: 页面跳转(router) 调用后端接口 页内交互(打开弹窗、打开抽屉) 它有两部分的来源: 模型内定义动作 窗口动作(页面跳转、打开弹窗、打开抽屉) 服务器动作(调接口) 前端定义客户端动作,可自定义其它逻辑,例如: 把选中行的某一列数据复制一下 使用 动作的使用绝大部分的情况是由平台自动执行的,在平台执行不符合预期时可以使用自定义动作自行扩展 查找 vue调试器选中对应的组件查找 选中服务器动作(ServerAction) 图3-5-7-9 vue调试器查找服务器动作(ServerAction) 选中窗口动作(ViewAction) 图3-5-7-10 vue调试器查找窗口动作(ViewAction) 字段(field) 概念 在我们的后端模型中,字段(Field)是核心的定义元素,它们在数据库中表现为数据表的列。更重要的是,这些字段在前端应用中发挥着数据传输的关键作用。例如,当前端需要调用后端接口时,它会发送如下结构的数据: 图3-5-7-11 name字段数据举例 这里的 "name" 是一个字段实例,它连接了前后端的交互。在后端,该字段不仅用于数据存储,也参与逻辑运算。 字段在 Oinone 系统中的加强应用 在 Oinone 系统中,字段的功能得到了扩展。除了基本的前后端数据交互,字段的定义还直接影响前端的用户界面(UI)交互。例如: 前端交互组件的选择:前端交互组件的类型取决于字段的数据类型。对于 String 类型的 "name" 字段,前端会使用输入框来收集用户输入的 "张三"。 数据存储和类型定义:在后端,"name" 字段被明确定义为 String 类型,这决定了它如何存储和处理数据。 字段与前端组件定义的解耦 一个关键的设计原则是,前端组件的定义与具体的字段值或字段名(如 "name" 或 "张三")不直接相关,而是基于字段的数据类型(此例中为 String)。这种设计实现了: 前端组件的一致性:确保所有组件的输入输出遵循同一数据类型(如 String)。 高度的组件复用性:在满足 UI 要求的前提下,任何 String 类型的字段都可以使用这种通用的组件设计。 使用 Oinone 系统中的视图与字段交互的灵活性 Oinone 系统为每种视图和字段类型(Ttype)提供了默认的交互模式。这不仅保证了前端工程启动时所有界面的即时展示,也为开发者带来了高度的灵活性和扩展能力。以下是这一设计理念的关键点: 1. 视图与字段交互的默认实现 每种视图都有对应字段类型(Ttype)的默认交互实现,确保用户界面一致且直观。这使得在前端工程启动时,所有界面能够无需额外配置即可正常展示。 2. 灵活性与扩展能力 尽管系统提供了默认的交互方式,开发者仍然拥有自定义这些交互方式的能力。这意味着开发者可以根据应用需求,设计更加贴合业务逻辑和用户体验的交互模式。 3. 覆盖和替换默认组件 最为重要的是,开发者不仅可以添加新的交互方式,还可以完全覆盖和替换系统的默认组件。这提供了极大的自由度,使开发者能够根据具体场景重新设计和实现界面组件,从而达到完全定制化的用户体验。 查找 vue调试器选中对应的组件查找 图3-5-7-12 vue调试器查找字段(field) 视图类型(viewType) 概念 在 Oinone 系统中,视图是模型在前端的具体表现形式。视图的核心组成和功能如下: 1. 组成要素 字段:视图中的字段代表了模型的数据结构,它们是界面上数据显示和交互的基础。 动作:视图包含的动作定义了用户可以进行的操作,如添加、编辑、删除等。 前端UI:视图的界面设计,包括布局、元素样式等,决定了用户的交互体验。 2. 数据源与交互 数据源:视图的数据直接来源于后端模型。这意味着前端视图展示的内容是根据后端模型中定义的数据结构动态生成的。 交互:视图不仅展示数据,还提供与数据交互的能力。这些交互也是基于后端模型定义的,包括数据的增删改查等操作。 3. 灵活性 视图可以灵活选择是否采用模型的交互。这意味着开发者可以根据需求决定视图仅展示模型的数据,或者同时提供与数据的交互功能。 使用 在 Oinone 系统中,用户可以通过无代码界面设计器轻松配置视图。系统内置了以下主要视图类型: 表格(Table) 表单(Form) 详情(Detail) 搜索(Search) 画廊(Gallery) 树(Tree) 界面设计器配置…
在我们日常开发中经常要一些单据生成指定格式的编码,而且现在分布式环境下要考虑的事情会特别多。oinone提供了简易的编码生成能力 一、编码生成器 可以在模型或者字段上配置编码自动生成规则。在进行数据存储时,如果配置了编码自动生成规则的字段值为空,则系统将根据规则自动生成编码。编码自动生成功能是通过序列生成器来支持的。可以在序列生成器生成的序列编码基础上再进行组合配置的功能编码生成最终的编码。序列生成器可以配置初始序列,步长,日期格式,长度。 模型序列生成器(举例) 使用模型编码生成器,需要继承CodeModel或者有Code字段,那么使用Model.Code注解即可。 Step1 为PetShop增加一个@Model.Code注解,并增加一个店铺编码(Code)字段 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import java.sql.Time; @Model.model(PetShop.MODEL_MODEL) @Model(displayName = "宠物店铺",summary="宠物店铺",labelFields = {"shopName"}) @Model.Code(sequence = "DATE_ORDERLY_SEQ",prefix = "P",size=6,step=1,initial = 10000,format = "yyyyMMdd") public class PetShop extends AbstractDemoIdModel { public static final String MODEL_MODEL="demo.PetShop"; @Field(displayName = "店铺编码") private String code; @Field(displayName = "店铺名称",required = true) private String shopName; @Field(displayName = "开店时间",required = true) private Time openTime; @Field(displayName = "闭店时间",required = true) private Time closeTime; } 图3-3-5-1 为PetShop增加一个@Model.Code注解 Step2 重启查看效果 进入店铺新增页面新增一个oinone宠物店铺003 图3-3-5-2 示例操作效果图 查看店铺列表页面,新增的记录中店铺编码一列,已经按Model.Code注解要求地生成了 图3-3-5-3 示例操作效果图 Step3 小结 在我们日常开发中经常要一些单据生成指定格式的编码,而且现在分布式环境下要考虑的事情会特别多。oinone提供了简易的编码生成能力,大家可以根据编码注解说明,自行对PetShop模型进行不同配置,来学习编码生成器的知识 字段序列生成器 字段编码生成器,在对应的字段上增加,并使用Field.Sequence注解即可 Step1 为PetShop增加一个字段codeTwo并增加@Field.Sequence注解 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import java.sql.Time; @Model.model(PetShop.MODEL_MODEL) @Model(displayName = "宠物店铺",summary="宠物店铺",labelFields = {"shopName"}) @Model.Code(sequence = "DATE_ORDERLY_SEQ",prefix = "P",size=6,step=1,initial = 10000,format = "yyyyMMdd") public class PetShop extends AbstractDemoIdModel { public static final String MODEL_MODEL="demo.PetShop"; @Field(displayName = "店铺编码") private String code; @Field(displayName = "店铺编码2") @Field.Sequence(sequence = "DATE_ORDERLY_SEQ",prefix = "C",size=6,step=1,initial = 10000,format = "yyyyMMdd") private String codeTwo; @Field(displayName = "店铺名称",required = true) private String shopName; @Field(displayName = "开店时间",required = true) private Time openTime; @Field(displayName = "闭店时间",required = true) private Time closeTime; } 图3-3-5-4 为PetShop增加一个字段codeTwo Step2 重启查看效果 进入店铺新增页面新增一个oinone宠物店铺004 图3-3-5-5 示例操作效果图 查看店铺列表页面,新增的记录中店铺编码2一列,已经按Field.Sequence注解要求地生成了 图3-3-5-6 示例操作效果图 二、编码注解说明,模型更多其他注解详见4.1.6【模型之元数据详解】…