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 重启看效果

修改宠物达人记录对应的字段,然后进入审计模块查看日志

image.png

image.png

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

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

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

相关推荐

  • 4.5 研发辅助

    这里都是一些提升研发效率的小工具

    Oinone 7天入门到精通 2024年5月23日
    1.3K00
  • 4.1.22 框架之分布式缓存

    分布式缓存Oinone平台主要用到了Redis,为了让业务研发时可以无感使用RedisTemplate和StringRedisTemplate,已经提前注册好了redisTemplate和stringRedisTemplate,而且内部会自动处理相关特殊逻辑以应对多租户环境,小伙伴不能自己重新定义Redis的相关bean。 使用说明 配置说明 spring: redis: database: 0 host: 127.0.0.1 port: 6379 timeout: 2000 # cluster: # nodes: # – 127.0.0.1:6379 # timeout: 2000 # max-redirects: 7 jedis: pool: # 连接池中的最大空闲连接 默认8 max-idle: 8 # 连接池中的最小空闲连接 默认0 min-idle: 0 # 连接池最大连接数 默认8 ,负数表示没有限制 max-active: 8 # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认-1 max-wait: -1 图4-1-22-1 分布式缓存配置说明 代码示例 package pro.shushi.pamirs.demo.core.service; import org.springframework.stereotype.Component; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; @Component public class Test { @Autowired private RedisTemplate redisTemplate; @Autowired private StringRedisTemplate stringRedisTemplate } 图4-1-22-2 代码示例

    Oinone 7天入门到精通 2024年5月23日
    1.2K00
  • 3.5.4 Ux注解详解

    我们默认视图已经基本可以用了,但实际业务中还是会有一些不大不小的自定义需求,写自定义视图又太麻烦,今天我们来学习一种更加轻量的模式即:后端研发可以通过注解来配置视觉交互。该系列注解以Ux开头,例如@UxHomepage、@UxMenu、@UxAction、@UxView、@UxWidget等等。 视图XML的配置优先级大于在代码上的注解,也就是代码上的注解影响的是默认展示逻辑。 一、Ux家族图谱 我们先简单通过家族图谱做个简单了解,脑海里有一个影响当有需要的时候知道能不能做,深入了解还需要大家多多动手去尝试 图3-5-4-1 Ux家族图谱 二、默认视图后端配置举例 在下面的代码片段中UxTable、UxForm、UxDetail、UxTableSearch都有涉及,几个特殊点做些解释其他的留大家自行测试 Group分组的配置逻辑:为了不让一个分组内的字段不断的写Group,所以采取了第一个字段写了Group,到下一个出现的group之间的字段都自动归为一个Group 搜素整体不展示可以用“@UxTable(enableSearch = false)”配置在模型的类上。 字段搜索用“UxTableSearch”配置在模型的字段上,其特殊逻辑是只要你配了一个字段,系统就不自动补充了,例子中表格页的搜索栏只会留下店铺名称和店铺编码 ……其他代码 //@UxTable(enableSearch = false),整体不支持搜索 public class PetShop extends AbstractDemoIdModel { public static final String MODEL_MODEL="demo.PetShop"; @Field(displayName = "店铺编码") @UxForm.FieldWidget(@UxWidget(group = "Form基础数据"))//Form分组 @UxTableSearch.FieldWidget(@UxWidget())//支持搜索 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; @UxTableSearch.FieldWidget(@UxWidget())//支持搜索 @UxTable.FieldWidget(@UxWidget(invisible = "true"))//表格中不展示支持搜索 @Field(displayName = "店铺名称",required = true,immutable=true) private String shopName; @Field(displayName = "一年内新店") @UxForm.FieldWidget(@UxWidget(widget = "Switch",group = "Form基础数据"))//Switch,Checkbox可以切换着看,字段可选widget参考【字段的配置】一文 private Boolean oneYear; @Field(displayName = "开店时间",required = true) @UxDetail.FieldWidget(@UxWidget(invisible = "true"))//详情不展示 private Time openTime; @Field(displayName = "闭店时间",required = true) @UxDetail.FieldWidget(@UxWidget(invisible = "true"))//详情不展示 private Time closeTime; …… 其他代码 } 图3-5-4-2 默认视图后端配置举例

    2024年5月23日
    1.2K00
  • 3.5.7.9 自定义多Tab

    在业务中,可能会遇到需要对多tab的交互或UI做全新设计的需求,这个时候可以自定义多tab组件支持。 首先继承平台的MultiTabsWidget组件,将自己vue文件设置到component处 import { MultiTabsWidget, SPI, ViewWidget } from '@kunlun/dependencies'; import Component from './CustomMultiTabs.vue'; @SPI.ClassFactory( ViewWidget.Token({ // 这里的tagName跟平台的组件一样,这样才能覆盖平台的组件 tagName: ['multi-tabs', 'MultiTabs'] }) ) export class CustomMultiTabsWidget extends MultiTabsWidget{ public initialize(props) { super.initialize(props); // 设置自定义的vue组件 this.setComponent(Component); return this; } } vue文件中继承平台的props,编写自定义页面代码 export const MultiTabsProps = { /** * 组件是否可见 */ invisible: { type: Boolean }, /** * tab列表数据 */ tabs: { type: Array as PropType<MultiTab[]> }, /** * 当前激活的tab */ activeTab: { type: Object as PropType<MultiTab> }, /** * 鼠标悬浮所在的tab */ hoverTab: { type: Object as PropType<MultiTab> }, /** * 鼠标经过tab事件回调 */ onMouseenterTab: { type: Function as PropType<(tab: MultiTab) => void> }, /** * 鼠标离开tab事件回调 */ onMouseleaveTab: { type: Function as PropType<(tab: MultiTab) => void> }, /** * 点击tab */ onClickTab: { type: Function as PropType<(tab: MultiTab) => void> }, /** * 刷新当前tab */ onRefreshCurrentTab: { type: Function as PropType<(tab: MultiTab) => void> }, /** * 关闭当前tab */ onCloseCurrentTab: { type: Function as PropType<(tab: MultiTab) => void> }, /** * 关闭除当前tab外的其他所有tab */ onCloseOtherTabs: { type: Function as PropType<(tab: MultiTab) => void> }, /** * 关闭当前tab左侧的所有tab */ onCloseLeftTabs: { type: Function as…

    2024年5月23日
    1.1K00

Leave a Reply

登录后才能评论