风控系统之普通规则条件,使用LiteFlow实现
个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview
提要
参考:智能风控筑基手册:全面了解风控决策引擎
前面有可配置输入参数的接口如何设计和风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法两篇文章,分别提出:
1、风控系统服务动态选择,根据配置处理输入参数,转换为系统参数
2、使用Redis
的zset
结构完成简单的指标计算(特征提取)
他们都是一次风控决策流程的一部分,当然完成的风控系统,比较复杂,涉及的功能模块更多,以下仅仅是我的简单梳理。
如上,服务选择和入参处理可配置输入参数的接口如何设计是这篇文章讨论的内容,风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法讨论的是规则集内普通指标计算。
本篇文章讨论通过LiteFlow
这款规则引擎框架实现风控系统的普通规则条件。
规则条件
规则条件是什么?
我将规则划分如下(未来会逐渐完善),规则条件是规则的一部分。
需要注意的是规则条件应该都是灵活可配置,并不是上面这样并列,可以任意复杂的组合。
为什么只是规则条件灵活可配置呢?操作难道不是吗?
可以,但没必要。
如下,是规则(最近24小时转账次数>=10次)示例。
观察可知,其实右半边可以作为一个新的规则独立出去的,所以说,规则操没必要和规则条件混在一起。
规则引擎LiteFlow
规则引擎是为了解耦,编排而生。
LiteFlow
官网:🍤LiteFlow简介 | LiteFlow
LiteFlow
官方文档写的已经非常清晰,花费不到一上午的时间就可以了完全了解了,所以我也不多说些什么了。
为什么需要规则引擎
因为独立组件+灵活编排的需求和规则引擎不谋而合。
设计与实现
组件
组件是规则引擎中最重要的一部分,他是所有规则表达式最终业务的实现。
不使用规则引擎时
在不使用规则引擎时,针对前面普通规则条件,可以设计如下的结构。
一条规则关联一组规则条件,规则条件又最多分为两级,一级指明了二级规则条件“与或非”关系,二级是具体的规则条件。具体的规则条件关键字段是:系统字段(property)、字段类型(property_data_type)、操作(operator)、希望的值(value)。
有了如下的结构该怎么使用也很清晰了
1、查规则
2、查规则条件组
3、根据父条件,确定子条件关系
4、代码解析操作类型,返回条件结果
id | uuid | rule_uuid | parent_uuid | logic_operator | property | property_data_type | operator | value |
---|---|---|---|---|---|---|---|---|
1 | 270a8dc859a940008539f270ae596ad6 | 86cbd8adff914f67b576f0046b5b337d | ||||||
2 | bfbe53d6b5ae4895aef1c4c453e3e16e | 86cbd8adff914f67b576f0046b5b337d | 270a8dc859a940008539f270ae596ad6 | && | ||||
3 | cf46348d533a48db8f027e4db4f6bb7a | 86cbd8adff914f67b576f0046b5b337d | bfbe53d6b5ae4895aef1c4c453e3e16e | S_N_EVENTHOUR | INT | >= | 22 | |
4 | f759541121664847bbc7d944ad1a553f | 86cbd8adff914f67b576f0046b5b337d | bfbe53d6b5ae4895aef1c4c453e3e16e | S_N_EVENTHOUR | INT | <= | 24 | |
5 | ec1e79cc18734fa4ab3daa51fe8597c8 | 86cbd8adff914f67b576f0046b5b337d | bfbe53d6b5ae4895aef1c4c453e3e16e | C_S_FINANCIALCLIENTS | STRING | == | 是 | |
6 | 5a3b35c7d1d04466b16ae2da64383e21 | 86cbd8adff914f67b576f0046b5b337d | 270a8dc859a940008539f270ae596ad6 | && | ||||
7 | 1bed61e83d7e4ad0a813f2fa3bd7b8a9 | 86cbd8adff914f67b576f0046b5b337d | 5a3b35c7d1d04466b16ae2da64383e21 | S_N_EVENTHOUR | INT | >= | 0 | |
8 | 9446d7a9ec284c1ab52c600ac1cfad26 | 86cbd8adff914f67b576f0046b5b337d | 5a3b35c7d1d04466b16ae2da64383e21 | S_N_EVENTHOUR | INT | < | 6 | |
9 | 690e668a2e7c445c80b04ef5e30d3fa4 | 86cbd8adff914f67b576f0046b5b337d | 5a3b35c7d1d04466b16ae2da64383e21 | C_S_FINANCIALCLIENTS | STRING | == | 是 |
使用规则引擎后
首先我们定义组件可以完成字段的比较并返回true
/false
。
那么上面作为组件的只有id
为3、4、5、7、8、9,然后将这些编排成如下表达式即可。
这里简单介绍一些IF
表达式,一共三个参数,第一个为条件,后面两个为true
执行,false
执行,跟三元表达式一样。
IF(OR(AND(3,4,5),AND(7,8,9)),x,y)
是不是很简单,看着确实,但有一个设计必须要搞通,也就是下面我要说的数据上下文。
数据上下文
🍄说明 | LiteFlow
数据上下文这个概念在LiteFlow框架中非常重要,你所有的业务数据都是放在数据上下文中。
要做到可编排,一定是消除每个组件差异性的。如果每个组件出参入参都不一致,那就没法编排了。
LiteFlow对此有独特的设计理念,平时我们写瀑布流的程序时,A调用B,那A一定要把B所需要的参数传递给B,而在LiteFlow框架体系中,每个组件的定义中是不需要接受参数的,也无任何返回的。
每个组件只需要从数据上下文中获取自己关心的数据即可,而不用关心此数据是由谁提供的,同样的,每个组件也只要把自己执行所产生的结果数据放到数据上下文中即可,也不用关心此数据到底是提供给谁用的。这样一来,就从数据层面一定程度的解耦了。从而达到可编排的目的。关于这个理念,也在LiteFlow简介中的设计原则有提到过,给了一个形象的例子,大家可以再去看看。
一旦在数据上下文中放入数据,整个链路中的任一节点都是可以取到的。
我简单说明一下。
如下,表示瀑布流程,从开始到结束,每步调用都需要将数据传递给下一步调用者,完成整个流程。
而对于LiteFlow
,更像是下面这样,整个流程存在这样的数据上下文,每个组件只需要去数据上下文中取自己关心的数据,结果也是一样,放进数据上下文即可。
此模式下,要非常注重数据上下文的管理,数据隔离和共享要非常注意。
相同组件数据问题
对于规则条件组件的问题在于:每个规则里的条件非常多,组件该怎么获取当前组件参数(如:appName==Phone
)。如IF(OR(AND(3,4,5),AND(7,8,9)),x,y)
此表达式转换为我们使用的规则表达式应该是这样的IF(OR(AND(ruleConditionIF,ruleConditionIF,ruleConditionIF),AND(ruleConditionIF,ruleConditionIF,ruleConditionIF)),x,y)
,ruleConditionIF
为规则条件组件。一个表达式中有多个相同的组件意味着他们需要不同的处理,那么数据怎么获取?
LiteFlow
提供了三种不同方式:
1、🍉组件参数 | LiteFlow,定义EL
表达式时声明数据并传入组件
2、🍍组件标签 | LiteFlow,定义组件tag
区别组件
3、🍕私有投递 | LiteFlow,用于私有独有数据传递
下面使用方式二(组件标签)来实现普通条件组件。
表结构与数据
chain
表
create table de_chain
(id bigint auto_increment comment '主键'primary key,application_name varchar(32) default '' not null comment '应用名',chain_name varchar(64) default '' not null comment 'chain名',el_data text not null comment 'el数据',enable bit default b'0' not null comment 'chain状态',description varchar(64) charset utf8mb4 default '' null comment '描述',creator varchar(64) charset utf8mb4 default '' null comment '创建者',create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',updater varchar(64) charset utf8mb4 default '' null comment '更新者',update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',deleted bit default b'0' not null comment '是否删除',constraint uk_codeunique (chain_name)
)comment 'chain表';INSERT INTO coolGuard.de_chain (id, application_name, chain_name, el_data, enable, description, creator, create_time, updater, update_time, deleted) VALUES (1, 'coolGuard', 'mainChain', 'THEN(chain1);', true, '', '', '2024-04-04 22:35:36', '', '2024-04-04 22:40:30', false);
INSERT INTO coolGuard.de_chain (id, application_name, chain_name, el_data, enable, description, creator, create_time, updater, update_time, deleted) VALUES (2, 'coolGuard', 'chain1', 'IF(OR(AND(ruleConditionIf.tag("1"),ruleConditionIf.tag("2")),ruleConditionIf.tag("3")),orderMode,worstMode);', true, '', '', '2024-04-04 22:31:16', '', '2024-04-05 13:25:49', false);
规则条件表
create table de_rule_condition
(id bigint auto_increment comment '主键'primary key,chain_name varchar(64) default '' not null comment 'chain名',field_name varchar(32) default '' not null comment '字段名',operate_type int default 0 not null comment '操作类型',expect_value varchar(32) default '' not null comment '期望值',description varchar(64) charset utf8mb4 default '' null comment '描述',creator varchar(64) charset utf8mb4 default '' null comment '创建者',create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',updater varchar(64) charset utf8mb4 default '' null comment '更新者',update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',deleted bit default b'0' not null comment '是否删除'
)comment '规则条件表';INSERT INTO coolGuard.de_rule_condition (id, chain_name, field_name, operate_type, expect_value, description, creator, create_time, updater, update_time, deleted) VALUES (1, 'chain3', 'appName', 2, 'Phone', '', '', '2024-04-04 22:32:25', '', '2024-04-05 12:24:03', false);
INSERT INTO coolGuard.de_rule_condition (id, chain_name, field_name, operate_type, expect_value, description, creator, create_time, updater, update_time, deleted) VALUES (2, 'chain4', 'customerId', 2, '123456', '', '', '2024-04-05 12:24:03', '', '2024-04-05 12:24:03', false);
INSERT INTO coolGuard.de_rule_condition (id, chain_name, field_name, operate_type, expect_value, description, creator, create_time, updater, update_time, deleted) VALUES (3, 'chain5', 'money', 5, '15', '', '', '2024-04-05 12:24:03', '', '2024-04-05 12:24:03', false);
依赖
<dependency><groupId>com.yomahub</groupId><artifactId>liteflow-spring-boot-starter</artifactId><version>${liteflow.version}</version>
</dependency>
<dependency><groupId>com.yomahub</groupId><artifactId>liteflow-rule-sql</artifactId><version>${liteflow.version}</version>
</dependency>
<dependency><groupId>com.yomahub</groupId><artifactId>liteflow-script-groovy</artifactId><version>${liteflow.version}</version>
</dependency>
配置
liteflow:rule-source-ext-data-map:url: jdbc:mysql://localhost:3306/coolGuard?allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=truedriverClassName: com.mysql.cj.jdbc.Driverusername: wnhyangpassword: 123456applicationName: ${spring.application.name}#是否开启SQL日志sqlLogEnabled: true#是否开启SQL数据轮询自动刷新机制 默认不开启pollingEnabled: truepollingIntervalSeconds: 60pollingStartSeconds: 60#以下是chain表的配置,这个一定得有chainTableName: de_chainchainApplicationNameField: application_namechainNameField: chain_nameelDataField: el_datachainEnableField: enable#以下是script表的配置,如果你没使用到脚本,下面可以不配置# scriptTableName: script
# scriptApplicationNameField: application_name
# scriptIdField: script_id
# scriptNameField: script_name
# scriptDataField: script_data
# scriptTypeField: script_type
# scriptLanguageField: script_language
# scriptEnableField: enable
自定义数据上下文
可以改善,先这样贴出来。
FieldContext
表示经过入参处理后的所有字段集合,后面的规则/指标都会用到的。
/*** @author wnhyang* @date 2024/4/3**/
public class FieldContext {private final Map<String, String> stringFields = new ConcurrentHashMap<>();private final Map<String, Integer> numberFields = new ConcurrentHashMap<>();private final Map<String, Boolean> booleanFields = new ConcurrentHashMap<>();private final Map<String, String> enumFields = new ConcurrentHashMap<>();private final Map<String, LocalDateTime> dateFields = new ConcurrentHashMap<>();private final Map<String, BigDecimal> floatFields = new ConcurrentHashMap<>();public void setStringData(String key, String value) {stringFields.put(key, value);}public String getStringData(String key) {return stringFields.get(key);}public boolean hasStringData(String key) {return stringFields.containsKey(key);}}
普通规则条件组件
当前还不是很完善,TODO
已有说明。
对了,我使用的jdk17
,所有switch
表达式是下面这样,与jdk8
有点区别。
/*** @author wnhyang* @date 2024/4/4**/
@Slf4j
@LiteflowComponent
@RequiredArgsConstructor
public class RuleConditionIf extends NodeIfComponent {private final RuleConditionMapper ruleConditionMapper;@Overridepublic boolean processIf() throws Exception {// 获取当前chainNameString tag = this.getTag();log.info("当前tag:{}", tag);// 获取当前chainName对应的条件RuleCondition ruleCondition = ruleConditionMapper.selectById(tag);log.info("当前chainName对应的条件:{}", ruleCondition);// 获取上下文FieldContext fieldContext = this.getContextBean(FieldContext.class);// 获取条件字段String fieldName = ruleCondition.getFieldName();log.info("条件字段:{}", fieldName);// 获取字段值// TODO 支持String、Integer、BigDecimal、Boolean等String stringData = fieldContext.getStringData(fieldName);log.info("字段值:{}", stringData);OperateType byType = OperateType.getByType(ruleCondition.getOperateType());log.info("操作类型:{}", byType);// TODO 当前是常量,之后要考虑变量String expectValue = ruleCondition.getExpectValue();log.info("期望值值:{}", expectValue);return switch (Objects.requireNonNull(byType)) {case NULL:yield StrUtil.isBlank(stringData);case NOT_NULL:yield !StrUtil.isBlank(stringData);case EQ:yield stringData.equals(expectValue);case NOT_EQ:yield !stringData.equals(expectValue);case CONTAINS:yield stringData.contains(expectValue);case NOT_CONTAINS:yield !stringData.contains(expectValue);case GT:yield Integer.parseInt(stringData) > Integer.parseInt(expectValue);case GTE:yield Integer.parseInt(stringData) >= Integer.parseInt(expectValue);case LT, LTE:yield false;case IN:String[] split1 = expectValue.split(",");for (String s : split1) {if (stringData.equals(s)) {yield true;}}case NOT_IN:String[] split2 = expectValue.split(",");for (String s : split2) {if (stringData.equals(s)) {yield false;}}case PREFIX:yield stringData.startsWith(expectValue);case NOT_PREFIX:yield !stringData.startsWith(expectValue);case SUFFIX:yield stringData.endsWith(expectValue);case NOT_SUFFIX:yield !stringData.endsWith(expectValue);};}
}
操作类型枚举
/*** @author wnhyang* @date 2024/4/3**/
@AllArgsConstructor
@Getter
public enum OperateType {NULL(0),NOT_NULL(1),EQ(2),NOT_EQ(3),GT(4),GTE(5),LT(6),LTE(7),IN(8),NOT_IN(9),CONTAINS(10),NOT_CONTAINS(11),PREFIX(12),NOT_PREFIX(13),SUFFIX(14),NOT_SUFFIX(15);private final Integer type;public static OperateType getByType(Integer type) {for (OperateType operateType : OperateType.values()) {if (operateType.getType().equals(type)) {return operateType;}}return null;}
}
测试
@Slf4j
@RestController
@RequestMapping("/field")
@RequiredArgsConstructor
public class FieldController {private final FieldService fieldService;private final FlowExecutor flowExecutor;@GetMapping("/test")public CommonResult<String> test(@RequestParam("appName") String appName, @RequestParam("customerId") String customerId, @RequestParam("money") String money) {FieldContext fieldContext = new FieldContext();fieldContext.setStringData("appName", appName);fieldContext.setStringData("customerId", customerId);fieldContext.setStringData("money", money);LiteflowResponse main1 = flowExecutor.execute2Resp("mainChain", null, fieldContext);log.info(String.valueOf(main1));return success("test");}
}
结果
mainChain
的EL
表达式为THEN(chain1);
,chain1
为子流程
IF(OR(AND(ruleConditionIf.tag("1"),ruleConditionIf.tag("2")),ruleConditionIf.tag("3")),orderMode,worstMode);
,ruleConditionIf
为上面的规则条件组件。
最终应该是这样的:THEN(IF(OR(AND(ruleConditionIf.tag("1"),ruleConditionIf.tag("2")),ruleConditionIf.tag("3")),orderMode,worstMode));
参数为:appName:Phone,customerId:235246,money:35
时
此时执行流程为:ruleConditionIf<17>==>ruleConditionIf<2>==>ruleConditionIf<2>==>orderMode<0>
参数为:
appName:Phone,customerId:235246,money:3
时
此时执行流程为:ruleConditionIf<42>==>ruleConditionIf<2>==>ruleConditionIf<1>==>worstMode<0>
总结
LiteFlow
可玩性还是很强的,未来我还会继续完善打造自己设计并实现的风控系统。冲冲冲!!!
写在最后
拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。
个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview
相关文章:

风控系统之普通规则条件,使用LiteFlow实现
个人博客:无奈何杨(wnhyang) 个人语雀:wnhyang 共享语雀:在线知识共享 Github:wnhyang - Overview 提要 参考:智能风控筑基手册:全面了解风控决策引擎 前面有可配置输入参数的接…...

在一套Dockerfile中完成编译和运行环境部署
大纲 解释型语言编译环境解释环境编译型语言编译环境运行环境 方法编译环境安装系统安装编译依赖下载代码特殊处理(可以忽略)编译准备(可以忽略)编译打包依赖(编译结果) 运行环境安装操作系统安装运行时依赖…...
ubuntu系统里克隆github代码到本地,提示fatal: unable to connect to github.com的解决方案
打开命令行终端生成一个新的SSH密钥对。如果你还没有SSH密钥或者想创建一个新的,可以使用以下命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com"当系统提示你“Enter a file in which to save the key”,时,…...
常见docker使用命令
#搭建镜像 “”" sudo docker build -t es_refresh:V1.20230303 . “”" #启动容器 “”" docker run -d --namepara_classify -v /etc/localtime:/etc/localtime -v /data/chenhw/multi_label_classification:/edb2vec -p 8066:8066 --gpus ‘“device0”’…...

Ubuntu系统中设置中文输入法的教程
1、Ubuntu介绍: (https://cn.ubuntu.com/) (Ubuntu | 全球领先的用于个人电脑、平板及手机的操作系统) Ubuntu是一款基于Debian的开源Linux操作系统,由英国Canonical公司赞助支持的全球性社区共同开发。U…...

练习14 Web [极客大挑战 2019]Upload
phtml格式绕过,burp修改content-type绕过,常见的文件上传存放目录名 题目就叫upload,打开靶机 直接上传一个图片格式的一句话木马,返回如下: 提交练习5和9中的两种可以执行图片格式php代码的文件,修改con…...

3.6k star, 免费开源跨平台的数据库管理工具 dbgate
3.6k star, 免费开源跨平台的数据库管理工具 dbgate 分类 开源分享 项目名: dbgate -- 免费开源跨平台的数据库管理工具 Github 开源地址: GitHub - dbgate/dbgate: Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under…...
2024.3.2力扣每日一题——受限条件下可到达节点的数目
2024.3.2 题目来源我的题解方法一 深度优先搜索方法二 并查集 题目来源 力扣每日一题;题序:2368 我的题解 方法一 深度优先搜索 使用深度优先搜索实现,在搜索过程中根据restricted进行截停。 时间复杂度:O(n) 空间复杂度&#…...

在云端遇见雨云:一位服务器寻觅者的指南
引言:寻觅一座云端归宿 当我踏入数字世界的边缘,带着对网络的探索与期待,我迫切需要一座安全可靠的数字栖息地。云计算技术正如一场魔法般的变革,而在这片广袤的云端中,雨云就像是一位友善的向导,引领我穿越…...

Pygame基础10-物理模拟
PyMunk PyMunk是一个模拟物理的库。 注意,PyMunk只是进行物理模拟,不包含可视化的功能。如果需要可视化,可使用pygame等库。 可用pip安装pymunk pip install pymunk pymunk中的概念: space: 物理空间。 包含gravity 模…...

蓝桥杯 --- 日期问题模板
目录 1.如何判断闰年 2.如何遍历当前年份的每一天 3.如果想要输出某一年某一天到某一年某一天之间一共有多少天。 4.精确到具体周几到周几的问题分析 5.如何直接通过一层for循环枚举年月日 习题: 蓝桥杯竞赛特别喜欢考日期问题,今天给大家分享一下…...

Java 处理Mysql获取树形的数据
Mysql数据: 代码如下: Entity: Data Accessors(chain true) public class Region {private BigInteger id;//名称private String name;//父idprivate BigInteger parentId;private List<Region> children;private Integer createTim…...

前端三剑客 —— CSS ( 坐标问题 、定位问题和图片居中 )
前期内容回顾: 1.常见样式 text-shadow x轴 y轴 阴影的模糊程度 阴影的颜色 box-shadow border-radio 实现圆角 margin 内边距 padding 外边距 background 2.特殊样式 媒体查询:media 自定义字体:font-face { font-family:自定义名称&#…...

向量数据库 | AI时代的航道灯塔
向量数据库 | AI时代的航道灯塔 什么是向量检索服务拍照搜商品 你使用过向量数据库吗?使用体验?为什么向量数据库能借由大模型引起众多关注向量数据库在当前AI热潮中是昙花一现,还是未来AI时代的航道灯塔? 今天的话题主要是讨论向…...
Linux中的conntrack命令深入解析
在Linux网络管理和监控领域,conntrack命令是一个强大的工具,它提供了对netfilter连接跟踪系统的直接访问🔍。这篇文章将深入探讨conntrack的由来、底层原理、参数意义,以及其常见用法,并对返回结果的每个字段进行详细解…...

反截屏控制技术如何防止信息通过手机拍照泄漏?
反截屏控制技术为企业数据安全提供了重要的防护措施。通过以下几点,有效阻止了信息通过拍照等方式的泄漏: 反截屏控制开启,用户启动截屏操作时,允许非涉密内容截屏操作,但所有涉密内容窗口会自动隐藏,防止涉…...
0.k8s简介
目录 k8s是什么 k8s不是什么 云原生 微服务 整体式架构与微服务架构 微服务的特性 微服务的优势 k8s是什么 Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快…...

VScode 集成终端设置默认打开当前文件夹 mac系统
一.快捷键设置 搜索 openInIntegratedTerminal 如图: 二.设置cmd 默认打开位置 点击设置 搜索 ntegrated:cwd 如下图: 三.查看ip 快捷指令: ipconfig getifaddr en0...

HDLbits 刷题 -- Alwaysblock2
学习: For hardware synthesis, there are two types of always blocks that are relevant: Combinational: always (*)Clocked: always (posedge clk) Clocked always blocks create a blob of combinational logic just like combinational always blocks, but…...

一、Docker部署GitLab(详细步骤)
Docker部署GitLab(详细步骤) 一、拉取镜像二、启动容器三、修改配置四、修改密码五、浏览器访问 一、拉取镜像 docker安装教程:https://qingsi.blog.csdn.net/article/details/131270071 docker pull gitlab/gitlab-ce:latest二、启动容器 …...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...