3.3.4 模型的继承

在我们的很多项目中,客户都是有个性化需求的,就像我们不能找到两件一模一样的东西,何况是企业的经营与管理思路,多少都会有差异。常规的方式只能去修改标准产品的逻辑来适配客户的需求。导致后续标品维护非常困难。而在介绍完这节以后是不是让你更加清晰认知到我们2.4.2【oinone独特性之每一个需求都可以是一个模块】一文中所表达的特性带来的好处呢?

一、继承方式

继承方式可以分为五种:

  • 抽象基类ABSTRACT,只保存不希望为每个子模型重复键入的信息的模型,抽象基类模型不生成数据表存储数据,只供其他模型继承模型可继承域使用,抽象基类可以继承抽象基类。

  • 扩展继承EXTENDS,子模型与父模型的数据表相同,子模型继承父模型的字段与函数。存储模型之间的继承默认为扩展继承。

  • 多表继承MULTI_TABLE,父模型不变,子模型获得父模型的可继承域生成新的模型;父子模型不同表,子模型会建立与父模型的一对一关联关系字段(而不是交叉表),使用主键关联,同时子模型会通过一对一关联关系引用父模型的所有字段。多表继承父模型需要使用@Model.MultiTable来标识,子模型需要使用@Model.MultiTableInherited来标识。

  • 代理继承PROXY,为原始模型创建代理,可以增删改查代理模型的实体数据,就像使用原始(非代理)模型一样。不同之处在于代理继承并不关注更改字段,可以更改代理中的元信息、函数和动作,而无需更改原始内容。一个代理模型必须仅能继承一个非抽象模型类。一个代理模型可以继承任意数量的没有定义任何模型字段的抽象模型类。一个代理模型也可以继承任意数量继承相同父类的代理模型。

  • 临时继承TRANSIENT,将父模型作为传输模型使用,并可以添加传输字段。

二、继承约束

通用约束

对于扩展继承,查询的时候,父模型只能查询到父模型字段的数据,子模型可以查询出父模型及子模型的字段数据(因为派生关系所以子模型复刻了一份父模型的字段到子模型中)。

系统不会为抽象基类创建实际的数据库表,它们也没有默认的数据管理器,不能被实例化也无法直接保存,它们就是用来被继承的。抽象基类完全就是用来保存子模型们共有的内容部分,达到重用的目的。当它们被继承时,它们的字段会全部复制到子模型中。

系统不支持非jar包依赖模型的继承。

多表继承具有阻断效应,子模型无法继承多表继承父模型的存储父模型的字段,需要使用@Model.Advanced注解的inherited属性显示声明继承父模型的父模型。但是可以继承多表继承父模型的抽象父模型的字段。

可以使用@Model.Advanced的unInheritedFields和unInheritedFunctions属性设置不从父类继承的字段和函数。

跨模块继承约束

如果模型间的继承是跨模块继承,应该与模型所属模块建立依赖关系;如果模块间有互斥关系,则不允许建立模块依赖关系,同理模型间也不允许存在继承关系。

跨模块代理继承,对代理模型的非inJvm函数调用将使用远程调用方式;跨模块扩展(同表)继承将使用本地调用方式,如果是数据管理器函数,将直连数据源。

模型类型与继承约束

  • 抽象模型可继承:抽象模型(Abstract)

  • 临时模型可继承:抽象模型(Abstract)、传输模型(Transient)

  • 存储模型可继承:抽象模型(Abstract)、存储模型(Store)、存储模型(多表,Multi-table Store),不可继承多个Store或Multi-table Store

  • 多表存储模型(父)可继承:同扩展继承

  • 多表存储模型(子)在继承单个Multi-table Store后可继承:抽象模型(Abstract)、存储模型(Store),不可继承多个Store

  • 代理模型可继承:

    • 抽象模型(Abstract),须搭配继承Store、Multi-table Store或Proxy

    • 存储模型(Store),不可继承多个Store或Multi-table Store

    • 存储模型(多表,Multi-table Store),不可继承多个Store或Multi-table Store

    • 代理模型(Proxy),可继承多个Proxy,但多个父Proxy须继承自同一个Store或Multi-table Store,且不能再继承其他Store或Multi-table Store

同名字段以模型自身字段为有效配置,若模型自身不存在该字段,继承字段以第一个加载的字段为有效配置,所以在多重继承的情况下,未避免继承同名父模型字段的不确定性,在自身模型配置同名字段来确定生效配置。

三、继承的使用场景

模型的继承可以继承父模型的元信息、字段、数据管理器和函数

  • 抽象基类 解决公用字段问题

  • 扩展继承 解决开放封闭原则、跨模块扩展等问题

  • 多表继承 解决多型派生类字段差异问题和前端多存储模型组合外观问题

  • 代理继承 解决同一模型在不同场景下的多态问题(一表多态)

  • 临时继承 解决使用现有模型进行数据传输问题

举例,前端多存储模型组合外观问题可通过多表继承的子模型,并一对一关联到关联模型,同时使用排除继承字段去掉不需要继承的字段。子模型通过默认模型管理器提供查询功能给前端,默认查询会查询子模型数据列表并在列表行内根据一对一关系查出关联模型数据合并,关联模型数据展现形态在行内是平铺还是折叠,在详情是分组还是选项卡可以自定义view进行配置

扩展继承 父子同表,模型在所有场景都有一致化的表现,意味着原模型被扩展成了新模型,父子模型的表名一致,模型编码不同,可覆盖父模型的模型管理器、数据排序规则、函数

多表继承 父子多表,父子间有隐式一对一关系,即父子模型都增加了一对一关联关系字段,同时父模型的字段被引用到子模型,且引用字段为只读字段,意味着子模型不可以直接更改父模型的字段值,子模型不继承父模型的模型管理器、数据排序规则、函数,子模型拥有自己的默认模型管理器、数据排序规则、函数。多表继承具有阻断效应,子模型无法自动多表继承父模型的存储父模型,需要显式声明多表继承父模型的存储父模型。

