Kafka API与SpringBoot调用

文章目录

      • 首先需要命令行创建一个名为cities的主题,并且创建该主题的订阅者。
  • 1、使用Kafka原生API
    • 1.1、创建spring工程
    • 1.2、创建发布者
    • 1.3、对生产者的优化
    • 1.4、批量发送消息
    • 1.5、创建消费者组
    • 1.6 消费者同步手动提交
    • 1.7、消费者异步手动提交
    • 1.8、消费者同异步手动提交
  • 2、SpringBoot Kafka
    • 2.1、定义发布者
      • 1、修改配置文件
      • 2、定义发布者处理器
    • 2.2、定义消费者
      • 1、修改配置文件
      • 2、定义消费者

首先需要命令行创建一个名为cities的主题,并且创建该主题的订阅者。

在这里插入图片描述

1、使用Kafka原生API

1.1、创建spring工程

在这里插入图片描述
导入依赖:
在这里插入图片描述

1.2、创建发布者

先创建一个发布者类OneProsucer:
(注意需要配置一下ip主机名映射:添加映射)

public class OneProducer {// 第一个泛型:当前生产者所生产消息的key// 第二个泛型:当前生产者所生产的消息本身private KafkaProducer<Integer, String> producer;public OneProducer() {Properties properties = new Properties();// 指定kafka集群properties.put("bootstrap.servers", "kafka01:9092,kafka02:9092,kafka03:9092");// 指定key与value的序列化器properties.put("key.serializer", "org.apache.kafka.common.serialization.IntegerSerializer");properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");this.producer = new KafkaProducer<Integer, String>(properties);}public void sendMsg() {// 创建消息记录(包含主题、消息本身)  (String topic, V value)// ProducerRecord<Integer, String> record = new ProducerRecord<>("cities", "tianjin");// 创建消息记录(包含主题、key、消息本身)  (String topic, K key, V value)// ProducerRecord<Integer, String> record = new ProducerRecord<>("cities", 1, "tianjin");// 创建消息记录(包含主题、partition、key、消息本身)  (String topic, Integer partition, K key, V value)ProducerRecord<Integer, String> record = new ProducerRecord<>("cities", 1, "tianjin");producer.send(record);}
}

注意代码中的字符串kafka都是有对应的常量的,这里便于理解用原生字符串来来写。

一般情况下,我们可能无法记住这些参数名。为此,Kafka的ProducerConfig类提供了一系列的参数常量。例如:
bootstrap.servers 可替换为 ProducerConfig.BOOTSTRAP_SERVERS_CONFIG
key.serializer 可替换为 ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG
value.serializer 可替换为 ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG

api生产的消息与命令行消息的区别:

参考:Kafka生产者

再创建一个测试类:

public class OneProducerTest {public static void main(String[] args) throws IOException {OneProducer producer = new OneProducer();producer.sendMsg();System.in.read();}
}

xshell启动主题为cities的一个消费者:

bin/kafka-console-consumer.sh --bootstrap-server 192.168.255.212:9092 --topic cities --from-beginning

启动生产者测试类生产消息:
在这里插入图片描述
查看linux端消费者,可以看到消息:
在这里插入图片描述
3台主机消费者都可以收到。

1.3、对生产者的优化

对于上一小节,有两个不舒服的点:

  1. 生产者端启动后控制台没有任何输出,只能通过看消费端消息才确认发送接收成功;
  2. 生产消息,指定分区的测试

这里可以使用回调方式,发送成功后,触发回调方法,生产端返回提示。

创建发布者类(修改senMsg方法):

