当前位置: 首页 > news >正文

SpringBoot集成Flink-CDC,实现对数据库数据的监听

一、什么是 CDC ?

CDC 是Change Data Capture(变更数据获取)的简称。 核心思想是,监测并捕获数据库的变动(包括数据或数据表的插入、 更新以及删除等),将这些变更按发生的顺序完整记录下来,写入到消息中间件中以供其他服务进行订阅及消费。

二、Flink-CDC 是什么?

CDC Connectors for Apache Flink是一组用于Apache Flink 的源连接器,使用变更数据捕获 (CDC) 从不同数据库获取变更。用于 Apache Flink 的 CDC 连接器将 Debezium 集成为捕获数据更改的引擎。所以它可以充分发挥 Debezium 的能力。

大概意思就是,Flink 社区开发了 flink-cdc-connectors 组件,这是一个可以直接从 MySQL、 PostgreSQL等数据库直接读取全量数据和增量变更数据的 source 组件。

Flink-CDC 开源地址: Apache/Flink-CDC

Flink-CDC 中文文档:Apache Flink CDC | Apache Flink CDC

三、SpringBoot 整合 Flink-CDC

3.1、如何集成到SpringBoot中?

Flink 作业通常独立于一般的服务之外,专门编写代码,用 Flink 命令行工具来运行和停止。将Flink 作业集成到 Spring Boot 应用中并不常见,而且一般也不建议这样做,因为Flink作业一般运行在大数据环境中。

然而,在特殊需求下,我们可以做一些改变使 Flink 应用适应 Spring Boot 环境,比如在你的场景中使用 Flink CDC 进行 数据变更捕获。将 Flink 作业以本地项目的方式启动,集成在 Spring Boot应用中,可以使用到 Spring 的便利性。

  • CommandLineRunner
  • ApplicationRunner

3.2、集成举例

1、CommandLineRunner

@SpringBootApplication
public class MyApp {public static void main(String[] args) {SpringApplication.run(MyApp.class, args);}@Beanpublic CommandLineRunner commandLineRunner(ApplicationContext ctx) {return args -> {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();DebeziumSourceFunction<String> sourceFunction = MySqlSource.<String>builder().hostname("localhost").port(3306).username("flinkuser").password("flinkpw").databaseList("mydb") // monitor all tables under "mydb" database.tableList("mydb.table1", "mydb.table2") // monitor only "table1" and "table2" under "mydb" database.deserializer(new StringDebeziumDeserializationSchema()) // converts SourceRecord to String.build();DataStreamSource<String> mysqlSource = env.addSource(sourceFunction);// formulate processing logic here, e.g., printing to standard outputmysqlSource.print();// execute the Flink job within the Spring Boot applicationenv.execute("Flink CDC");};}
}

2、ApplicationRunner

@SpringBootApplication
public class FlinkCDCApplication implements ApplicationRunner {public static void main(String[] args) {SpringApplication.run(FlinkCDCApplication.class, args);}@Overridepublic void run(ApplicationArguments args) throws Exception {final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// Configure your Flink job hereDebeziumSourceFunction<String> sourceFunction = MySqlSource.<String>builder().hostname("localhost").port(3306).username("flinkuser").password("flinkpw").databaseList("mydb")// set other source options ....deserializer(new StringDebeziumDeserializationSchema()) // Converts SourceRecord to String.build();DataStream<String> cdcStream = env.addSource(sourceFunction);// Implement your processing logic here// For example:cdcStream.print();// Start the Flink job within the Spring Boot applicationenv.execute("Flink CDC with Spring Boot");}
}

这次用例采用 ApplicationRunner,不过要改变一下,让 Flink CDC 作为 Bean 来实现。

四、功能实现

4.1、功能逻辑

总体来讲,不太想把 Flink CDC单独拉出来,更想让它依托于一个服务上,彻底当成一个组件。

其中在生产者中,我们将要进行实现:

4.2、所需环境

