4.2.3 框架之SPI机制

SPI(Service Provider Interface)服务提供接口,是一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件,简单来说就是用来解耦,实现组件的自由插拔,这样我们就能在平台提供的基础组件外扩展新组件或覆盖平台组件。

目前定义SPI组件
ViewWidget 视图组件
FieldWidget 字段组件
ActionWidget 动作组件

表4-2-3-1 目前定义SPI组件

前提知识点

1. 通过注解定义一种SPI接口(Interface)

@SPI.Base<IViewFilterOptions, IView>('View', ['id', 'name', 'type', 'model', 'widget'])
export abstract class ViewWidget<ViewData = any> extends DslNodeWidget {

}

图4-2-3-1 代码示意

2. 通过注解注册提供View类型接口的一个或多个实现

@SPI.Base<IViewFilterOptions, IView>('View', ['id', 'name', 'type', 'model', 'widget'])
export abstract class ViewWidget<ViewData = any> extends DslNodeWidget {

}

图4-2-3-2 代码示意

3. 视图的xml内通过配置来调用已定义的一种SPI组件

<view widget="form" model="demo.shop">
  <field name="id" />
</view>

图4-2-3-3 代码示意

4.2.3 框架之SPI机制

图4-2-3-4 组件继承示意图

当有多个服务提供方时,按以下规则匹配出最符合条件的服务提供方

SPI匹配规则

SPI组件没有严格的按匹配选项属性限定,而是一个匹配规则

  1. 按widget最优先匹配,配置了widget等于是指定了需要调用哪个widget,此时其他属性直接忽略

  2. 按最大匹配原则(匹配到的属性越多优先级越高)

  3. 按后注册优先原则

Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9304.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
史, 昂的头像史, 昂数式管理员
上一篇 2024年5月23日 am8:34
下一篇 2024年5月23日 am8:36