public class TwoProducer {// 第一个泛型:当前生产者所生产消息的key// 第二个泛型:当前生产者所生产的消息本身private KafkaProducer<Integer, String> producer;public TwoProducer() {Properties properties = new Properties();// 指定kafka集群properties.put("bootstrap.servers", "kafka01:9092,kafka02:9092,kafka03:9092");// 指定key与value的序列化器properties.put("key.serializer", "org.apache.kafka.common.serialization.IntegerSerializer");properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");this.producer = new KafkaProducer<Integer, String>(properties);}public void sendMsg() {// 创建消息记录(包含主题、消息本身)  (String topic, V value)// ProducerRecord<Integer, String> record = new ProducerRecord<>("cities", "tianjin");// 创建消息记录(包含主题、key、消息本身)  (String topic, K key, V value)// ProducerRecord<Integer, String> record = new ProducerRecord<>("cities", 1, "tianjin");// 创建消息记录(包含主题、partition、key、消息本身)  (String topic, Integer partition, K key, V value)ProducerRecord<Integer, String> record = new ProducerRecord<>("cities", 2, 1, "tianjin");producer.send(record, (metadata, ex) -> {System.out.println("topic = " + metadata.topic());System.out.println("partition = " + metadata.partition());System.out.println("offset = " + metadata.offset());});}
}

创建测试类:

public class TwoProducerTest {public static void main(String[] args) throws IOException {TwoProducer producer = new TwoProducer();producer.sendMsg();System.in.read();}
}

启动运行:
在这里插入图片描述
消费端:
在这里插入图片描述
再次生产消息,偏移量变为1:
在这里插入图片描述
但是到目前为止,生产者一次只能发送一条消息,接下来看生产者批量发送消息。

1.4、批量发送消息

创建发布者类:

public class SomeProducerBatch {// 第一个泛型:当前生产者所生产消息的key// 第二个泛型:当前生产者所生产的消息本身private KafkaProducer<Integer, String> producer;public SomeProducerBatch() {Properties properties = new Properties();// 指定kafka集群properties.put("bootstrap.servers", "kafka01:9092,kafka02:9092,kafka03:9092");// 指定key与value的序列化器properties.put("key.serializer", "org.apache.kafka.common.serialization.IntegerSerializer");properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");// 指定生产者每10条向broker发送一次properties.put("batch.size", 10);// 指定生产者每50ms向broker发送一次properties.put("linger.ms", 50);this.producer = new KafkaProducer<Integer, String>(properties);}public void sendMsg() {for(int i=0; i<50; i++) {ProducerRecord<Integer, String> record = new ProducerRecord<>("cities", "city-" + i);int k = i;producer.send(record, (metadata, ex) -> {System.out.println("i = " + k);System.out.println("topic = " + metadata.topic());System.out.println("partition = " + metadata.partition());System.out.println("offset = " + metadata.offset());});}}
}

注意:

  1. batch.size
  2. lingger.ms
    如果50ms没产生50条,时间到了也发消息。

创建一个测试类:

public class ProducerBatchTest {public static void main(String[] args) throws IOException {SomeProducerBatch producer = new SomeProducerBatch();producer.sendMsg();System.in.read();}
}

本身send方法执行了50次,但是并不是每一次都发送,仅仅是生产了50条消息;发送是按照上面的设置每10条向broker发送一次或者每50ms发送一次。
(分区是轮询的):