代理继承 代理模型继承并可覆盖父模型的模型管理器、数据排序规则、函数,同时可以使用排除继承字段和函数来达到不同场景不同视觉交互的效果。

3.3.4 模型的继承

图3-3-4-1 继承的使用场景

四、抽象基类(举例)

参考前文中3.3.2【模型的类型】一文中关于抽象模型的介绍

五、多表继承(举例)

场景设计如下

3.3.4 模型的继承

图3-3-4-2 多表继承设计场景

Step1 新建宠物品种、宠狗品种和萌猫品种模型

  1. 新建宠物品种模型,用@Model.MultiTable(typeField = "kind"),申明为可多表继承父类,typeField指定为kind字段
package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.base.IdModel;

@Model.MultiTable(typeField = "kind")
@Model.model(PetType.MODEL_MODEL)
@Model(displayName="品种",labelFields = {"name"})
public class PetType extends IdModel {

    public static final String MODEL_MODEL="demo.PetType";

    @Field(displayName = "品种名")
    private String name;

    @Field(displayName = "宠物分类")
    private String kind;
}

图3-3-4-3 多表继承示例代码

  1. 新建宠狗品种模型,用@Model.MultiTableInherited(type = PetDogType.KIND_DOG),申明以多表继承模式继承PetType,覆盖kind字段(用defaultValue设置默认值,用invisible = true设置为前端不展示),更多模块元数据以及模型字段元数据配置详见4.1.6【模型之元数据详解】一文
package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;

@Model.MultiTableInherited(type = PetDogType.KIND_DOG)
@Model.model(PetDogType.MODEL_MODEL)
@Model(displayName="宠狗品种",labelFields = {"name"})
public class PetDogType extends PetType {

    public static final String MODEL_MODEL="demo.PetDogType";
    public static final String KIND_DOG="DOG";

    @Field(displayName = "宠物分类",defaultValue = PetDogType.KIND_DOG,invisible = true)
    private String kind;
}

图3-3-4-4 多表继承示例代码

  1. 新建萌猫品种模型,用@Model.MultiTableInherited(type = PetCatType.KIND_CAT),申明以多表继承模式继承PetType,覆盖kind字段(用defaultValue设置默认值,用invisible = true设置为前端不展示),并新增一个CatShapeEnum枚举类型的字段shape
package pro.shushi.pamirs.demo.api.enumeration;

import pro.shushi.pamirs.meta.annotation.Dict;
import pro.shushi.pamirs.meta.common.enmu.BaseEnum;

@Dict(dictionary = CatShapeEnum.DICTIONARY,displayName = "萌猫体型")
public class CatShapeEnum extends BaseEnum<CatShapeEnum,Integer> {

    public static final String DICTIONARY ="demo.CatShapeEnum";

    public final static CatShapeEnum BIG =create("BIG",1,"大","大");
    public final static CatShapeEnum SMALL =create("SMALL",2,"小","小");
}

图3-3-4-5 多表继承示例代码

package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.demo.api.enumeration.CatShapeEnum;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;

@Model.MultiTableInherited(type = PetCatType.KIND_CAT)
@Model.model(PetCatType.MODEL_MODEL)
@Model(displayName="萌猫品种",labelFields = {"name"})
public class PetCatType extends PetType {

    public static final String MODEL_MODEL="demo.PetCatType";
    public static final String KIND_CAT="CAT";

    @Field(displayName = "宠物分类",defaultValue = PetCatType.KIND_CAT,invisible = true)
    private String kind;

    @Field.Enum
    @Field(displayName = "宠物体型")
    private CatShapeEnum shape;
}

图3-3-4-6 多表继承示例代码

Step2 配置菜单后,重启查看效果

  1. 为了更好帮助大家更好地理解,这里先把对应的菜单配置上,从页面来看看效果。下面以注解方式进行菜单配置,更多详见3.5.1【构建第一个Menu】一文。
package pro.shushi.pamirs.demo.core.init;

import pro.shushi.pamirs.boot.base.constants.ViewActionConstants;
import pro.shushi.pamirs.boot.base.ux.annotation.action.UxRoute;
import pro.shushi.pamirs.boot.base.ux.annotation.navigator.UxMenu;
import pro.shushi.pamirs.boot.base.ux.annotation.navigator.UxMenus;
import pro.shushi.pamirs.demo.api.model.*;

@UxMenus
public class DemoMenus implements ViewActionConstants {
    @UxMenu("宠物品种")@UxRoute(PetType.MODEL_MODEL) class PetTypeMenu{}
    @UxMenu("萌猫品种")@UxRoute(PetCatType.MODEL_MODEL) class CatTypeMenu{}
    @UxMenu("宠狗品种")@UxRoute(PetDogType.MODEL_MODEL) class DogTypeMenu{}
}

图3-3-4-7 对应菜单配置

  1. 在宠狗品种中新增、修改、列表都隐藏了品种类型字段,并附上了默认值DOG

3.3.4 模型的继承

图3-3-4-8 宠狗品种新增页

3.3.4 模型的继承

图3-3-4-9 宠狗品种列表页

3.3.4 模型的继承

图3-3-4-10 宠狗品种数据表

  1. 在萌猫品种中新增、修改、列表都增加宠物体型枚举字段,并且隐藏了品种类型字段,并附上了默认值CAT

3.3.4 模型的继承

图3-3-4-11 萌猫品种新增页

3.3.4 模型的继承

图3-3-4-12 萌猫品种列表页

3.3.4 模型的继承

图3-3-4-13 萌猫品种数据表