  • MySQL 5.7 +:确保源数据库已经开启 Binlog 日志功能,并且设置 Row 格式
  • Spring Boot2.7.6:还是不要轻易使用 3.0 以上为好,有好多jar没有适配
  • RabbitMQ:适配即可
  • Flink CDC:特别注意版本

4.3、Flink CDC POM依赖

<flink.version>1.13.6</flink.version><dependency><groupId>org.apache.flink</groupId><artifactId>flink-clients_2.12</artifactId><version>${flink.version}</version>
</dependency><dependency><groupId>org.apache.flink</groupId><artifactId>flink-java</artifactId><version>${flink.version}</version>
</dependency>
<dependency><groupId>org.apache.flink</groupId><artifactId>flink-streaming-java_2.12</artifactId><version>${flink.version}</version>
</dependency>
<!--mysql -cdc-->
<dependency><groupId>com.ververica</groupId><artifactId>flink-connector-mysql-cdc</artifactId><version>2.0.0</version>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version>
</dependency>
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.5</version>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.10</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.42</version>
</dependency>

上面是一些Flink CDC必须的依赖,当然如果需要实现其他数据库,可以替换其他数据库的CDC jar。怎么安排jar包的位置和其余需要的jar,这个可自行调整。

4.4、代码展示

核心类