i = 0
topic = cities
partition = 0
offset = 2
i = 3
topic = cities
partition = 0
offset = 3
i = 1
topic = cities
partition = 2
offset = 2
i = 4
topic = cities
partition = 2
offset = 3
i = 6
topic = cities
partition = 0
offset = 4
i = 9
topic = cities
partition = 0
offset = 5
i = 7
topic = cities
partition = 2
offset = 4
i = 10
topic = cities
partition = 2
offset = 5
i = 12
topic = cities
partition = 0
offset = 6
i = 15
topic = cities
partition = 0
offset = 7
i = 13
topic = cities
partition = 2
offset = 6
i = 16
topic = cities
partition = 2
offset = 7
i = 18
topic = cities
partition = 0
offset = 8
i = 21
topic = cities
partition = 0
offset = 9
i = 24
topic = cities
partition = 0
offset = 10
i = 27
topic = cities
partition = 0
offset = 11
i = 19
topic = cities
partition = 2
offset = 8
i = 22
topic = cities
partition = 2
offset = 9
i = 30
topic = cities
partition = 0
offset = 12
i = 33
topic = cities
partition = 0
offset = 13
i = 36
topic = cities
partition = 0
offset = 14
i = 39
topic = cities
partition = 0
offset = 15
i = 42
topic = cities
partition = 0
offset = 16
i = 45
topic = cities
partition = 0
offset = 17
i = 25
topic = cities
partition = 2
offset = 10
i = 28
topic = cities
partition = 2
offset = 11
i = 31
topic = cities
partition = 2
offset = 12
i = 34
topic = cities
partition = 2
offset = 13
i = 37
topic = cities
partition = 2
offset = 14
i = 40
topic = cities
partition = 2
offset = 15
i = 43
topic = cities
partition = 2
offset = 16
i = 46
topic = cities
partition = 2
offset = 17
i = 48
topic = cities
partition = 0
offset = 18
i = 49
topic = cities
partition = 2
offset = 18
i = 2
topic = cities
partition = 1
offset = 0
i = 5
topic = cities
partition = 1
offset = 1
i = 8
topic = cities
partition = 1
offset = 2
i = 11
topic = cities
partition = 1
offset = 3
i = 14
topic = cities
partition = 1
offset = 4
i = 17
topic = cities
partition = 1
offset = 5
i = 20
topic = cities
partition = 1
offset = 6
i = 23
topic = cities
partition = 1
offset = 7
i = 26
topic = cities
partition = 1
offset = 8
i = 29
topic = cities
partition = 1
offset = 9
i = 32
topic = cities
partition = 1
offset = 10
i = 35
topic = cities
partition = 1
offset = 11
i = 38
topic = cities
partition = 1
offset = 12
i = 41
topic = cities
partition = 1
offset = 13
i = 44
topic = cities
partition = 1
offset = 14
i = 47
topic = cities
partition = 1
offset = 15

linux端:

city-1
city-4
city-7
city-10
city-0
city-3
city-6
city-9
city-13
city-16
city-19
city-22
city-25
city-28
city-31
city-34
city-37
city-40
city-12
city-15
city-18
city-21
city-24
city-27
city-30
city-33
city-36
city-39
city-42
city-45
city-43
city-46
city-49
city-48
city-2
city-5
city-8
city-11
city-14
city-17
city-20
city-23
city-26
city-29
city-32
city-35
city-38
city-41
city-44
city-47

1.5、创建消费者组

消费者类:

public class SomeConsumer extends ShutdownableThread {private KafkaConsumer<Integer, String> consumer;public SomeConsumer() {// 两个参数:// 1)指定当前消费者名称// 2)指定消费过程是否会被中断super("KafkaConsumerTest", false);Properties properties = new Properties();String brokers = "kafka01:9092,kafka02:9092,kafka03:9092";// 指定kafka集群properties.put("bootstrap.servers", brokers);// 指定消费者组IDproperties.put("group.id", "cityGroup1");// 开启自动提交,默认为trueproperties.put("enable.auto.commit", "true");// 指定自动提交的超时时限,默认5sproperties.put("auto.commit.interval.ms", "1000");// 指定消费者被broker认定为挂掉的时限。若broker在此时间内未收到当前消费者发送的心跳,则broker// 认为消费者已经挂掉。默认为10sproperties.put("session.timeout.ms", "30000");// 指定两次心跳的时间间隔,默认为3s,一般不要超过session.timeout.ms的 1/3properties.put("heartbeat.interval.ms", "10000");// 当kafka中没有指定offset初值时,或指定的offset不存在时,从这里读取offset的值。其取值的意义为:// earliest:指定offset为第一条offset// latest: 指定offset为最后一条offsetproperties.put("auto.offset.reset", "earliest");// 指定key与value的反序列化器properties.put("key.deserializer","org.apache.kafka.common.serialization.IntegerDeserializer");properties.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");this.consumer = new KafkaConsumer<Integer, String>(properties);}@Overridepublic void doWork() {// 订阅消费主题consumer.subscribe(Collections.singletonList("cities"));// 从broker摘取消费。参数表示,若buffer中没有消费,消费者等待消费的时间。// 0,表示没有消息什么也不返回// >0,表示当时间到后仍没有消息,则返回空ConsumerRecords<Integer, String> records = consumer.poll(1000);for(ConsumerRecord record : records) {System.out.println("topic = " + record.topic());System.out.println("partition = " + record.partition());System.out.println("key = " + record.key());System.out.println("value = " + record.value());}}
}

测试类:

public class ConsumerTest {public static void main(String[] args) {SomeConsumer consumer = new SomeConsumer();consumer.start();}
}

启动运行,查看消费者控制台:

topic = cities
partition = 0
key = 1
value = tianjin
topic = cities
partition = 0
key = 1
value = tianjin
topic = cities
partition = 0
key = null
value = city-0
topic = cities
partition = 0
key = null
value = city-3
topic = cities
partition = 0
key = null
value = city-6
topic = cities
partition = 0
...

1.6 消费者同步手动提交

(1) 自动提交的问题
前面的消费者都是以自动提交 offset 的方式对 broker 中的消息进行消费的,但自动提交
可能会出现消息重复消费的情况。所以在生产环境下,很多时候需要对 offset 进行手动提交,
以解决重复消费的问题。

(2) 手动提交分类
手动提交又可以划分为同步提交、异步提交,同异步联合提交。这些提交方式仅仅是
doWork()方法不相同,其构造器是相同的。所以下面首先在前面消费者类的基础上进行构造
器的修改,然后再分别实现三种不同的提交方式。

创建创建消费者类 SyncManualConsumer