Step3 为宠狗和萌猫品种模型实现默认读写扩展点,保证父子表数据同步

多表继承默认父子表是不同步的,不过oinone为每一个模型的默认数据管理器都提供的默认读写扩展点,我们可以主动利用这个特性来进行手动同步,更多扩展点知识详见3.4.3【函数相关特性】部分中的扩展点一文,会介绍除了利用系统默认提供的扩展点,还有如何自定义扩展。

  1. PetCatType和PetDogType都需要实现扩展点来完成与父模型的同步,所以这里把相同逻辑做了提取AbstractPetTypeExtPoint
package pro.shushi.pamirs.demo.core.extpoint;

import pro.shushi.pamirs.core.common.CopyHelper;
import pro.shushi.pamirs.demo.api.model.PetType;
import pro.shushi.pamirs.framework.connectors.data.sql.Pops;
import pro.shushi.pamirs.meta.api.Models;
import pro.shushi.pamirs.meta.base.extpoint.DefaultReadWriteExtPoint;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractPetTypeExtPoint  extends DefaultReadWriteExtPoint {

    public T createBefore(T data) {
        data.construct();
        return data;
    }

    public T updateBefore(T data) {
        return data;
    }

    public T createAfter(T data) {
        CopyHelper.simpleReplace(data, new PetType()).create();
        return data;
    }

    public T updateAfter(T data) {
        CopyHelper.simpleReplace(data, new PetType()).updateById();
        return data;
    }

    public List deleteBefore(List data) {
        List petTypeIdList = new ArrayList();
        for(T item:data){
            petTypeIdList.add(item.getId());
        }
        Models.data().deleteByWrapper(Pops.lambdaQuery().from(PetType.MODEL_MODEL).in(PetType::getId,petTypeIdList));
        return data;
    }
}

图3-3-4-14 相同逻辑提取AbstractPetTypeExtPoint

  1. PetCatTypeExtPoint继承AbstractPetTypeExtPoint类,并通过@Ext(PetCatType.class)申明扩展点所扩展函数所在类为PetCatType,并@ExtPoint.Implement申明对应扩展点的实现方法实例
package pro.shushi.pamirs.demo.core.extpoint;

import pro.shushi.pamirs.demo.api.model.PetCatType;
import pro.shushi.pamirs.meta.annotation.Ext;
import pro.shushi.pamirs.meta.annotation.ExtPoint;

import java.util.List;

@Ext(PetCatType.class)
public class PetCatTypeExtPoint extends AbstractPetTypeExtPoint{

    @Override
    @ExtPoint.Implement
    public PetCatType createBefore(PetCatType data) {
        return super.createBefore(data);
    }
    @Override
    @ExtPoint.Implement
    public PetCatType updateBefore(PetCatType data) {
        return super.updateBefore(data);
    }
    @Override
    @ExtPoint.Implement
    public PetCatType createAfter(PetCatType data) {
        return super.createAfter(data);
    }
    @Override
    @ExtPoint.Implement
    public PetCatType updateAfter(PetCatType data) {
        return super.updateAfter(data);
    }
    @Override
    @ExtPoint.Implement
    public List deleteBefore(List data) {
        return super.deleteBefore(data);
    }
}

图3-3-4-15 PetCatTypeExtPoint继承AbstractPetTypeExtPoint类

  1. PetDogTypeExtPoint继承AbstractPetTypeExtPoint类,并通过@Ext(PetDogType.class)申明扩展点所扩展函数所在类为PetDogType,并@ExtPoint.Implement申明对应扩展点的实现方法实例
package pro.shushi.pamirs.demo.core.extpoint;

import pro.shushi.pamirs.demo.api.model.PetDogType;
import pro.shushi.pamirs.meta.annotation.Ext;
import pro.shushi.pamirs.meta.annotation.ExtPoint;

import java.util.List;

@Ext(PetDogType.class)
public class PetDogTypeExtPoint extends AbstractPetTypeExtPoint{

    @Override
    @ExtPoint.Implement
    public PetDogType createBefore(PetDogType data) {
        return super.createBefore(data);
    }
    @Override
    @ExtPoint.Implement
    public PetDogType updateBefore(PetDogType data) {
        return super.updateBefore(data);
    }
    @Override
    @ExtPoint.Implement
    public PetDogType createAfter(PetDogType data) {
        return super.createAfter(data);
    }
    @Override
    @ExtPoint.Implement
    public PetDogType updateAfter(PetDogType data) {
        return super.updateAfter(data);
    }
    @Override
    @ExtPoint.Implement
    public List deleteBefore(List data) {
        return super.deleteBefore(data);
    }
}

图3-3-4-16 PetDogTypeExtPoint继承AbstractPetTypeExtPoint类

Step4 重启查看效果:在萌猫品种和宠狗品种下新增、修改、删除,则会在宠物品种下看到对应记录变化

3.3.4 模型的继承

图3-3-4-17 父模型宠物品种列表页

3.3.4 模型的继承

图3-3-4-18 父模型宠物品种数据表

六、扩展继承(举例)

场景设计(如下图3-3-55所示)

3.3.4 模型的继承

图3-3-4-19 扩展继承场景设计

Step1 新建宠物商品、宠狗商品和萌猫商品模型,并配置菜单

  1. 新建宠物商品模型为普通存储模型,用扩展继承父类设置公共字段如:店铺,品种等,注意type字段类型为PetType
package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;

import java.math.BigDecimal;

@Model.model(PetItem.MODEL_MODEL)
@Model(displayName = "宠物商品",summary="宠物商品")
public class PetItem  extends AbstractDemoCodeModel{

    public static final String MODEL_MODEL="demo.PetItem";
    @Field(displayName = "商品名称",required = true)
    private String itemName;

    @Field(displayName = "商品价格",required = true)
    private BigDecimal price;