  • MysqlEventListener:配置类
  • MysqlDeserialization:MySQL消息读取自定义序列化
  • DataChangeInfo:封装的变更对象
  • DataChangeSink:继承一个Flink提供的抽象类,用于定义数据的输出或“下沉”逻辑,sink 是Flink处理流的最后阶段,通常用于将数据写入外部系统,如数据库、文件系统、消息队列等
(1)通过 ApplicationRunner 接入 SpringBoot
@Component
public class MysqlEventListener implements ApplicationRunner {private final DataChangeSink dataChangeSink;public MysqlEventListener(DataChangeSink dataChangeSink) {this.dataChangeSink = dataChangeSink;}@Overridepublic void run(ApplicationArguments args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);DebeziumSourceFunction<DataChangeInfo> dataChangeInfoMySqlSource = buildDataChangeSourceRemote();DataStream<DataChangeInfo> streamSource = env.addSource(dataChangeInfoMySqlSource, "mysql-source").setParallelism(1);streamSource.addSink(dataChangeSink);env.execute("mysql-stream-cdc");}private DebeziumSourceFunction<DataChangeInfo> buildDataChangeSourceLocal() {return MySqlSource.<DataChangeInfo>builder().hostname("127.0.0.1").port(3306).username("root").password("0507").databaseList("flink-cdc-producer").tableList("flink-cdc-producer.producer_content", "flink-cdc-producer.name_content")/** initial初始化快照,即全量导入后增量导入(检测更新数据写入)* latest:只进行增量导入(不读取历史变化)* timestamp:指定时间戳进行数据导入(大于等于指定时间错读取数据)*/.startupOptions(StartupOptions.latest()).deserializer(new MysqlDeserialization()).serverTimeZone("GMT+8").build();}
}
(2)自定义 MySQL 消息读取序列化
public class MysqlDeserialization implements DebeziumDeserializationSchema<DataChangeInfo> {public static final String TS_MS = "ts_ms";public static final String BIN_FILE = "file";public static final String POS = "pos";public static final String CREATE = "CREATE";public static final String BEFORE = "before";public static final String AFTER = "after";public static final String SOURCE = "source";public static final String UPDATE = "UPDATE";/*** 反序列化数据,转为变更JSON对象*/@Overridepublic void deserialize(SourceRecord sourceRecord, Collector<DataChangeInfo> collector) {String topic = sourceRecord.topic();String[] fields = topic.split("\.");String database = fields[1];String tableName = fields[2];Struct struct = (Struct) sourceRecord.value();final Struct source = struct.getStruct(SOURCE);DataChangeInfo dataChangeInfo = new DataChangeInfo();dataChangeInfo.setBeforeData(getJsonObject(struct, BEFORE).toJSONString());dataChangeInfo.setAfterData(getJsonObject(struct, AFTER).toJSONString());//5.获取操作类型  CREATE UPDATE DELETEEnvelope.Operation operation = Envelope.operationFor(sourceRecord);
//        String type = operation.toString().toUpperCase();
//        int eventType = type.equals(CREATE) ? 1 : UPDATE.equals(type) ? 2 : 3;dataChangeInfo.setEventType(operation.name());dataChangeInfo.setFileName(Optional.ofNullable(source.get(BIN_FILE)).map(Object::toString).orElse(""));dataChangeInfo.setFilePos(Optional.ofNullable(source.get(POS)).map(x -> Integer.parseInt(x.toString())).orElse(0));dataChangeInfo.setDatabase(database);dataChangeInfo.setTableName(tableName);dataChangeInfo.setChangeTime(Optional.ofNullable(struct.get(TS_MS)).map(x -> Long.parseLong(x.toString())).orElseGet(System::currentTimeMillis));//7.输出数据collector.collect(dataChangeInfo);}private Struct getStruct(Struct value, String fieldElement) {return value.getStruct(fieldElement);}/*** 从元数据获取出变更之前或之后的数据*/private JSONObject getJsonObject(Struct value, String fieldElement) {Struct element = value.getStruct(fieldElement);JSONObject jsonObject = new JSONObject();if (element != null) {Schema afterSchema = element.schema();List<Field> fieldList = afterSchema.fields();for (Field field : fieldList) {Object afterValue = element.get(field);jsonObject.put(field.name(), afterValue);}}return jsonObject;}@Overridepublic TypeInformation<DataChangeInfo> getProducedType() {return TypeInformation.of(DataChangeInfo.class);}
}
(3)封装的变更对象
@Data
public class DataChangeInfo implements Serializable {/*** 变更前数据*/private String beforeData;/*** 变更后数据*/private String afterData;/*** 变更类型 1新增 2修改 3删除*/private String eventType;/*** binlog文件名*/private String fileName;/*** binlog当前读取点位*/private Integer filePos;/*** 数据库名*/private String database;/*** 表名*/private String tableName;/*** 变更时间*/private Long changeTime;}

这里的 beforeData、afterData直接存储Struct 不好吗,还得费劲去来回转?

我曾尝试过使用Struct 存放在对象中,但是无法进行序列化。具体原因可以网上搜索,或者自己尝试一下。

(4)定义 Flink 的 Sink
@Component
@Slf4j
public class DataChangeSink extends RichSinkFunction<DataChangeInfo> {transient RabbitTemplate rabbitTemplate;transient ConfirmService confirmService;transient TableDataConvertService tableDataConvertService;@Overridepublic void invoke(DataChangeInfo value, Context context) {log.info("收到变更原始数据:{}", value);//转换后发送到对应的MQif (MIGRATION_TABLE_CACHE.containsKey(value.getTableName())) {String routingKey = MIGRATION_TABLE_CACHE.get(value.getTableName());//可根据需要自行进行confirmService的设计rabbitTemplate.setReturnsCallback(confirmService);rabbitTemplate.setConfirmCallback(confirmService);rabbitTemplate.convertAndSend(EXCHANGE_NAME, routingKey, tableDataConvertService.convertSqlByDataChangeInfo(value));}}/*** 在启动SpringBoot项目是加载了Spring容器,其他地方可以使用@Autowired获取Spring容器中的类;但是Flink启动的项目中,* 默认启动了多线程执行相关代码,导致在其他线程无法获取Spring容器,只有在Spring所在的线程才能使用@Autowired,* 故在Flink自定义的Sink的open()方法中初始化Spring容器*/@Overridepublic void open(Configuration parameters) throws Exception {super.open(parameters);this.rabbitTemplate = ApplicationContextUtil.getBean(RabbitTemplate.class);this.confirmService = ApplicationContextUtil.getBean(ConfirmService.class);this.tableDataConvertService = ApplicationContextUtil.getBean(TableDataConvertService.class);}
}
(5)数据转换类接口和实现类
public interface TableDataConvertService {String convertSqlByDataChangeInfo(DataChangeInfo dataChangeInfo);
}@Service
public class TableDataConvertServiceImpl implements TableDataConvertService {@AutowiredMap<String, SqlGeneratorService> sqlGeneratorServiceMap;@Overridepublic String convertSqlByDataChangeInfo(DataChangeInfo dataChangeInfo) {SqlGeneratorService sqlGeneratorService = sqlGeneratorServiceMap.get(dataChangeInfo.getEventType());return sqlGeneratorService.generatorSql(dataChangeInfo);}
}

因为在dataChangeInfo 中我们有封装对象的类型(CREATEDELETEUPDATE),所以我希望通过不同类来进行不同的工作。于是就有了下面的类结构:

根据 dataChangeInfo 的类型去生成对应的SqlGeneratorServiceImpl

这是策略模式还是模板方法?

策略模式(Strategy Pattern)允许在运行时选择算法的行为。在策略模式中,定义了一系列的算法(策略),并将每一个算法封装起来,使它们可以相互替换。策略模式允许算法独立于使用它的客户端进行变化。

InsertSqlGeneratorServiceImpl、UpdateSqlGeneratorServiceImpl 和 DeleteSqlGeneratorServiceImpl 各自实现了 SqlGeneratorService 接口,这确实表明了一种策略。每一个实现类表示一个特定的SQL生成策略,并且可以相互替换,只要它们遵守同一个接口。

模板方法模式(Template Method Pattern),则侧重于在抽象类中定义算法的框架,让子类实现算法的某些步骤而不改变算法的结构。AbstractSqlGenerator 作为抽象类的存在是为了被继承,但如果它不含有模板方法(即没有定义算法骨架的方法),那它就不符合模板方法模式。

在实际应用中,一个设计可能同时结合了多个设计模式,或者在某些情况下,一种设计模式的实现可能看起来与另一种模式类似。在这种情况下,若 AbstractSqlGenerator 提供了更多的共享代码或默认实现表现出框架角色,那么它可能更接近模板方法。而如果 AbstractSqlGenerator 仅仅作为一种接口实现方式,且策略之间可以相互替换,那么这确实更符合策略模式。

值得注意的是,在 TableDataConvertServiceImpl 中,我们注入了一个Map<String, SqlGeneratorService> sqlGeneratorServiceMap,通过它来进行具体实现类的获取。那么他是个什么东西呢?作用是什么呢?为什么可以通过它来获取呢?

@Resource、@Autowired 标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会将容器中所有类型符合 Map 的 value 对应的类型的 Bean 增加进来,用 Bean 的 id 或 name 作为 Map 的 key。

那么可以看到下面第六步,在进行DeleteSqlGeneratorServiceImpl装配的时候进行指定了名字**@Service(“DELETE”)**,方便通过dataChangeInfo获取。

(6)转换类部分代码
public interface SqlGeneratorService {String generatorSql(DataChangeInfo dataChangeInfo);
}public abstract class AbstractSqlGenerator implements SqlGeneratorService {@Overridepublic String generatorSql(DataChangeInfo dataChangeInfo) {return null;}public String quoteIdentifier(String identifier) {// 对字段名进行转义处理,这里简化为对其加反引号// 实际应该处理数据库标识符的特殊字符return "`" + identifier + "`";}
}@Service("DELETE")
@Slf4j
public class DeleteSqlGeneratorServiceImpl extends AbstractSqlGenerator {@Overridepublic String generatorSql(DataChangeInfo dataChangeInfo) {String beforeData = dataChangeInfo.getBeforeData();Map<String, Object> beforeDataMap = JSONObjectUtils.JsonToMap(beforeData);StringBuilder wherePart = new StringBuilder();for (String key : beforeDataMap.keySet()) {Object beforeValue = beforeDataMap.get(key);if ("create_time".equals(key)){SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");beforeValue = dateFormat.format(beforeValue);}if (wherePart.length() > 0) {// 不是第一个更改的字段,增加逗号分隔wherePart.append(", ");}wherePart.append(quoteIdentifier(key)).append(" = ").append(formatValue(beforeValue));}log.info("wherePart : {}", wherePart);return "DELETE FROM " + dataChangeInfo.getTableName() + " WHERE " + wherePart;}
}

核心代码如上所示,具体实现可自行设计。

五、源码获取

Github:incremental-sync-flink-cdc

相关文章:

SpringBoot集成Flink-CDC,实现对数据库数据的监听

一、什么是 CDC &#xff1f; CDC 是Change Data Capture&#xff08;变更数据获取&#xff09;的简称。 核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数据表的插入、 更新以及删除等&#xff09;&#xff0c;将这些变更按发生的顺序完整记录下来&…...

微信小程序云开发服务端存储API 从云存储空间删除文件

deleteFile 从云存储空间删除文件 const cloud require(wx-server-sdk)exports.main async (event, context) > {const fileIDs [xxx, xxx]const result await cloud.deleteFile({fileList: fileIDs,})return result.fileList }写的资式如有不对&#xff0c;请各位大神多…...

[操作系统] 深入进程地址空间

程序地址空间回顾 在C语言学习的时&#xff0c;对程序的函数、变量、代码等数据的存储有一个大致的轮廓。在语言层面上存储的地方叫做程序地址空间&#xff0c;不同类型的数据有着不同的存储地址。 下图为程序地址空间的存储分布和和特性&#xff1a; 使用以下代码来验证一下…...

gitlab处理空文件夹的提交或空文件夹提交失败

问题描述 厂家发给了我一个压缩包文件&#xff0c;压缩包解压之后本地编译没问题&#xff1b;推送到gitlab之后&#xff0c;再编译就报错了&#xff1b; 问题原因 经过分析之后发现&#xff0c;压缩包解压之后存在很多空文件夹&#xff1b;但是gitlab推送的时候&#xff0c;…...

C++ —— 智能指针 unique_ptr (上)

C —— 智能指针 unique_ptr &#xff08;上&#xff09; 普通指针的不足普通指针的释放智能指针智能指针 unique_ptr智能指针初始化错误用法get()方法返回裸指针智能指针不支持指针的运算&#xff08;、-、、- -&#xff09; 普通指针的不足 new和new [] 的内存需要用delete和…...

ruoyi-vue-pro集成magic-api(图文代码)

目录 前言1. 配置依赖2. 集成登录3. 成功展示前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 原先写过简单的集成:了解 magic-api的基本用法 附实战代码 magic-api相关文档推荐阅读:接口鉴权 相关的Java代码推荐阅读: java框架 零基础从入门到精…...

【线上问题定位处理】及【性能优化】系列文章

目录 性能优化 性能优化 九大服务架构性能优化方式 如何进行GC调优 如何排查线上系统出现的Full GC MySQL - 性能优化 MySQL - 分库分表 大数据查询的处理方案 MySQL优化手段有哪些 服务CPU100%问题如何快速定位? 服务内存OOM问题如何快速定位? JVM调优6大步骤 线…...

如何解压rar格式文件?8种方法(Win/Mac/手机/网页端)

RAR 文件是一种常见的压缩文件格式&#xff0c;由尤金・罗谢尔&#xff08;Eugene Roshal&#xff09;开发&#xff0c;因其扩展名 “rar” 而得名。它通过特定算法将一个或多个文件、文件夹进行压缩&#xff0c;大幅减小存储空间&#xff0c;方便数据传输与备份。然而&#xf…...

GORM 支持的数据库解析

GORM 是一个流行的 Go 语言 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它简化了 Go 与数据库之间的交互。作为一款功能强大的库&#xff0c;GORM 支持多种主流关系型数据库&#xff0c;满足不同开发场景下的需求。本文将探讨 GORM 支持的主要数据库及其特点&#…...

分布式光纤应变监测是一种高精度、分布式的监测技术

一、土木工程领域 桥梁结构健康监测 主跨应变监测&#xff1a;在大跨度桥梁的主跨部分&#xff0c;如悬索桥的主缆、斜拉桥的斜拉索和主梁&#xff0c;分布式光纤应变传感器可以沿着这些关键结构部件进行铺设。通过实时监测应变情况&#xff0c;能够精确捕捉到车辆荷载、风荷…...

如何在oracle关闭情况下如何修改spfile的参数

如何在oracle关闭情况下如何修改spfile的参数 一、问题背景二、处理方案 一、问题背景 在ORACLE数据库启动状态下通过下列代码修改了最大连接数 alter system set processes2000 scopespfile sid*;关闭了数据库再重新启动提示如下报错&#xff1a; ORA-00838: Specified valu…...

[ Spring ] Spring Cloud Gateway 2025 Comprehensive Overview

文章目录 Spring Gateway ArchitectureProject Level DependencyService CenterService ProviderGateway ServiceLaunch All Service Spring Gateway Architecture Service Center : register and find service providerService Provider : programs that provide actual serv…...

软考信安27~Windows操作系统安全相关

1、Windows账户与组管理 1.1、用户账户查看 whoami #查看当前登录的用户名称 whoami /all #查看当前系统的用户名和组信息,以及SID whoami /user #查看当前用户的SID net user #查看系统中包含哪些用户 wmic useraccount get name,sid #查看…...

2025年数学建模美赛 A题分析(3)楼梯使用方向偏好模型

2025年数学建模美赛 A题分析&#xff08;1&#xff09;Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析&#xff08;2&#xff09;楼梯磨损分析模型 2025年数学建模美赛 A题分析&#xff08;3&#xff09;楼梯使用方向偏好模型 2025年数学建模美赛 A题分…...

Spring整合Mybatis、junit纯注解

如何创建一个Spring项目 错误问题 不知道什么原因&#xff0c;大概是依赖版本不兼容、java版本不对的问题&#xff0c;折磨了好久就是搞不成。 主要原因看pom.xml配置 pom.xml配置 java版本 由于是跟着22年黑马视频做的&#xff0c;java版本换成了jdk-11&#xff0c;用21以…...

HAM-TTS大模型:基于token的零样本文字转语音分层声学建模

HAM-TTS大模型:基于token的零样本文字转语音分层声学建模 ​​ 吉利自研语音大模型HAM-TTS的全称是:Hierarchical Acoustic Modeling for Token-Based Zero-Shot Text-to-Speech,直译是基于token的零样本文字转语音分层声学建模,是星睿AI大模型体系下的重要一员。顾名思义…...

SpringBoot开发(三)SpringBoot介绍、项目创建、运行

1. SpringBoot 1.1. SpringBoot介绍 Spring Boot给世界程序员带来了春天&#xff0c;越来越多的企业选择使用spring boot来开发他们的软件&#xff0c;因此学习spring boot是科技发展的必然趋势。本门课程将从web最基础的知识点开始讲起&#xff0c;逐步带你攻破spring boot的…...

SQL Server 建立每日自动log备份的维护计划

SQLServer数据库可以使用维护计划完成数据库的自动备份&#xff0c;下面以在SQL Server 2012为例说明具体配置方法。 1.启动SQL Server Management Studio&#xff0c;在【对象资源管理器】窗格中选择数据库实例&#xff0c;然后依次选择【管理】→【维护计划】选项&#xff0…...

git Bash通过SSH key 登录github的详细步骤

1 问题 通过在windows 终端中的通过git登录github 不再是通过密码登录了&#xff0c;需要本地生成一个密钥&#xff0c;配置到gihub中才能使用 2 步骤 &#xff08;1&#xff09;首先配置用户名和邮箱 git config --global user.name "用户名"git config --global…...

软件越跑越慢的原因分析

如果是qt软件&#xff0c;可以用Qt Creator Profiler 作性能监控如果是通过web请求&#xff0c;可以用JMeter监控。 软件运行过程中逐渐变慢的现象&#xff0c;通常是因为系统资源&#xff08;如 CPU、内存、磁盘 I/O 等&#xff09;逐渐被消耗或软件中存在性能瓶颈。这个问题…...

C++AVL树(二)详解

文章目录 AVL树旋转单旋右单旋左单旋 双旋左右双旋右左双旋 平衡因子的更新左右双旋右左双旋 判断是不是AVL树时间复杂度分析全部的代码 AVL树 旋转 单旋 单旋是纯粹的一边高 单旋平衡因子是同号 右单旋 a,b,c自身不能发生旋转 并且也不能不向上继续更新&#xff08;不能停…...

【GoLang】利用validator包实现服务端参数校验时自定义错误信息

在C/S架构下&#xff0c;服务端在校验请求参数时&#xff0c;若出现参数错误&#xff0c;要响应给客户端一个错误消息&#xff0c;通常我们会统一响应“参数错误”。 但是&#xff0c;如果只是一味的提示参数错误&#xff0c;我并不知道具体是哪个参数错了呀&#xff01;能不能…...

AIP-128 声明友好接口

编号128原文链接AIP-128: Declarative-friendly interfaces状态批准创建日期2020-10-06更新日期2020-10-06 许多服务需要与常见的DevOps工具交互&#xff0c;特别是创建和管理可网络寻址资源&#xff08;如虚拟机、负载均衡器、数据库实例等&#xff09;的工具。这些工具采用“…...

【Jave全栈】Java与JavaScript比较

文章目录 前言一、Java1、 历史与背景2、语言特点3、应用场景4、生态系统 二、JavaScript1、历史与背景2、语言特点3、应用场景4、 生态系统 三、相同点四、不同点1、语言类型2、用途3、语法和结构4、性能5、生态系统6、开发模式 前言 Java和JavaScript是两种不同的编程语言&a…...

钉钉群机器人设置——python版本

钉钉群机器人设置——python版本 应用场景钉钉界面操作程序开发效果展示 应用场景 由于工作需要&#xff0c;很多项目执行程序后出现报错信息无法第一时间收到&#xff0c;因此实时预警对于监控程序还是有必要。&#xff08;仅个人观点&#xff09; 参考文档及博客&#xff1a…...

报错:{‘csrf_token‘: [‘The CSRF token is missing.‘]}

flask实现一个简单的注册界面报错 register.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <form action"" method"post&…...

STM32新建不同工程的方式

新建工程的方式 1. 安装开发工具 MDK5 / keil52. CMSIS 标准3. 新建工程3.1 寄存器版工程3.2 标准库版工程3.3 HAL/LL库版工程3.4 HAL库、LL库、标准库和寄存器对比3.5 库开发和寄存器的关系 4. STM32CubeMX工具的作用 1. 安装开发工具 MDK5 / keil5 MDK5 由两个部分组成&#…...

Java数据库操作指南:快速上手JDBC【学术会议-2025年数字化教育与信息技术(DEIT 2025】

大会官网&#xff1a;www.ic-deit.org 前言 在现代企业应用中&#xff0c;数据库是数据存储和管理的重要组成部分。Java作为一种广泛使用的编程语言&#xff0c;提供了多种方式与数据库进行交互。本文将介绍 JDBC&#xff08;Java Database Connectivity&#xff09;&#x…...

基于Springboot + vue实现的在线装修管理系统

“前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff1a;人工智能学习网站” &#x1f496;学习知识需费心&#xff0c; &#x1f4d5;整理归纳更费神。 &#x1f389;源码免费人人喜…...

计算机网络之应用层

本文章目录结构出自于《王道计算机考研 计算机网络_哔哩哔哩_bilibili》 05 应用层 在网上看到其他人做了相关笔记&#xff0c;就不再多余写了&#xff0c;直接参考着学习吧。 王道考研 计算机网络笔记 第六章&#xff1a;应用层_王道考研 应用层 笔记-CSDN博客 DNS&#x…...

SpringMVC框架

第1章 SpringMVC入门 1.1 SpringMVC简介 Spring MVC 全称:Spring Web MVC是 Spring 框架的一部分&#xff0c;专注于实现 Web 应用程序的模型-视图-控制器&#xff08;Model-View-Controller, MVC&#xff09;设计模式。它为构建灵活且松耦合的 Web 应用提供了强大的功能&…...

将 OneLake 数据索引到 Elasticsearch - 第 1 部分

作者&#xff1a;来自 Elastic Gustavo Llermaly 学习配置 OneLake&#xff0c;使用 Python 消费数据并在 Elasticsearch 中索引文档&#xff0c;然后运行语义搜索。 OneLake 是一款工具&#xff0c;可让你连接到不同的 Microsoft 数据源&#xff0c;例如 Power BI、Data Activ…...

flutter跨端UI框架简介

flutter跨端UI框架简介 简介 Flutter是由Google开发的开源应用开发框架&#xff0c;主要用于构建高性能、跨平台的移动、Web和桌面应用程序。Flutter使用Dart语言&#xff0c;提供了一套丰富的Widgets&#xff0c;使开发者能够快速创建美观的用户界面。其最大特点是热重载功能…...

Centos 修改历史读录( HISTSIZE)

history命令 -c #清空命令历史 -r #读历史文件附加到历史列表 -w #保存历史列表到指定的历史文件 命令历史相关环境变量 HISTSIZE #命令历史记录的条数 HISTFILE #指定历史文件&#xff0c;默认为~/.bash_history HISTFILESIZE #命令历史文件记录历史的条数 以上变量可以 exp…...

利用ML.NET精准提取人名

在当今信息爆炸的时代&#xff0c;文本处理任务层出不穷&#xff0c;其中人名提取作为基础且重要的工作&#xff0c;广泛应用于信息检索、社交网络分析、客户关系管理等领域。随着人工智能不断进步&#xff0c;ML.NET作为微软推出的开源机器学习框架&#xff0c;为开发者提供了…...

关于deepin上运行Qt开发的程序

国产化替代是将来各单位的主流趋势&#xff0c;探索自行开发应用程序在国产操作系统上正常运行是将来的主要工作之一。本文浅尝gui程序在统信社区版——deepin上遇到的小问题。 使用Qt在deepin上做了一个类似gif的帧动画弹窗&#xff0c;在编译运行时&#xff0c;程序可以正常…...

3.3 Go函数可变参数

可变参数&#xff08;variadic parameters&#xff09;是一种允许函数接受任意数量参数的机制。它在函数定义中使用 ...type 来声明参数类型&#xff0c;所有传递的参数会被收集为一个切片&#xff0c;函数内部可以像操作普通切片一样处理这些参数。 package mainimport "…...

Queries Acceleration -Tuning- Tuning Execution 学习笔记

1 Adjustment of RuntimeFilter Wait Time 1.1 Case: Too Short RuntimeFilter Wait Time 1.1.1 没有看懂,好像是等待时间过小也会导致性能下降 1.1.2 set runtime_filter_wait_time_ms = 3000; 2 Data Skew Handling 2.1 Case 1: Bucket Data Skew Leading to Suboptimal …...

VS C++ 配置OPENCV环境

VS C 配置OPENCV环境 1.下载opencv2.安装环境3.opencv环境4.VS配置opencv环境5.EXE执行文件路径的环境lib和dll需要根据是debug还是release环境来区分使用哪个 6.Windows环境 1.下载opencv 链接: link 2.安装环境 双击运行即可 3.opencv环境 include文件路径:opencv\build\…...

Midscene.js:重新定义UI自动化的新时代工具

前言 Midscene.js 是一个创新的、面向开发者的 UI 自动化解决方案&#xff0c;并通过人工智能技术简化自动化脚本的编写与维护。 它提供了三种核心方法——交互&#xff08;.ai, .aiAction&#xff09;、提取&#xff08;.aiQuery&#xff09;和断言&#xff08;.aiAssert&am…...

记录让cursor帮我给ruoyi-vue后台管理项目整合mybatis-plus

自己整合过程中会出现 work.web.exception.GlobalExceptionHandler :100 | 请求地址/admin/device/install/detail/1,发生未知异常. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.fire.mapper.DeviceInstallMapper.selectById at o…...

uniapp中h5的微应用解决办法

考虑过用wujie&#xff0c;参考官网Vue组件封装 | 无界的教程&#xff0c;虽然没报错&#xff0c;但是子应用的vue节点根本没挂载上&#xff0c;不知道什么原因&#xff0c;如下图所示 后面采用iframe方式将子应用导入进来&#xff1a; 父应用&#xff1a; <template>&…...

再尝Semantic Kernel,planning特性很香

背景 书接上回《浅尝semantic kernel》&#xff1b; 上次只试了试SK框架的插件特性&#xff0c;这次试了下编排的特性&#xff0c;也就是把多个本地任务按顺序按逻辑执行&#xff0c;没想到效果也是出奇的好&#xff01; 关键步骤 架构层面的代码本篇不在赘述&#xff0c;这…...

华为OD机试真题---战场索敌

华为OD机试真题“战场索敌”是一道考察算法和数据结构应用能力的题目。以下是对该题目的详细解析&#xff1a; 一、题目描述 有一个大小是NM的战场地图&#xff0c;被墙壁’#‘分隔成大小不同的区域。上下左右四个方向相邻的空地’.‘属于同一个区域&#xff0c;只有空地上可…...

Case逢无意难休——深度解析JAVA中case穿透问题

Case逢无意难休——深度解析JAVA中case穿透问题~ 不作溢美之词&#xff0c;不作浮夸文章&#xff0c;此文与功名进取毫不相关也&#xff01;与大家共勉&#xff01;&#xff01; 更多文章&#xff1a;个人主页 系列文章&#xff1a;JAVA专栏 欢迎各位大佬来访哦~互三必回&#…...

HTML入门知识

目录 一、什么是HTML 二、HTML文档的语法规则 三、HTML基本标签 四、HTML注释与特殊字符 1、注释 2、特殊字符 五、HTML属性 六、常见误区与建议 一、什么是HTML HTML&#xff0c;全称Hyper Text Markup Language&#xff0c;即超文本标记语言&#xff0c;是一种用于创…...

idea maven本地有jar包,但还要从远程下载

idea 中&#xff0c;java 工程执行 maven reimport&#xff0c;报jar报无法下载。 我奇了个怪&#xff0c;我明明在本地仓库有啊&#xff0c;你非得从远程下载&#xff1f; 我从供应商那里拿来的&#xff0c;远程当然没有了。 这太奇葩了吧&#xff0c;折腾好久不行。 后来…...

利用大语言模型(LLM)增强软件测试自动化的最佳实践

在当今迅速变化的科技时代&#xff0c;软件测试行业面临着越来越高的效率和质量要求。作为测试专家&#xff0c;我们都知道&#xff0c;传统的测试方法往往无法满足快速迭代和高效交付的需求。在这种背景下&#xff0c;自动化测试逐渐成为解决方案的一部分。而大语言模型&#…...

联想电脑怎么设置u盘启动_联想电脑设置u盘启动方法(支持新旧机型)

有很多网友问联想电脑怎么设置u盘启动&#xff0c;联想电脑设置u盘启动的方法有两种&#xff0c;一是通过bios进行设置。二是通过快捷方式启动进入u盘启动。但需要注意有两种引导模式是&#xff0c;一种是uefi引导&#xff0c;一种是传统的leacy引导&#xff0c;所以需要注意制…...

Browser-Use WebUI项目启动指南

摘要 此前发布《Browser - Use WebUI 使用体验》博文后&#xff0c;鉴于部分朋友运行时出现问题&#xff0c;重新运行并整理相关内容。本文详细记录 Web UI 项目启动全过程&#xff0c;涵盖 Python 3.11、Chrome 浏览器及 API Keys 等环境要求&#xff0c;Python 环境检查、依赖…...