Kafka、Kafka Streams、Drools、Redis 和分布式数据库的风控系统程序
由于实时风控系统难度较大,集成框架设计各个单位均有特点,快速建立一个通用性较强,学习、实施和使用成本较低的框架尤其重要。
提供一个简化的 Java 程序示例,演示如何将 Kafka 消息中间件、Kafka Streams 计算引擎、Drools 规则引擎、Redis 内存数据库和分布式数据库集成在一起。程序的主要功能是:
- 从 Kafka 中消费实时交易数据。
- 从 Redis 获取对应的风险标签,如果没有则从分布式数据库获取并更新到 Redis。
- 使用 Drools 规则引擎对交易数据和风险标签进行评估。
- 将评估结果发送回支付业务系统或记录下来。
示例图:
实时交易模块:接收交易数据 -> 获取风险标签(Redis)---> 调用规则引擎 —> 评估结果返回
↓ ↓ ↑
规则引擎模块:交易数据 + 风险标签 ---> 规则执行 -----------> 输出评估结果(通过/拒绝)
为了简化示例,我们将:
创建一个简单的 Kafka 生产者,向 transaction-topic
发送交易数据。
2. 生产测试数据
- 使用简单的交易数据结构和风险标签。
- 定义基本的 Drools 规则。
- 使用内存中的 H2 数据库模拟分布式数据库
-
项目结构和依赖
1. 项目结构
risk-control-demo/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com.example.riskcontrol/ │ │ │ ├── RiskControlApplication.java // 主应用程序 │ │ │ ├── Transaction.java // 交易数据模型 │ │ │ ├── RiskTag.java // 风险标签模型 │ │ │ ├── RiskEvaluator.java // 风险评估类 │ │ │ ├── RedisService.java // Redis 服务类 │ │ │ ├── DatabaseService.java // 数据库服务类 │ │ │ └── KafkaStreamsConfig.java // Kafka Streams 配置 │ │ └── resources/ │ │ ├── drools/ │ │ │ └── rules.drl // Drools 规则文件 │ │ └── application.properties // 应用程序配置 ├── pom.xml // Maven 项目配置
- 2. 依赖库(在
pom.xml
中) -
<dependencies><!-- Kafka Streams --><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-streams</artifactId><version>3.4.0</version></dependency><!-- Drools Core --><dependency><groupId>org.kie</groupId><artifactId>kie-api</artifactId><version>7.73.0.Final</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-core</artifactId><version>7.73.0.Final</version></dependency><dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.73.0.Final</version></dependency><!-- Redis Client (Jedis) --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.1</version></dependency><!-- H2 Database --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>2.1.214</version><scope>runtime</scope></dependency><!-- JSON Processing --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.0</version></dependency><!-- Logging --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.36</version></dependency> </dependencies>
详细代码
1. Transaction.java(交易数据模型)
-
package com.example.riskcontrol;import java.io.Serializable;public class Transaction implements Serializable {private String transactionId;private String accountId;private double amount;private long timestamp;// Constructors, getters, setters, toString()public Transaction() {}public Transaction(String transactionId, String accountId, double amount, long timestamp) {this.transactionId = transactionId;this.accountId = accountId;this.amount = amount;this.timestamp = timestamp;}// Getters and Setters// toString() method }
2. RiskTag.java(风险标签模型)
-
package com.example.riskcontrol;import java.io.Serializable;public class RiskTag implements Serializable {private String accountId;private int riskLevel; // 1-低风险, 2-中风险, 3-高风险// Constructors, getters, setters, toString()public RiskTag() {}public RiskTag(String accountId, int riskLevel) {this.accountId = accountId;this.riskLevel = riskLevel;}// Getters and Setters// toString() method }
3. RedisService.java(Redis 服务类)
-
package com.example.riskcontrol;import redis.clients.jedis.Jedis;public class RedisService {private Jedis jedis;public RedisService(String host, int port) {jedis = new Jedis(host, port);}public RiskTag getRiskTag(String accountId) {String riskLevelStr = jedis.get("risk:" + accountId);if (riskLevelStr != null) {int riskLevel = Integer.parseInt(riskLevelStr);return new RiskTag(accountId, riskLevel);}return null;}public void setRiskTag(RiskTag riskTag) {jedis.set("risk:" + riskTag.getAccountId(), String.valueOf(riskTag.getRiskLevel()));}public void close() {jedis.close();} }
4. DatabaseService.java(数据库服务类)
-
package com.example.riskcontrol;import java.sql.*;public class DatabaseService {private Connection connection;public DatabaseService() throws SQLException {// 连接 H2 内存数据库connection = DriverManager.getConnection("jdbc:h2:mem:testdb");initializeDatabase();}private void initializeDatabase() throws SQLException {Statement stmt = connection.createStatement();// 创建风险标签表String sql = "CREATE TABLE IF NOT EXISTS risk_tags (" +"account_id VARCHAR(255) PRIMARY KEY," +"risk_level INT" +")";stmt.executeUpdate(sql);// 插入示例数据sql = "INSERT INTO risk_tags (account_id, risk_level) VALUES ('account123', 2)";stmt.executeUpdate(sql);stmt.close();}public RiskTag getRiskTag(String accountId) throws SQLException {String sql = "SELECT risk_level FROM risk_tags WHERE account_id = ?";PreparedStatement pstmt = connection.prepareStatement(sql);pstmt.setString(1, accountId);ResultSet rs = pstmt.executeQuery();if (rs.next()) {int riskLevel = rs.getInt("risk_level");rs.close();pstmt.close();return new RiskTag(accountId, riskLevel);} else {rs.close();pstmt.close();return null;}}public void close() throws SQLException {connection.close();} }
5. RiskEvaluator.java(风险评估类)
-
package com.example.riskcontrol;import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession;public class RiskEvaluator {private KieSession kieSession;public RiskEvaluator() {// 初始化 DroolsKieServices kieServices = KieServices.Factory.get();KieContainer kieContainer = kieServices.newKieClasspathContainer();kieSession = kieContainer.newKieSession("ksession-rules");}public boolean evaluate(Transaction transaction, RiskTag riskTag) {kieSession.insert(transaction);kieSession.insert(riskTag);int fired = kieSession.fireAllRules();kieSession.dispose();return fired > 0;} }
6. drools/rules.drl(Drools 规则文件)
-
package com.example.riskcontrolimport com.example.riskcontrol.Transaction; import com.example.riskcontrol.RiskTag;rule "High Risk Transaction" when$transaction : Transaction( amount > 10000 )$riskTag : RiskTag( riskLevel == 3 ) thenSystem.out.println("High risk transaction detected: " + $transaction); endrule "Medium Risk Transaction" when$transaction : Transaction( amount > 5000 && amount <= 10000 )$riskTag : RiskTag( riskLevel >= 2 ) thenSystem.out.println("Medium risk transaction detected: " + $transaction); endrule "Low Risk Transaction" when$transaction : Transaction()$riskTag : RiskTag( riskLevel == 1 ) thenSystem.out.println("Transaction passed: " + $transaction); end
7. KafkaStreamsConfig.java(Kafka Streams 配置)
-
package com.example.riskcontrol;import org.apache.kafka.common.serialization.Serdes; import org.apache.kafka.streams.StreamsConfig;import java.util.Properties;public class KafkaStreamsConfig {public static Properties getProperties() {Properties props = new Properties();props.put(StreamsConfig.APPLICATION_ID_CONFIG, "risk-control-app");props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());return props;} }
8. RiskControlApplication.java(主应用程序)
-
package com.example.riskcontrol;import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.kafka.common.serialization.Serdes; import org.apache.kafka.streams.KafkaStreams; import org.apache.kafka.streams.StreamsBuilder; import org.apache.kafka.streams.kstream.KStream;import java.sql.SQLException;public class RiskControlApplication {public static void main(String[] args) throws SQLException {// 初始化服务RedisService redisService = new RedisService("localhost", 6379);DatabaseService databaseService = new DatabaseService();RiskEvaluator riskEvaluator = new RiskEvaluator();// 配置 Kafka StreamsStreamsBuilder builder = new StreamsBuilder();KStream<String, String> sourceStream = builder.stream("transaction-topic");// 处理流sourceStream.foreach((key, value) -> {try {ObjectMapper objectMapper = new ObjectMapper();Transaction transaction = objectMapper.readValue(value, Transaction.class);// 从 Redis 获取风险标签RiskTag riskTag = redisService.getRiskTag(transaction.getAccountId());if (riskTag == null) {// 如果 Redis 中没有,从数据库获取并更新到 RedisriskTag = databaseService.getRiskTag(transaction.getAccountId());if (riskTag != null) {redisService.setRiskTag(riskTag);} else {// 如果数据库中也没有,设定默认风险标签riskTag = new RiskTag(transaction.getAccountId(), 1);}}// 使用 Drools 进行风险评估boolean isRisk = riskEvaluator.evaluate(transaction, riskTag);// 根据评估结果进行处理if (isRisk) {System.out.println("Transaction " + transaction.getTransactionId() + " is risky. Action: Block");// 发送阻止交易的消息或记录日志} else {System.out.println("Transaction " + transaction.getTransactionId() + " is safe. Action: Approve");// 发送通过交易的消息或记录日志}} catch (Exception e) {e.printStackTrace();}});// 启动 Kafka StreamsKafkaStreams streams = new KafkaStreams(builder.build(), KafkaStreamsConfig.getProperties());streams.start();// 添加关闭钩子Runtime.getRuntime().addShutdownHook(new Thread(() -> {streams.close();redisService.close();try {databaseService.close();} catch (SQLException e) {e.printStackTrace();}}));} }
运行示例
1. 启动必要的服务
- Redis:确保 Redis 服务在本地的
6379
端口运行。 - Kafka:确保 Kafka 服务在本地的
9092
端口运行,并创建主题transaction-topic
。
package com.example.riskcontrol;import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.kafka.clients.producer.*;import java.util.Properties;public class TransactionProducer {public static void main(String[] args) {Properties props = new Properties();props.put("bootstrap.servers", "localhost:9092");props.put("acks", "all");props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");Producer<String, String> producer = new KafkaProducer<>(props);try {ObjectMapper objectMapper = new ObjectMapper();// 创建示例交易数据Transaction transaction = new Transaction("tx1001", "account123", 12000.0, System.currentTimeMillis());String transactionJson = objectMapper.writeValueAsString(transaction);ProducerRecord<String, String> record = new ProducerRecord<>("transaction-topic", transaction.getTransactionId(), transactionJson);producer.send(record);System.out.println("Transaction sent: " + transactionJson);} catch (Exception e) {e.printStackTrace();} finally {producer.close();}}
}
. 运行应用程序
- 先运行
RiskControlApplication
,启动风控系统。 - 再运行
TransactionProducer
,发送交易数据。
4. 预期输出
风控系统将处理交易数据,使用 Drools 规则引擎进行评估,并根据规则打印评估结果。例如:
High risk transaction detected: Transaction{transactionId='tx1001', accountId='account123', amount=12000.0, timestamp=...}
Transaction tx1001 is risky. Action: Block
说明
- Kafka Streams:用于实时消费交易数据,并进行数据处理。
- Drools:规则引擎,用于评估交易的风险级别。
- Redis:作为缓存,存储风险标签,快速获取账户的风险级别。
- 分布式数据库(H2 数据库模拟):当 Redis 中没有风险标签时,从数据库获取,并更新到 Redis。
- 风险标签:简单地使用风险级别(1-低风险,2-中风险,3-高风险)来表示。
注意事项
- 异常处理:在实际应用中,需要更完善的异常处理机制,防止因异常导致程序崩溃。
- 多线程与并发:在高并发场景下,需要考虑线程安全和性能优化。
- 资源管理:确保所有的资源(如数据库连接、Redis 连接、Kafka Streams)在程序结束时正确关闭。
- 配置管理:将硬编码的配置(如主机地址、端口、主题名)提取到配置文件中,便于管理和修改。
5、系统整体各个模块的调度关系流程
以下是系统各模块之间的交互流程,详细说明了调度关系:
-
交易数据的接收与预处理:
- 支付业务系统将实时交易数据通过消息队列模块(Kafka)或接口与通信模块(API/gRPC)发送到实时交易数据处理模块。
- 实时交易数据处理模块接收数据后,进行数据预处理,如格式验证和完整性检查。
-
风险标签的获取:
- 实时交易数据处理模块需要获取交易涉及的账户或用户的风险标签。
- 首先从**数据存储与缓存模块(Redis)**中查询风险标签。
- 如果缓存中没有对应的风险标签,则从分布式数据库中读取,并更新到缓存。
-
风险评估:
- 实时交易数据处理模块将交易数据和风险标签一起传递给规则引擎模块。
- 规则引擎模块根据预定义的业务规则,对交易进行风险评估,生成评估结果(如通过、拒绝、需人工审核)。
-
评估结果的返回:
- 规则引擎模块将评估结果返回给实时交易数据处理模块。
- 实时交易数据处理模块通过接口与通信模块将评估结果反馈给支付业务系统,执行相应的业务操作。
-
风险标签的批量更新:
- 批量风险标签处理模块定期执行,获取历史数据进行风险标签的重新计算。
- 计算出的风险标签存储在分布式数据库中,并同步更新到Redis 缓存。
-
系统监控与安全:
- 监控与运维模块持续监控各模块的状态和性能,收集日志信息,设置报警机制。
- 安全与合规模块确保数据传输和存储的安全性,对各模块的访问进行权限控制,满足合规要求。
[支付业务系统]|v
1. 发送交易数据|v
[消息队列模块(Kafka)/接口与通信模块(API/gRPC)]|v
[实时交易数据处理模块]|+--> 2. 从缓存获取风险标签| || v| [数据存储与缓存模块(Redis)]| || 若未命中| v| 从数据库获取并更新缓存| || [分布式数据库]|+--> 3. 调用规则引擎模块| || v| [规则引擎模块]| || 执行风险评估| || 返回评估结果|+--> 4. 返回评估结果给支付业务系统| |v v
[接口与通信模块] <---> [支付业务系统]
总结
上述示例提供了一个基本的程序框架,演示了如何将 Kafka、Kafka Streams、Drools、Redis 和分布式数据库集成在一起,完成实时风控的基本功能。在实际项目中,需要根据具体的业务需求和技术环境,对程序进行扩展和优化。
相关文章:
Kafka、Kafka Streams、Drools、Redis 和分布式数据库的风控系统程序
由于实时风控系统难度较大,集成框架设计各个单位均有特点,快速建立一个通用性较强,学习、实施和使用成本较低的框架尤其重要。 提供一个简化的 Java 程序示例,演示如何将 Kafka 消息中间件、Kafka Streams 计算引擎、Drools 规则…...

C++在实际项目中的应用第一课:游戏开发中的C++
第五章:C在实际项目中的应用 第一课:游戏开发中的C 1. 游戏引擎架构的详细分析 游戏引擎是现代游戏开发的核心,负责处理图形渲染、物理计算、音频管理和用户输入等多项功能。以下是游戏引擎架构的各个主要组成部分及其详细分析。 1.1 渲染…...

一键下载海外youtbe视频 解锁版 支持多分辨率
下载:https://pan.quark.cn/s/387e1110ebe5 【应用名称】:Snaptube 【应用版本】:7.28.0 【应用大小】:26.6M 【测试机型】:小米10S 【适用平台】:Andriod 【版本说明】:解锁版...
Scala内部类的运用
内部类:定义在类里面的类(内部类可以访问私有成员用它来操作类的私有成员,封闭性更好) class Student{var age18def say():Unit{}class Book{val bookName: Any "Scala程序设计"}}object Test19 {def main(args: Arra…...

【在Linux世界中追寻伟大的One Piece】Socket编程UDP
目录 1 -> UDP网络编程 1.1 -> V1版本 -echo server 1.2 -> V2版本 -DictServer 1.3 -> V2版本 -DictServer(封装版) 1 -> UDP网络编程 1.1 -> V1版本 -echo server 简单的回显服务器和客户端代码。 备注:代码中会用到地址转换函数。 noc…...

机器学习在聚合物及其复合材料中的应用与实践
在当前的工业和科研领域,聚合物及其复合材料因其卓越的物理和化学性能而受到广泛关注。这些材料在航空航天、汽车制造、能源开发和生物医学等多个行业中发挥着至关重要的作用。随着材料科学的发展,传统的实验和理论分析方法已逐渐无法满足新材料研发的需…...
用大模型或者预训练模型对图片进行OCR
背景:使用大模型或者预训练模型(比如来自huggingface上的模型)对图片进行OCR,并将识别结果标记在图片原文的下方。 愿我们终有重逢之时,而你还记得我们曾经讨论的话题。 QQ group 868373192 QQ second group 277356808 要使用预训练模型对图片进行OCR(光学字符识别)…...

如何使用的是github提供的Azure OpenAI服务
使用的是github提供的Azure OpenAI的服务gpt-4o 说明:使用的是github提供的Azure OpenAI的服务,可以无限薅羊毛。开源地址 进入: 地址 进入后点击 右上角“Get API key”按钮 点击“Get developer key” 选择Beta版本“Generate new to…...

elementUI进度条el-progress不显示白色
效果图 通过设置百分比为100,动态修改进度条的宽度完成 <template><div class"myProgressBox"><div class"index">{{ index }}</div><div class"typeTitle">{{ typeTitle }}</div><div class"twoP…...

学习笔记——路由——IP组播-PIM(协议无关组播)-概述/PIM模式
八、PIM(协议无关组播) 1、前言 在单播中,是一对一的模型,路由器将IP数据包发往目标地址,因此,单播路由器不用关心发送数据包得源地址。而组播数据流量由组播产生,发向一组接收者,那们组播路由器如何这道…...
TCP 协议学习
一、引言 在当今的网络通信世界中,TCP(Transmission Control Protocol,传输控制协议)是最为重要的协议之一。它为各种网络应用提供了可靠的、有序的数据传输服务,是互联网通信的基石。无论是网页浏览、电子邮件发送、…...
python3的基本数据类型:String(字符串)
一. 简介 本文简单学习了一下 python3中的一种数据类型: String(字符串)。 Python中的String类型是一种用于表示文本数据的数据类型。 它可以包含字母、数字、符号等字符,用于存储文本信息。 二. python3的基本数据类型&…...

面试总结(2024/10/16)
面试总结(2024/10/16) 面试11.闭包2.promise3.全局数据的保存4.多模板切换,布局,系统主题颜色5.同一个搜索,不同的搜索条件,输入框不同的校验方法6.自定义一个组件,包括哪些属性7.多个父组件之间…...

从图像识别到聊天机器人:Facebook AI的多领域应用
随着人工智能技术的快速发展,Facebook已在多个领域内广泛应用AI技术,以提升用户体验、提高效率并推动创新。从图像识别到聊天机器人,Facebook的AI应用涵盖了社交媒体的方方面面,下面我们将深入探讨这些应用的具体实现及其对用户生…...

linux中级(NFS服务器)
NFS:用于在NNIX/Linux主机之间进行文件共享的协议 流程:首先服务端开启RPC服务,并开启111端口,服务器端启动NFS服务,并向RPC注册端口信息,客户端启动RPC,向服务器RPC服务请求NFS端口࿰…...

微软主动出击,“钓”出网络钓鱼者
微软正采取一种巧妙的策略来对抗网络钓鱼行为者,其手段是通过访问Azure平台创建高度仿真的蜜罐租户,以此作为诱饵,吸引网络犯罪分子进入,进而收集他们的相关信息。 凭借所收集的数据,微软能够绘制出恶意基础设施的地图…...

Xcode16 编译运行YYCache iOS18 sqlite3_finalize 闪退问题解决方案
问题原因 升级Xcode 16 之后,真机运行APP,发现会有Crash,崩溃堆栈线上Crash 在 YYCache 之中。如下图所示 崩溃堆栈如下: * thread #1, queue com.apple.main-thread, stop reason signal SIGABRTframe #0: 0x00000001d9391…...

Kafka-Windows搭建全流程(环境,安装包,编译,消费案例,远程连接,服务自启,可视化工具)
目录 一. Kafka安装包获取 1. 官网地址 2. 百度网盘链接 二. 环境要求 1. Java 运行环境 (1) 对 java 环境变量进行配置 (2) 下载完毕之后进行解压 三. 启动Zookeeper 四. 启动Kafka (1) 修改Conf下的server.properties文件,修改kafka的日志文件路径 (2)…...
django模板相关配置
模板引擎配置 Django支持多种模板引擎,最常用的是Django自带的模板引擎和Jinja2模板引擎。模板引擎的配置主要在settings.py文件中的TEMPLATES列表中进行。 BACKEND:指定模板引擎。例如,BACKEND: django.template.backends.django.DjangoTe…...
MongoDB等保限制下的连接认证问题
目录 一、问题描述 二、解决方案 三、代码示例 四、拓展知识 一、问题描述 用户调整用户连接认证机制以满足等保要求,调整后程序连接mongodb失败。数据库日志报错如下: {"t":{"$date":"2024-10-10T14:39:07.825+08:00"},"s":&q…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...

算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...

Element-Plus:popconfirm与tooltip一起使用不生效?
你们好,我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip,产品要求是两个需要结合一起使用,也就是鼠标悬浮上去有提示文字,并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...