    @Field(displayName = "店铺",required = true)
    private PetShop shop;

    @Field(displayName = "品种")
    @Field.many2one
    private PetType type;
}

图3-3-4-20 新建宠物商品模型为普通存储模型

  1. 新建宠狗商品模型继承宠物商品模型,注意这里把type字段类型覆盖为PetType的子类PetDogType,并新增原产地字段provenance
package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;

@Model.model(PetDogItem.MODEL_MODEL)
@Model(displayName = "宠狗商品",summary="宠狗商品")
public class PetDogItem extends PetItem{

    public static final String MODEL_MODEL="demo.PetDogItem";

    @Field(displayName = "品种")
    @Field.many2one
    private PetDogType type;

    @Field(displayName = "原产地")
    private String provenance;
}

图3-3-4-21 新建宠狗商品模型继承宠物商品模型

  1. 新建萌猫商品模型继承宠物商品模型,注意这里把type字段类型覆盖为PetType的子类PetCatType。
package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;

@Model.model(PetCatItem.MODEL_MODEL)
@Model(displayName = "萌猫商品",summary="萌猫商品")
public class PetCatItem extends PetItem{
    public static final String MODEL_MODEL="demo.PetCatItem";

    @Field(displayName = "品种")
    @Field.many2one
    private PetCatType type;
}

图3-3-4-22 新建萌猫商品模型继承宠物商品模型

  1. 为了更好帮助大家更好地理解,这里先把对应的菜单配置上,从页面来看看效果。下面以注解方式进行菜单配置,更多详见3.5.1【构建第一个Menu】一文。
package pro.shushi.pamirs.demo.core.init;

import pro.shushi.pamirs.boot.base.constants.ViewActionConstants;
import pro.shushi.pamirs.boot.base.ux.annotation.action.UxRoute;
import pro.shushi.pamirs.boot.base.ux.annotation.navigator.UxMenu;
import pro.shushi.pamirs.boot.base.ux.annotation.navigator.UxMenus;
import pro.shushi.pamirs.demo.api.model.*;

@UxMenus
public class DemoMenus implements ViewActionConstants {
    @UxMenu("商品管理")@UxRoute(PetItem.MODEL_MODEL) class ItemMenu{}
    @UxMenu("宠狗商品")@UxRoute(PetDogItem.MODEL_MODEL) class DogItemMenu{}
    @UxMenu("萌猫商品")@UxRoute(PetCatItem.MODEL_MODEL) class CatItemMenu{}
    @UxMenu("宠物品种")@UxRoute(PetType.MODEL_MODEL) class PetTypeMenu{}
    @UxMenu("萌猫品种")@UxRoute(PetCatType.MODEL_MODEL) class CatTypeMenu{}
    @UxMenu("宠狗品种")@UxRoute(PetDogType.MODEL_MODEL) class DogTypeMenu{}
}

图3-3-4-23 以注解方式进行菜单配置

至此模型就建完了,还是很简单的吧

Step2 分别新建三条宠物商品、宠狗商品和萌猫商品记录,查看效果

  1. 父模型宠物商品的商品管理可以看到品类中可选柴犬、加菲猫,数据来源是品种的父模型PetType,店铺下拉框展示为"-",因为店铺模型没有配置label字段,可以在店铺模型的注解上增加“@Model(displayName = "宠物店铺",summary="宠物店铺",labelFields = {"shopName"})”,即可解决。这里先选择第一个往下执行

3.3.4 模型的继承

图3-3-4-24 宠物商品管理

  1. 父模型宠狗商品的商品管理可以看到品类中可选柴犬,数据来源是品种的子模型PetDogType,而且新增源产地字段;

3.3.4 模型的继承

图3-3-4-25 父模型宠狗商品管理

  1. 父模型萌猫商品的商品管理可以看到品类中可选加菲猫,数据来源是品种的子模型PetCatType;

3.3.4 模型的继承

图3-3-4-26 父模型萌猫商品管理

Step3 分别观察宠物商品、宠狗商品和萌猫商品的列表页,我们会发现数据记录都是三条,但是展示字段会随着模型不同而有差异

  1. 父页面在品种一列中可以显示所有品种名称

3.3.4 模型的继承

图3-3-4-27 父页面在品种一列中可以显示所有品种名称

  1. 宠狗页面在品种一列中只能显示PetDogType的品种名称、但多了原产地字段

3.3.4 模型的继承

图3-3-4-28 宠狗页面品种列展示

  1. 萌猫页面在品种一列中只能显示PetCatType的品种名称

3.3.4 模型的继承

图3-3-4-29 萌猫页面品种列中只展示PetCatType的品种名称

  1. 对应的数据库表:数据都在一张记录表中,新增了原产地字段

3.3.4 模型的继承

图3-3-4-30 对应数据库表

Step4 顺带优化下宠物店铺的展示Labels

  1. 给PetShop增加@Model(labelFields ={"shopName"} )注解,labelFields是为模型的“数据标题, 用于前端展示”,其默认值为name,但PetShop没有name字段,所以我们列表上展示不出来。更多元数据见4.1.6【模型之元数据详解】一文;
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"} )
public class PetShop extends AbstractDemoIdModel {
    public static final String MODEL_MODEL="demo.PetShop";

    @Field(displayName = "店铺名称",required = true)
    private String shopName;

    @Field(displayName = "开店时间",required = true)
    private Time openTime;

    @Field(displayName = "闭店时间",required = true)
    private Time closeTime;
}

图3-3-4-31 给PetShop增加@Model(labelFields ={shopName} )注解

  1. 重启查看效果,店铺字段可以展示出来

3.3.4 模型的继承

图3-3-4-32 店铺字段可展示

Step5 思考在扩展继承模式下数据隔离问题