相关推荐

  • 2.1 数字化时代软件业的另一个本质变化

    随着企业从信息化向数字化转变,软件公司提供的产品也由传统的企业管理软件向企业商业支撑软件发展。这一变化带来了许多技术上的挑战和机遇。在之前的章节中,我们提到企业的视角已经从内部管理转向业务在线和生态在线协同,这也带来了一系列新的需求。但是,我们常常会忽视这一变化所带来的对系统要求的变化。在本章中,我们将探讨这些技术上的变化,以及这些变化所带来的机遇和挑战。 图2-1 从信息化到数字化软件本质变化 在信息化时代,企业的业务围绕着内部管理效率展开,借鉴国外优秀的管理经验,企业将其管理流程固化下来,典型的例子是ERP项目。这类项目上线后往往长期稳定,不轻易更改,因此信息化时代软件的技术流派侧重于通过模型对业务进行全面支持。例如,SAP具有丰富的配置能力,将已有企业管理思想抽象到极致。其功能基本上可以通过配置来实现,因此其模型设计特别复杂。但是,我们也应该清楚地了解到,配置是面向已知问题的。在数字化时代,创新和业务迭代速度非常快,这种方法可能就不太适合了。我们知道,模型抽象是在设计时具有前瞻性的,一旦不适合,修改起来就会异常困难。 随着数字化时代的到来,企业主的关注点已经从单一企业内部管理转变为了围绕企业上下游价值链的协同展开。这种变化给企业信息化系统提出了更高的要求,例如业务需求的响应速度、系统性能和用户体验等方面。现在,企业对软件不仅是管理需求的承载,更是业务在线化的承载。传统的重模型设计软件模式已经不再适用,因为业务本身不断创新和变化。因此,数字化时代需要新的软件技术流派,这种流派必须是轻模型加上低代码技术的结合体。通过模型抽象80%的通用场景,剩余的20%个性化需求可以通过技术手段来完成。这样的设计可以让每家企业的研发人员轻松理解模型,而不像ERP模型那样异常复杂,无法进行修改。此外,配合低代码技术可以快速研发和上线。如果说配置化是面向已知问题的,那么低代码就是面向未知问题设计的。虽然低代码的概念可以追溯到上个世纪80年代,当时是为了满足企业内部部门之间有协同需求,但又没有专业软件支撑,定制化开发又不划算的辅助场景。但现在它的核心原因是企业数字化的核心场景不稳定,变化很快,每家企业都有强烈的个性化需求。因此,低代码成为解决这些问题的核心手段,数字化时代的低代码需要具备处理复杂场景的能力,而不仅仅是围绕着内部管理展开。 企业在数字化转型的过程中需要考虑到不仅是成熟的全链路业务解决方案,还要应对数字化场景的快速变化和持续创新的需求。为此,Oinone打造了一站式低代码商业支撑平台,从业务与技术两个维度来帮助企业建立开放、链接、安全的数字化平台。这将在水平和垂直两个维度上全面推动企业数字化转型。 另外,低代码的另一个好处是完成了软件本身的数字化建设。通过基于元数据设计,元数据成为软件中数据、逻辑和交互的数据,软件结合AI可以有更多的创造可能。想象一下,AI了解软件的元数据后可以自我运作,人在极少情况下才需要参与,人机交互也会发生大的改变。未来的软件交互不再需要研发提前预设,而是能够实现用户所需即所呈现的效果。作为一家帮助企业进行数字化转型的软件公司,请问您的数字化转型是否已经完成呢?

    2024年5月23日
    89600
  • 6.3 数据审计(改)

    在业务应用中我们经常需要为一些核心数据的变更做审计追踪,记录字段的前后变化、操作IP、操作人、操作地址等等。数据审计模块为此提供了支撑和统一管理。它在成熟的企业的核心业务系统中,需求是比较旺盛的。接下来我们开始学习下数据审计模块 准备工作 pamirs-demo-core的pom文件中引入pamirs-data-audit-api包依赖 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-data-audit-api</artifactId> </dependency> pamirs-demo-boot的pom文件中引入pamirs-data-audit-core和pamirs-third-party-map-core包依赖,数据审计会记录操作人的地址信息,所以也依赖了pamirs-third-party-map-core <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-data-audit-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core.map</groupId> <artifactId>pamirs-third-party-map-core</artifactId> </dependency> pamirs-demo-boot的application-dev.yml文件中增加配置pamirs.boot.modules增加data_audit 和third_party_map,即在启动模块中增加data_audit和third_party_map模块 pamirs: boot: modules: – data_audit – tp_map 为third_party_map模块增加高德接口api,下面e439dda234467b07709f28b57f0a9bd5换成自己的key pamirs: eip: map: gd: key: e439dda234467b07709f28b57f0a9bd5 数据审计 注解式(举例) Step1 新增PetTalentDataAudit数据审计定义类 package pro.shushi.pamirs.demo.core.init.audit; import pro.shushi.pamirs.data.audit.api.annotation.DataAudit; import pro.shushi.pamirs.demo.api.model.PetTalent; @DataAudit( model = PetTalent.MODEL_MODEL,//需要审计的模型 modelName = "宠物达人" ,//模型名称,默认模型对应的displayName //操作名称 optTypes = {PetTalentDataAudit.PETTALENT_CREATE,PetTalentDataAudit.PETTALENT_UDPATE}, fields={"nick","picList.id","picList.url","petShops.id","petShops.shopName"}//需要审计的字段,关系字段用"."连结 ) public class PetTalentDataAudit { public static final String PETTALENT_CREATE ="宠物达人创建"; public static final String PETTALENT_UDPATE ="宠物达人修改"; Step2 修改PetTalentAction的update方法 做审计日志埋点:手工调用 OperationLogBuilder.newInstance().record()方法。需要注意的是这里需要把原有记录的数据值先查出来做对比 @Function.Advanced(type= FunctionTypeEnum.UPDATE) @Function.fun(FunctionConstants.update) @Function(openLevel = {FunctionOpenEnum.API}) public PetTalent update(PetTalent data){ //记录日志 OperationLogBuilder.newInstance(PetTalent.MODEL_MODEL, PetTalentDataAudit.PETTALENT_UDPATE).record(data.queryById().fieldQuery(PetTalent::getPicList).fieldQuery(PetTalent::getPetShops),data); PetTalent existPetTalent = new PetTalent().queryById(data.getId()); if(existPetTalent !=null){ existPetTalent.fieldQuery(PetTalent::getPicList); existPetTalent.fieldQuery(PetTalent::getPetShops); existPetTalent.relationDelete(PetTalent::getPicList); existPetTalent.relationDelete(PetTalent::getPetShops); } data.updateById(); data.fieldSave(PetTalent::getPicList); data.fieldSave(PetTalent::getPetShops); return data; } Step3 重启看效果 修改宠物达人记录对应的字段,然后进入审计模块查看日志

    2024年5月23日
    59400
  • 流程类

    1.流程类 1.1 审批 审批节点配置步骤: 添加审批节点 选择审批的模型和视图 设置审批人和通过方式 设置审批人在审批时的操作权限和数据权限 1.1.1 审批节点 审批节点只能放置在有数据可审批的流程链路上,审批分支只能放置在审批节点后。 1.1.2 审批模型和视图 可选的审批模型包含添加的审批节点之前的所有能获取到数据的模型。可选视图为该选择的数据模型关联的界面设计器中视图类型为表单的页面。 1.1.3 审批人和通过方式 审批人可在个人、部门、角色和模型中的字段里复选。当某人在不同类型人员选择中被重复选中,只会收到一次审批的代办。若为多人审批,审批是同步进行的。 单人审批: 通过方式:唯一通过方式,同意通过,拒绝否决 多人审批: 通过方式:或签/会签(默认或签) a. 或签(一名审批人同意或拒绝即可) 任意一位审批人操作通过或否决后流程就结束,其他审批人无法进入审批操作,但是会弹出消息提示审批结果。 场景:紧急且影响不大的审批可以由任意一位领导层或签。 b. 会签(需所有审批人同意才为同意,一名审批人拒绝即为拒绝) 场景:影响比较重大的审批,一票否决的形式决定是否通过。 c. 会签(一名审批人同意即为同意,需所有审批人拒绝才为拒绝) 场景:需要评估项目可操作性时,若有领导觉得有意义就通过,进入下一步评估,全员否决就否决项目。 1.1.4 操作&数据权限 操作权限 可设置是否必填拒绝原因、是否允许转交、是否允许加签、是否允许退回。 选择允许转交或允许加签之后,可选择添加人员的候选名单,不填默认所有人都可选。 选择允许退回后,可以选择退回到该审批节点之前的任意审批节点。ps:需所有审批人拒绝才为拒绝的会签不允许退回。 数据权限 选择视图后自动显示该视图下的数据字段,可选择的权限为查看、编辑、隐藏数据字段,默认可查看全部字段。 1.1.5 参与人重复 勾选参与人重复的场景时,满足场景的审批流程会由系统自动审批通过。 1.2 填写 当流程需要某些人提交数据才能继续时,可以使用填写这个动作。区别于数据类中的操作,填写这个动作只能修改当前触发模型中关联的视图表单,而数据类中的更新数据可以修改其他模型中的数据。 和审批动作相似,填写动作需要选择填写的模型和视图表单,需要选择填写人,可以选择添加转交权限。另外,填写动作必须包含一个及以上的可编辑的数据权限供操作人填写。

    2024年5月23日
    84900
  • 3.4.1 构建第一个Function

    Function做为oinone的可管理的执行逻辑单元,是无处不在的 在3.3.3【模型的数据管理器】和3.3.2【模型类型】一文中的代理模型部分,涉及到包括在Action中自定义函数(action背后都对应一个Function)、重写queryPage的函数、以及独立抽取的公共逻辑函数,Function做为oinone的可管理的执行逻辑单元,是无处不在的。这也是为什么说oinone以函数为内在的原因。 一、构建第一个Function 因为数据管理器和数据构造器是oinone为模型自动赋予的Function,是内在数据管理能力。模型其他Function都需要用以下四种方式主动定义 伴随模型新增函数(举例) 它是跟模型的java类定义在一起,复用模型的命名空间。 Step1 为PetShop增加一个名为sayHello的Function package pro.shushi.pamirs.demo.api.model; …… //import @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"; …… //省略其他代码 @Function(openLevel = FunctionOpenEnum.API) @Function.Advanced(type=FunctionTypeEnum.QUERY) public PetShop sayHello(PetShop shop){ PamirsSession.getMessageHub().info("Hello:"+shop.getShopName()); return shop; } } 图3-4-1-1 代码示例 Step2 重启看效果 用graphQL工具Insomnia查看效果 用Insomnia模拟登陆 a. 创建一个login请求,用于保存login请求,为后续模拟登陆保留快捷方式 图3-4-1-2 创建一个login请求 b. 下面为登陆请求的GraphQL,请在post输入框中输入。如果请求输入框提示错误可以,可以点击schema 的Refresh Schema来刷新文档 mutation { pamirsUserTransientMutation { login(user: {login: "admin", password: "admin"}) { broken errorMsg errorCode errorField } } } 图3-4-1-3 登陆请求的GraphQL c. 点击Send按钮,我们可以看到登陆成功的反馈信息 图3-4-1-4 登陆成功的反馈信息 用Insomnia模拟访问PetShop的sayHello方法,gql的返回中,我们可以看到两个核心返回 a. 一是方法正常返回的shopName b. 二是“PamirsSession.getMessageHub().info("Hello:"+shop.getShopName())”代码执行的结果,在messages中有一个消息返回,更多消息机制详见4.1.23【框架之信息传递】 query{ petShopQuery{ sayHello(shop:{shopName:"cpc"}){ shopName } } } 图3-4-1-5 用Insomnia模拟访问PetShop的sayHello 图3-4-1-6 代码执行结果 用Insomnia模拟访问PetShopProxy的sayHello方法 效果同用Insomnia模拟访问PetShop的sayHello方法,体现Function的继承特性。 独立新增函数绑定到模型(举例) 独立方法定义类,并采用Model.model或Fun注解,但是value都必须是模型的编码,如@Model.model(PetShop.MODEL_MODEL)或@Fun(PetShop.MODEL_MODEL) Step1 提取PetShop的sayHello方法独立到PetShopService中 注释掉PetShop的sayHello方法 package pro.shushi.pamirs.demo.api.model; …… //import @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"; …… //省略其他代码 // @Function(openLevel = FunctionOpenEnum.API) // @Function.Advanced(type=FunctionTypeEnum.QUERY) // public PetShop sayHello(PetShop shop){ // PamirsSession.getMessageHub().info("Hello:"+shop.getShopName()); // return shop; // } } 图3-4-1-7 注释掉PetShop的sayHello 新增PetShopService接口类 接口的方法上要加上@Function注解,这样另模块依赖api包的时候,会自动注册远程服务的消费者 package pro.shushi.pamirs.demo.api.service; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; @Fun(PetShop.MODEL_MODEL) //@Model.model(PetShop.MODEL_MODEL) public interface…

    2024年5月23日
    92300

Leave a Reply

登录后才能评论