  • A、原理
    同步提交方式是,消费者向 broker 提交 offset 后等待 broker 成功响应。若没有收到响
    应,则会重新提交,直到获取到响应。而在这个等待过程中,消费者是阻塞的。其严重影响
    了消费者的吞吐量。

  • B、 修改构造器
    直接复制前面的 SomeConsumer,在其基础上进行修改。

public class SyncManualConsumer extends ShutdownableThread {private KafkaConsumer<Integer, String> consumer;public SyncManualConsumer() {// 两个参数:// 1)指定当前消费者名称// 2)指定消费过程是否会被中断super("KafkaConsumerTest", false);Properties properties = new Properties();String brokers = "kafkaOS1:9092,kafkaOS2:9092,kafkaOS3:9092";// 指定kafka集群properties.put("bootstrap.servers", brokers);// 指定消费者组IDproperties.put("group.id", "cityGroup1");// 开启手动提交properties.put("enable.auto.commit", "false");// 指定自动提交的超时时限,默认5s// properties.put("auto.commit.interval.ms", "1000");// 指定一次提交10个offsetproperties.put("max.poll.records", 10);// 指定消费者被broker认定为挂掉的时限。若broker在此时间内未收到当前消费者发送的心跳,则broker// 认为消费者已经挂掉。默认为10sproperties.put("session.timeout.ms", "30000");// 指定两次心跳的时间间隔,默认为3s,一般不要超过session.timeout.ms的 1/3properties.put("heartbeat.interval.ms", "10000");// 当kafka中没有指定offset初值时,或指定的offset不存在时,从这里读取offset的值。其取值的意义为:// earliest:指定offset为第一条offset// latest: 指定offset为最后一条offsetproperties.put("auto.offset.reset", "earliest");// 指定key与value的反序列化器properties.put("key.deserializer","org.apache.kafka.common.serialization.IntegerDeserializer");properties.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");this.consumer = new KafkaConsumer<Integer, String>(properties);}@Overridepublic void doWork() {// 订阅消费主题consumer.subscribe(Collections.singletonList("cities"));// 从broker摘取消费。参数表示,若buffer中没有消费,消费者等待消费的时间。// 0,表示没有消息什么也不返回// >0,表示当时间到后仍没有消息,则返回空ConsumerRecords<Integer, String> records = consumer.poll(1000);for(ConsumerRecord record : records) {System.out.println("topic = " + record.topic());System.out.println("partition = " + record.partition());System.out.println("key = " + record.key());System.out.println("value = " + record.value());// 手动同步提交consumer.commitSync();}}
}

创建测试类:

public class SyncManualTest {public static void main(String[] args) {SyncManualConsumer consumer = new SyncManualConsumer();consumer.start();}
}

1.7、消费者异步手动提交

(1) 原理
手动同步提交方式需要等待 broker 的成功响应,效率太低,影响消费者的吞吐量。异步提交方式是,消费者向 broker 提交 offset 后不用等待成功响应,所以其增加了消费者的吞吐量。

(2) 创建消费者类 AsyncManualConsumer

复制前面的 SyncManualConsumer 类,在其基础上进行修改。

public class AsynManualConsumer extends ShutdownableThread {private KafkaConsumer<Integer, String> consumer;public AsynManualConsumer() {...}@Overridepublic void doWork() {// 订阅消费主题consumer.subscribe(Collections.singletonList("cities"));// 从broker摘取消费。参数表示,若buffer中没有消费,消费者等待消费的时间。// 0,表示没有消息什么也不返回// >0,表示当时间到后仍没有消息,则返回空ConsumerRecords<Integer, String> records = consumer.poll(1000);for(ConsumerRecord record : records) {System.out.println("topic = " + record.topic());System.out.println("partition = " + record.partition());System.out.println("key = " + record.key());System.out.println("value = " + record.value());// 手动异步提交// consumer.commitAsync();consumer.commitAsync((offsets, ex) -> {if(ex != null) {System.out.print("提交失败,offsets = " + offsets);System.out.println(", exception = " + ex);}});}}
}

启动类:

public class AsyncManualTest {public static void main(String[] args) {AsynManualConsumer consumer = new AsynManualConsumer();consumer.start();}
}

1.8、消费者同异步手动提交

(1) 原理
同异步提交,即同步提交与异步提交组合使用。一般情况下,若偶尔出现提交失败,其
也不会影响消费者的消费。因为后续提交最终会将这次提交失败的 offset 给提交了。
但异步提交会产生重复消费,为了防止重复消费,可以将同步提交与异常提交联合使用。
(2) 创建消费者类 SyncAsyncManualConsumer
复制前面的 AsyncManualConsumer 类,在其基础上进行修改。

@Overridepublic void doWork() {// 订阅消费主题consumer.subscribe(Collections.singletonList("cities"));// 从broker摘取消费。参数表示,若buffer中没有消费,消费者等待消费的时间。// 0,表示没有消息什么也不返回// >0,表示当时间到后仍没有消息,则返回空ConsumerRecords<Integer, String> records = consumer.poll(1000);for(ConsumerRecord record : records) {System.out.println("topic = " + record.topic());System.out.println("partition = " + record.partition());System.out.println("key = " + record.key());System.out.println("value = " + record.value());consumer.commitAsync((offsets, ex) -> {if(ex != null) {System.out.print("提交失败,offsets = " + offsets);System.out.println(", exception = " + ex);// 同步提交consumer.commitSync();}});}}

2、SpringBoot Kafka

新建一个简单案例,将发布者和订阅者定义到一个工程中。

创建一个SpringBoot工程,pom.xml添加如下依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

2.1、定义发布者

Spring 是通过 KafkaTemplate 来完成对 Kafka 的操作的。

1、修改配置文件

# 自定义属性
kafka:topic: cities# 配置Kafka
spring:kafka:bootstrap-servers: kafkaOS1:9092,kafkaOS2:9092,kafkaOS3:9092# producer:   # 配置生产者# key-serializer: org.apache.kafka.common.serialization.StringSerializer# value-serializer: org.apache.kafka.common.serialization.StringSerializerconsumer:   # 配置消费者group-id: group0  # 消费者组# key-deserializer: org.apache.kafka.common.serialization.StringDeserializer# value-deserializer: org.apache.kafka.common.serialization.StringDeserializer

2、定义发布者处理器

@RestController
public class SomeProducer {@Autowiredprivate KafkaTemplate<String, String> template;// 从配置文件读取自定义属性@Value("${kafka.topic}")private String topic;// 由于是提交数据,所以使用Post方式@PostMapping("/msg/send")public String sendMsg(@RequestParam("message") String message) {template.send(topic, message);return "send success";}
}

2.2、定义消费者

Spring 是通过监听方式实现消费者的。

1、修改配置文件

如上一小节,在配置文件中添加消费者配置内容。注意,Spring 中要求必须为消费者指定组。

2、定义消费者

Spring Kafka 是通过 KafkaListener 监听方式来完成消息订阅与接收的。当监听到有指定
主题的消息时,就会触发@KafkaListener 注解所标注的方法的执行

@Component
public class SomeConsumer {@KafkaListener(topics = "${kafka.topic}")public void onMsg(String message) {System.out.println("Kafka消费者接受到消息 " + message);}}

run运行,postman访问接口输入消息:
在这里插入图片描述
消费者收到消息:
在这里插入图片描述
因为SpringBoot自动配置的原理,Kafka自动配置里:
在这里插入图片描述
在这里插入图片描述
默认就有了序列化,所以配置文件可以不用配置生产者的序列化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/89297.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Vue-Router】路由模式

1. WebHashHistory index.ts import { createRouter, createWebHistory, RouteRecordRaw, createWebHashHistory } from "vue-router";// 路由模式 //vue2 mode history -> vue3 createWebHistory //vue2 mode hash -> vue3 createWebHashHistory //vue2 m…

动动小手搭建私人大模型人工智能私人助理

引言&#xff1a; 去年12月OpenAI公司的ChatGPT3.5彻底引爆人工智能圈&#xff0c;今年国内大公司争相进入大模型的赛道&#xff0c;打造自己的大模型。前些日子的世界人工智能大会上&#xff0c;可谓是百模大战&#xff0c;热闹纷呈。 ChatGPT的出现&#xff0c;的确给人们带…

解读spring中@Value 如何将配置转自定义的bean

实现方式 着急寻求解决方式的猿友先看这块 定义配置转化类 public class UserConverter implements Converter<String, List<User>> {Overridepublic List<User> convert(String config) {if (StringUtils.isEmpty(config)) {return Collections.emptyLis…

iOS手机无法安装Charles 的ssl证书

问题描述 iOS客户端安装证书时一直卡在下载这一步&#xff0c;无法抓包 1、打开Charles&#xff0c;选择help→SSL Proxying→Install Charles Root Certificate on a Mobile Device or Remote Browser 2、按照步骤1中的提示进行操作&#xff0c;手机连接电脑代理&#xff0c;…

Gitlab CI/CD笔记-第二天-主机套接字进行构建并push镜像。

一、安装gitlab-runner 1.可以是linux也可以是docker的 2.本文说的是docker安装部署的。 二、直接上.gitlab-ci.yml stages: # List of stages for jobs, and their order of execution - build-image build-image-job: stage: build-image image: harbor.com:543/docke…

【100天精通python】Day34:使用python操作数据库_ORM(SQLAlchemy)使用

目录 专栏导读 1 ORM 概述 2 SQLAlchemy 概述 3 ORM&#xff1a;SQLAlchemy使用 3.1 安装SQLAlchemy&#xff1a; 3.2 定义数据库模型类&#xff1a; 3.3 创建数据表&#xff1a; 3.4 插入数据&#xff1a; 3.5 查询数据&#xff1a; 3.6 更新数据&#xff1a; 3.7 删…

微信小程序(由浅到深)

文章目录 一. 项目基本配置1. 项目组成2. 常见的配置文件解析3. app.json全局的五大配置4.单个页面中的page配置5. App函数6.tabBar配置 二. 基本语法&#xff0c;事件&#xff0c;单位1. 语法2. 事件3. 单位 三. 数据响应式修改四 . 内置组件1. button2. image3. input4. 组件…

VR全景乡村旅游浇灭乡愁,近距离体验自然之美

说起乡愁&#xff0c;可能每位漂泊的游子都有所感受&#xff0c;在外漂泊数十载&#xff0c;每到佳节倍思亲&#xff0c;家乡的一草一木都浮现在脑海中&#xff0c;满载着儿时的回忆。为了留住那抹儿时回忆&#xff0c;VR全景助力数字化乡村建设。 乡村振兴是国家的重大战略&am…

【java面向对象中static关键字】

提纲 static修饰成员变量static修饰成员变量的应用场景static修饰成员方法static修饰成员方法的应用场景static的注意事项static的应用知识&#xff1a;代码块static的应用知识&#xff1a;单例设计模式 static静态的意思&#xff0c;可以修饰成员变量&#xff0c;成员方法&a…

sql高频面试题-连续完成两个指定动作的用户统计

用户行为分析 业务背景 某购物APP最近上线了一个新功能&#xff0c;用户签到后可以跳转到大转盘抽奖&#xff0c;抽奖获得的奖金可以抵消购物的费用&#xff0c;以此来培养用户使用app的习惯。 数据表介绍 现有一张用户行为表action_log&#xff0c;主要字段如下&#xff0c…

什么是CSS中的渐变(gradient)?如何使用CSS创建线性渐变和径向渐变?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 渐变&#xff08;Gradient&#xff09;在CSS中的应用⭐ 线性渐变&#xff08;Linear Gradient&#xff09;语法&#xff1a;示例&#xff1a; ⭐ 径向渐变&#xff08;Radial Gradient&#xff09;语法&#xff1a;示例&#xff1a; ⭐ 写…

Tesseract用OpenCV进行文本检测

我没有混日子&#xff0c;只是辛苦的时候没人看到罢了 一、什么是Tesseract Tesseract是一个开源的OCR&#xff08;Optical Character Recognition&#xff09;引擎&#xff0c;OCR是一种技术&#xff0c;它可以识别和解析图像中的文本内容&#xff0c;使计算机能够理解并处理…

骨传导运动耳机推荐?这几款耳机不仅配置高性价比也高!

目前&#xff0c;骨传导运动耳机是运动圈颇受欢迎的耳机之一&#xff0c;骨传导耳机就是基于骨传导原理设计制造的。骨传导耳机把声音转化为不同频率的振动&#xff0c;通过振动颅骨使人感知到声音。由于能够“敞开”双耳&#xff0c;骨传导耳机解决了传统耳机长时间佩戴不适以…

日常BUG —— Java判空注解

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一. 问题描述 问题一&#xff1a; 在使用Java自带的注解NotNull、NotEmpty、NotBlank时报错&#xff0c;…

探索自动化网页交互的魔力:学习 Selenium 之旅【超详细】

"在当今数字化的世界中&#xff0c;网页自动化已经成为了不可或缺的技能。想象一下&#xff0c;您可以通过编写代码&#xff0c;让浏览器自动执行各种操作&#xff0c;从点击按钮到填写表单&#xff0c;从网页抓取数据到进行自动化测试。学习 Selenium&#xff0c;这一功能…

postman入门基础 —— 接口测试流程

一、编写接口测试计划 接口测试计划和功能测试计划目标一致&#xff0c;都是为了确认需求、确定测试环境、确定测试方法&#xff0c;为设计测试用例做准备&#xff0c;初步制定接口测试进度方案。一般来说&#xff0c;接口测试计划包括概述、测试资源、测试功能、测试重点、测试…

【Java】2021 RoboCom 机器人开发者大赛-高职组(复赛)题解

7-8 人工智能打招呼 号称具有人工智能的机器人&#xff0c;至少应该能分辨出新人和老朋友&#xff0c;所以打招呼的时候应该能有所区别。本题就请你为这个人工智能机器人实现这个功能&#xff1a;当它遇到陌生人的时候&#xff0c;会说&#xff1a;“Hello X, how are you?”其…

Debian 12.1 正式发布

导读Debian 12.1 现已发布&#xff0c;这是对稳定发行版 Debian 12&#xff08;代号 Bookworm &#xff09;的首次更新。本次发布主要增加了安全问题的修正&#xff0c;并对严重问题进行了一些调整。 一些更新内容包括&#xff1a; 妥善处理系统用户的创建&#xff1b;修复 eq…

A Survey for In-context Learning

A Survey for In-context Learning 摘要&#xff1a; 随着大语言模型(LLMs)能力的增长&#xff0c;上下文学习(ICL)已经成为一个NLP新的范式&#xff0c;因为LLMs仅基于几个训练样本让内容本身增强。现在已经成为一个新的趋势去探索ICL来评价和extrapolate LLMs的能力。在这篇…

二次封装element-plus上传组件,提供校验、回显等功能

二次封装element-plus上传组件 0 相关介绍1 效果展示2 组件主体3 视频组件4 Demo 0 相关介绍 基于element-plus框架&#xff0c;视频播放器使用西瓜视频播放器组件 相关能力 提供图片、音频、视频的预览功能提供是否为空、文件类型、文件大小、文件数量、图片宽高校验提供图片…