多表继承需要自己搞定父、子模型的数据同步问题,同表继承则需要自己搞定数据隔离问题。我们可以重写queryPage这个Function,如我们在3.3.2【模型类型】一文中介绍“代理模型类型”的部分时,涉及的PetShopProxyAction就覆盖了queryPage。这里举例PetCatItem的queryPage覆盖,PetDogItem留给大家自行练习

  1. 给PetItem显示增加一个typeId字段,方便在PetCatItemAction中用于过滤条件使用。为什么说显示增加呢?因为type字段是一个many2one的字段在没有配置@Field.Relation的情况下,oinone会为PetItem模型自动推断出一个typeId字段去关联PetType模型的Id。@Field.Relation的relationFields为本模型的关联字段,referenceFields为目标模型关联字段。如符合推断规范可以不配置@Field.Relation,就如这个场景配不配效果是一样的。还是那句话“更多元数据详见4.1.6【模型之元数据详解】一文”;
package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;

import java.math.BigDecimal;

@Model.model(PetItem.MODEL_MODEL)
@Model(displayName = "宠物商品",summary="宠物商品")
public class PetItem  extends AbstractDemoCodeModel{
    public static final String MODEL_MODEL="demo.PetItem";

    @Field(displayName = "商品名称",required = true)
    private String itemName;

    @Field(displayName = "商品价格",required = true)
    private BigDecimal price;

    @Field(displayName = "店铺",required = true)
    private PetShop shop;

    @Field(displayName = "品种")
    @Field.many2one
    @Field.Relation(relationFields = {"typeId"},referenceFields = {"id"})
    private PetType type;

    @Field(displayName = "品种类型",invisible = true)
    private Long typeId;
}

图3-3-4-33 给PetItem显示增加一个typeId字段

  1. 覆盖PetCatItem名为“queryFilters”的函数,增加typeId的过滤条件为PetCatType表对应的Id列表,则针对PetCatItem的所有查询都会自动加上“queryFilters”的函数返回的过滤条件
package pro.shushi.pamirs.demo.core.action;

import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import pro.shushi.pamirs.core.common.behavior.impl.DataStatusBehavior;
import pro.shushi.pamirs.demo.api.model.PetCatItem;
import pro.shushi.pamirs.demo.api.model.PetCatType;
import pro.shushi.pamirs.framework.connectors.data.sql.Pops;
import pro.shushi.pamirs.meta.annotation.Action;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;

import java.util.List;
import java.util.stream.Collectors;

@Model.model(PetCatItem.MODEL_MODEL)
@Component
public class PetCatItemAction extends DataStatusBehavior {

    @Override
    protected PetCatItem fetchData(PetCatItem data) {
        return data.queryById();
    }
    @Action(displayName = "启用")
    public PetCatItem dataStatusEnable(PetCatItem data){
        data = super.dataStatusEnable(data);
        data.updateById();
        return data;
    }

    @Function.Advanced(displayName = "查询模型数据的默认过滤条件", type = FunctionTypeEnum.QUERY, managed = true)
    @Function(openLevel = {LOCAL})
    public String queryFilters() {
        StringBuilder sqlWhereCondition = new StringBuilder();
        List typeList = new PetCatType().queryList();
        if(!CollectionUtils.isEmpty(typeList)){
//          sqlWhereCondition.append("type_id");
            sqlWhereCondition.append(PStringUtils.fieldName2Column(LambdaUtil.fetchFieldName(PetCatItem::getTypeId)));
            sqlWhereCondition.append(StringUtils.SPACE).append(SqlConstants.IN).append(CharacterConstants.LEFT_BRACKET);
            for(PetCatType petCatType: typeList){
                sqlWhereCondition.append(petCatType.getId()).append(CharacterConstants.SEPARATOR_COMMA);
            }
            sqlWhereCondition.deleteCharAt(sqlWhereCondition.lastIndexOf(CharacterConstants.SEPARATOR_COMMA));
            sqlWhereCondition.append(StringUtils.SPACE).append(CharacterConstants.RIGHT_BRACKET);
        }
        return sqlWhereCondition.toString();
    }
}

图3-3-4-34 覆盖函数的代码示例

  1. 重启查看效果,萌猫商品只能看到PetCatType对应的数据记录了,赶紧自己动手试试PetDogItem的改造吧

3.3.4 模型的继承

图3-3-4-35 重启查看效果

七、代理继承(举例)

代理模型在3.3.2【模型的类型】一文中有介绍过,代理模型看名字就知道其本身是通过继承方式代理另一个存储模型,这里不过多介绍。我们来尝试一下它继承的特殊性“一个代理模型也可以继承任意数量继承相同父类的代理模型”

场景设计(如下图3-3-72所示)

3.3.4 模型的继承

图3-3-4-36 代理继承场景设计

Step1 新建宠物店铺代理模型A和宠物店铺代理模型B,同时修改PetItem

  1. 新建宠物店铺代理模型A申明为代理模型,新增一个one2many字段items,用@Field.Relation申明关联字段
package pro.shushi.pamirs.demo.api.proxy;

import pro.shushi.pamirs.demo.api.model.PetItem;
import pro.shushi.pamirs.demo.api.model.PetShop;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.enmu.ModelTypeEnum;
import pro.shushi.pamirs.user.api.model.PamirsUser;

import java.util.List;

@Model.model(PetShopProxyA.MODEL_MODEL)
@Model.Advanced(type = ModelTypeEnum.PROXY)
@Model(displayName = "宠物店铺代理模型A",summary="宠物店铺代理模型A")
public class PetShopProxyA extends PetShop {
    public static final String MODEL_MODEL="demo.PetShopProxyA";

    @Field.one2many
    @Field(displayName = "商品列表")
    @Field.Relation(relationFields = {"id"},referenceFields = {"shopId"})
    private List items;
}

图3-3-4-37 新建宠物店铺代理模型A申明为代理模型

  1. 新建宠物店铺代理模型B申明为代理模型,用 @Model.Advanced(inherited ={PetShopProxy.MODEL_MODEL,PetShopProxyA.MODEL_MODEL})声明继承多个同源代理模型,并且新增一个one2many字段catItems用@Field.Relation申明关联字段
package pro.shushi.pamirs.demo.api.proxy;

import pro.shushi.pamirs.demo.api.model.PetCatItem;
import pro.shushi.pamirs.demo.api.model.PetShop;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.enmu.ModelTypeEnum;

import java.util.List;

@Model.model(PetShopProxyB.MODEL_MODEL)
@Model.Advanced(type = ModelTypeEnum.PROXY,inherited ={PetShopProxy.MODEL_MODEL,PetShopProxyA.MODEL_MODEL} )
@Model(displayName = "宠物店铺代理模型B",summary="宠物店铺代理模型B")
public class PetShopProxyB extends PetShop {

    public static final String MODEL_MODEL="demo.PetShopProxyB";

    @Field.one2many
    @Field(displayName = "萌猫商品列表")
    @Field.Relation(relationFields = {"id"},referenceFields = {"shopId"})
    private List catItems;
}

图3-3-4-38 新建宠物店铺代理模型B申明为代理模型

  1. 修改PetItem增加一个labelFields={"itemName"}注解,给PetItem显示增加一个shopId字段方便,在Service中用于过滤条件使用。
package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;

import java.math.BigDecimal;

@Model.model(PetItem.MODEL_MODEL)
@Model(displayName = "宠物商品",summary="宠物商品",labelFields={"itemName"})
public class PetItem  extends AbstractDemoCodeModel{

    public static final String MODEL_MODEL="demo.PetItem";
    @Field(displayName = "商品名称",required = true)
    private String itemName;

    @Field(displayName = "商品价格",required = true)
    private BigDecimal price;

    @Field(displayName = "店铺",required = true)
    private PetShop shop;

    @Field(displayName="店铺id",invisible = true)
    private Long shopId;

    @Field(displayName = "品种")
    @Field.many2one
    @Field.Relation(relationFields = {"typeId"},referenceFields = {"id"})
    private PetType type;

    @Field(displayName = "品种类型",invisible = true)
    private Long typeId;
}

图3-3-4-39 PetItem代码修改示例

Step2 覆盖PetShopProxyB的queryPage和queryOne函数

PetShopProxyB的queryPage和queryOne都查catItems\creater\items三个字段

package pro.shushi.pamirs.demo.core.action;

import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import pro.shushi.pamirs.core.common.behavior.impl.DataStatusBehavior;
import pro.shushi.pamirs.demo.api.model.PetShop;
import pro.shushi.pamirs.demo.api.proxy.PetShopProxy;
import pro.shushi.pamirs.demo.api.proxy.PetShopProxyB;
import pro.shushi.pamirs.framework.faas.utils.ArgUtils;
import pro.shushi.pamirs.meta.annotation.Action;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;

@Model.model(PetShopProxyB.MODEL_MODEL)
@Component
public class PetShopProxyBAction  {

    @Function.Advanced(type= FunctionTypeEnum.QUERY)
    @Function.fun(FunctionConstants.queryPage)
    @Function(openLevel = {FunctionOpenEnum.API})
    public Pagination queryPage(Pagination page, IWrapper queryWrapper){
        Pagination result = new PetShopProxy().queryPage(page,queryWrapper);
        if(!CollectionUtils.isEmpty(result.getContent())) {
            //自身继承【宠物店铺】后扩展的字段catItems
            new PetShopProxyB().listFieldQuery(result.getContent(),PetShopProxyB::getCatItems);
            //继承【宠物店铺代理模型】而来的字段creater,java语言限制【宠物店铺代理模型B】没有getCreate()方法
            new PetShopProxyB().listFieldQuery(result.getContent(),"creater");
            //继承【宠物店铺代理模型A】而来的字段items,java语言限制【宠物店铺代理模型B】没有getItems()方法
            new PetShopProxyB().listFieldQuery(result.getContent(),"items");
        }
        return result;
    }
    @Function.Advanced(type= FunctionTypeEnum.QUERY)
    @Function.fun(FunctionConstants.queryByEntity)
    @Function(openLevel = {FunctionOpenEnum.API})
    public PetShopProxyB queryOne(PetShopProxyB query){
        query = query.queryById();
        //自身继承【宠物店铺】后扩展的字段catItems
        query.fieldQuery(PetShopProxyB::getCatItems);
        //继承【宠物店铺代理模型】而来的字段creater,java语言限制【宠物店铺代理模型B】没有getCreate()方法
        query.fieldQuery("creater");
        //继承【宠物店铺代理模型A】而来的字段items,java语言限制【宠物店铺代理模型B】没有getItems()方法
        query.fieldQuery("items");
        return query;
    }
}

图3-3-4-40 函数覆盖代码示例

Step3 配置菜单,并重启看效果

  1. 配置菜单:请参考本节前面介绍自行增加三个菜单商店管理、商店管理A、商店管理B分别对应宠物店铺代理模型、宠物店铺代理模型A、宠物店铺代理模型B的管理入口

  2. 宠物店铺代理模型覆盖了queryPage方法但没有覆盖queryOne方法,所以列表页有显示新增字段创建者,但详情页没有。具体详见3.3.2【模型的类型】一文中的“代理模型”介绍部分;

3.3.4 模型的继承

图3-3-4-41 宠物店铺代理模型的列表页

3.3.4 模型的继承

图3-3-4-42 宠物店铺代理模型的详情页

  1. 宠物店铺代理模型A只增加了一个商品列表字段,没有覆盖对应query相关方法,所以列表页有这个字段但没有值;

3.3.4 模型的继承

图3-3-4-43 宠物店铺代理模型A的列表页

  1. 宠物店铺代理模型B因为同源多表继承了宠物店铺代理模型和宠物店铺代理模型A所以它拥有商品列表、萌猫商品列表、创建者三个字段,并且同时覆盖queryPage和queryOne函数,所以列表和详情都有值。

3.3.4 模型的继承

图3-3-4-44 宠物店铺代理模型B的列表页

3.3.4 模型的继承

图3-3-4-45 宠物店铺代理模型B的详情页

八、临时继承(举例)

参考前文3.3.2【模型的类型】一文中对传输模型的介绍,差别在于一个继承抽象基类,一个继承其他模型类型,不管什么类型都只是复用父类的字段,自己还是传输模型

九、总结

在我们的很多项目中,客户都是有个性化需求的,就像我们不能找到两件一模一样的东西,何况是企业的经营与管理思路,多少都会有差异。常规的方式只能去修改标准产品的逻辑来适配客户的需求。导致后续标品维护非常困难。而在介绍完这节以后是不是让你更加清晰认知到我们2.4.2【oinone独特性之每一个需求都可以是一个模块】一文中所表达的特性带来的好处呢?

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

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

(1)
史, 昂的头像史, 昂数式管理员
上一篇 2024年5月23日 am9:42
下一篇 2024年5月23日 am9:49

相关推荐

  • 业务域

    1. 业务域介绍 业务域是根据业务域对集成应用、开放接口进行归类管理。在创建集成应用、开发接口时,可选择归属的业务域。 操作入口:集成设计器——业务域。 2. 业务域管理 业务域管理提供新增、删除、搜索操作。 2.1 业务域列表 支持按照编码、名称、描述搜索业务域。 2.2 新增业务域 新增业务域:输入业务域名称、描述新增。 2.3 删除业务域 当前业务域未被其他数据记录引用时,可删除成功,反之如果被引用了,不允许删除。

    2024年6月20日
    1.8K00
  • 3.1.2 环境准备(windows版)

    一、后端基础环境准备 安装JDK1.8 ,高于1.8_221以上(下载地址见书籍【附件一】) 打开Windows环境变量配置页 此电脑 => 右键属性 => 系统高级设置 => 环境变量 配置环境变量 在用户环境变量中新建变量为JAVA_HOME的项,值为JDK安装之后的路径 图3-1-27 新建环境变量JAVA_HOM 编辑变量为Path的项添加一个值%JAVA_HOME%\bin 图3-1-28 添加一个环境变量值%JAVA_HOME%\\bin PowerShell或者CMD中验证,输出类似信息为安装配置成功 图3-1-29 验证JAVA是否安装成功 安装 Apache Maven 3.8+ (下载地址见书籍【附件一】) 删除Maven安装目录下的conf/settings.xml 配置mvn的settings,下载附件settings-open.xml,并重命名为settings.xml,建议直接放在【C:\Users\你的用户名.m2】下面。下载地址见oinone开源社区群公告,也可以联系oinone合作伙伴或服务人员 配置环境变量 在用户环境变量中新建变量为M2_HOME的项,值为Maven安装路径 图3-1-30 新建变量M2_HOME 编辑变量为Path的项添加一个值%M2_HOME%\bin 图3-1-31 添加一个值%M2_HOME%\\bin 验证 图3-1-32 验证Maven是否安装成功 安装 Jetbrains IDEA (下载地址见书籍【附件一】) 插件安装 下载地址 密码: mdji 如果IDEA安装了Lombok插件,请禁用Lombok插件 点击菜单项File => Settings => Plugins 图3-1-33 插件管理页面操作示意 下载插件包 (联系Oinone官方客服) 图3-1-35 操作指引 图3-1-36 操作指引 安装MySQL 8 (下载地址见书籍【附件一】) 解压下载的ZIP安装包, 复制到自定义安装目录 设置环境变量 MYSQL_BASE_DIR 提换成MySQL安装目录路径 把 %MYSQL_BASE_DIR%\bin 加入到系统环境变量中 在PowerShell中可以使用 Get-Command mysqld 命令验证环境变量是否配置成功,执行成功输出mysqld的所在路径 初始化 在命令行中执行 mysqld –initialize-insecure –user=mysql 安装 mysqld -install 启动MySQL服务 mysqld -install 设置root用户密码 alter user \’root\’@\’localhost\’ identified with mysql_native_password by \’oinone\’; flush privileges; 安装DB GUI工具 Datagrip、MySQLWorkbench、DBEaver 选其一 ### 安装Git (下载地址见书籍【附件一】) 安装GraphQL测试工具Insomnia(下载地址见书籍【附件一】) 安装RocketMQ(下载地址见书籍【附件一】) 修改安装目录下bin中对应文件的默认配置 a. runserver.cmd文件内容 -Xms2g -Xmx2g为 -Xms1g -Xmx1g b. runbroker.cmd文件内容 -Xms2g -Xmx2g为 -Xms1g -Xmx1g,以及-XX:G1HeapRegionSize=1m 启动RocketMQ NameServer命令 RocketMQ安装目录\bin\mqnamesrv.cmd start 启动RocketMQ Broker命令 RocketMQ安装目录\bin\mqbroker.cmd -n localhost:9876 停止 RocketMQ命令 mqshutdown.cmd broker mqshutdown.cmd namesrv 安装ElasticSearch 版本 8.4.1(下载地址见书籍【附件一】) (非必须) ES运行时需要JDK18及以上版本JDK运行环境, ES安装包中包含了一个JDK18版本 set JAVA_HOME=ES安装路径\jdk 启动 ES安装路径\bin\elasticsearch.bat 停止 ctrl+c 或者关闭cmd、PowerShell的窗口 安装Redis (下载地址见书籍【附件一】) 解压安装包到安装目录 在PowerShell进入到Redis安装目录 在PowerShell中执行.\redis-server.exe,输出图中类似信息(如下图3-35所示): 图3-1-37 验证redis是否安装成功 新开PowerShell窗口, 进入到Redis安装目录, 执行 .\redis-cli.exe回车,输入 ping 回车输出 PONG即表示Redis安装成功 图3-1-38 验证redis是否安装成功 Zookeeper安装(下载地址见书籍【附件一】) 解压安装, 在 PowerShell中执行 tar zxvf 安装包路径(tar.gz包) -C Zk安装目录 进入 Zk安装目录\conf\ 复制 zoo_sample.cfg文件为 zoo.cfg 修改zoo.cfg文件的内容 (其中dataDir需要自己设定) tickTime=2000…

    2024年5月23日
    2.9K00
  • 3.3.7 字段之序列化方式

    本文核心是带大家全面了解oinone的序列方式,包括支持的序列化类型、注意点、如果新增客户化序列化方式以及字段默认值的反序列化。 一、数据存储的序列化 (举例) 使用@Field注解的serialize属性来配置非字符串类型属性的序列化与反序列化方式,最终会以序列化后的字符串持久化到存储中。 ### Step1 新建PetItemDetail模型、并为PetItem添加两个字段 PetItemDetail继承TransientModel,增加两个字段,分别为备注和备注人 package pro.shushi.pamirs.demo.api.tmodel; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.TransientModel; import pro.shushi.pamirs.user.api.model.PamirsUser; @Model.model(PetItemDetail.MODEL_MODEL) @Model(displayName = "商品详情",summary = "商品详情",labelFields = {"remark"}) public class PetItemDetail extends TransientModel { public static final String MODEL_MODEL="demo.PetItemDetail"; @Field.String(min = "2",max = "20") @Field(displayName = "备注",required = true) private String remark; @Field(displayName = "备注人",required = true) private PamirsUser user; } 图3-3-7-1 PetItemDetail继承TransientModel 修改PetItem,增加两个字段petItemDetails类型为List和tags类型为List,并设置为不同的序列化方式,petItemDetails为JSON(缺省就是JSON,可不配),tags为COMMA。同时设置 @Field.Advanced(columnDefinition = varchar(1024)),防止序列化后存储过长 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.demo.api.tmodel.PetItemDetail; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.enmu.NullableBoolEnum; import java.math.BigDecimal; import java.util.List; @Model.model(PetItem.MODEL_MODEL) @Model(displayName = "宠物商品",summary="宠物商品",labelFields = {"itemName"}) public class PetItem extends AbstractDemoCodeModel{ public static final String MODEL_MODEL="demo.PetItem"; @Field(displayName = "商品名称",required = true) private String itemName; @Field(displayName = "商品价格",required = true) private BigDecimal price; @Field(displayName = "店铺",required = true) @Field.Relation(relationFields = {"shopId"},referenceFields = {"id"}) private PetShop shop; @Field(displayName = "店铺Id",invisible = true) private Long shopId; @Field(displayName = "品种") @Field.many2one @Field.Relation(relationFields = {"typeId"},referenceFields = {"id"}) private PetType type; @Field(displayName = "品种类型",invisible = true) private Long typeId; @Field(displayName = "详情", serialize = Field.serialize.JSON, store = NullableBoolEnum.TRUE) @Field.Advanced(columnDefinition = "varchar(1024)") private List<PetItemDetail> petItemDetails; @Field(displayName = "商品标签",serialize = Field.serialize.COMMA,store = NullableBoolEnum.TRUE,multi = true) @Field.Advanced(columnDefinition = "varchar(1024)") private…

    2024年5月23日
    1.4K00
  • 流程

    1. 流程介绍 日常工作和生活中到处都存在各种各样的流程,例如业务开展中的产品研发流程、产品制作流程、订单发货流程等,也有管控分险的费用报销流程、员工请假审批流程、项目立项流程等。流程设计器可以帮助公司实现流程的数字化,规范流程操作,减少人工操作并留存痕迹,提高工作效率和安全性。 2. 流程的组成 流程设计器主要包含基本操作和流程设计两个部分。前者包含了流程的新增、删除、复制、停用/启用、编辑、搜索。后者包含单一流程的基础信息修改、流程设计、参数配置、保存、发布。 2.1 流程的基本操作 流程页面有两种显示方式,默认为平铺显示的模式,可以点击切换为列表详情显示的模式。 2.1.1 新增 平铺显示和列表详情模式下点击左上角的创建按钮即可新增一个流程,点击后进入流程设计页面,流程名默认为“未命名流程”,可自行修改。 2.1.2 删除 遇到流程创建有误,没有使用过且将来也不会使用该流程,可以删除流程。需要注意的是,删除流程的前提是该流程已停用,并且该流程从未执行过。 2.1.3 复制 遇到流程节点动作相似度较高的情况可以使用复制流程的功能,点击按钮后生成一个“原流程名-复制”的流程,并且进入新流程的流程设计界面。 2.1.4 停用/启用 流程需要更新或暂时不用时可以使用停用功能。流程停用后将不会执行流程中的动作,正在执行中的流程不受停用影响,会正常执行直到流程结束。 点击启用按钮,流程恢复启用状态,可正常触发。 2.1.5 编辑 点击编辑进入该流程的设计页面。 2.1.6 搜索 页面最上方的是搜索区,可以按照流程名称、触发方式、启用状态、更新状态进行筛选搜素,点击重置按钮修改搜索条件。

    2024年1月20日
    1.7K00
  • 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日
    1.2K00

Leave a Reply

登录后才能评论