SpringBoot整合MQTT利用EMQX完成消息的发布与接收+Python模拟硬件测试通信

教程说明

本教程主要内容为使用SpringBoot整合MQTT利用EMQX代理服务完成MQTT的消息发送与接收,然后用Python模拟硬件与SpringBoot应用进行了MQTT消息的通信,教程详细,并在最后讲解了开发中的注意事项,本教程适用于物联网领域、JavaWeb领域的开发人员。

前置所需

已经搭建好了EMQX代理服务,不懂的可以参考上一篇文章 CentOS7安装EMQX并搭建个人MQTT代理服务器 | Python实现MQTT通信测试教程

内容架构

如图,教程内容主要是用到了这三个端,对于Python的测试,可有可无,这里只是模拟硬件测试与SpringBoot的通信,并且便于理解MQTT的通信

QQ_1732244919285

大致步骤

1.确定SpringBoot版本并导入所需依赖
2.yaml配置相关参数
3.确定包结构并编写读取yaml参数的组件
4.编写客户端回调组件
5.编写MQTT的发送客户端和接收客户端
6.编写MQTT监听接收消息的配置类
7.编写控制器测试SpringBoot应用自身消息与发送
8.利用Python与SpringBoot进行MQTT通信交互
9.重要的注意事项分析

步骤1.确定SpringBoot版本并导入所需依赖

我这里所使用的SpringBoot版本为2.3.4RELEASE,JDK使用1.8,Maven随意,如图

QQ_1732246422790

然后所使用的依赖为如下,我这里列出我所有使用到的依赖,最上面三个是MQTT相关的依赖

<!-- mqtt -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-integration</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-stream</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-mqtt</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

步骤2.yaml配置相关参数

在application.yaml中配置如下参数,注意将hostUrl的ip替换为你自己的EMQX所在ip,如图

mqtt:
  hostUrl: tcp://111.111.11.111:1883
  username: 123
  password: 321
  client-id: testId #虽然这里 幽络源配置了client-id,但是在获取客户端连接时,我是用的uuid,避免重复
  cleanSession: false

  #开发时这里的自动重连接一定要设置false,不然会由于热部署导致连接两个相同的clientId,出现bug
  #真正部署时这里的自动重连接 再设置为true,这样就可以保证 由于网络原因即使连接断开也会自动重连接
  reconnect: true
  timeout: 100
  keepAlive: 100
  topic: test/topic
  isOpen: true
  qos: 0

QQ_1732246924976

步骤3.确定包结构并编写读取yaml参数的组件

包结构比较简单,只需要建立config和controller包即可,如图,config包用于放置我们的MQTT相关配置文件,controller用于放置接口

QQ_1732249646196

由于我们的MQTT相关配置文件甚至接口中都会用到yaml中配置的参数,方便起见,建立一个专门读取yaml中mqtt参数的组件并利用lombok提供get/set方法,在config包下建立MqttProperties.java文件,代码与图如下

package com.youluoyuan.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;


@Component
@ConfigurationProperties("mqtt")
@Data
public class MqttProperties {

    //mqtt认证的用户名
    private String username;
    //mqtt认证的用户对应的密码
    private String password;
    //ip地址
    private String hostUrl;
    //客户端id
    private String clientId;
    //主题
    private String topic;
    //超时时间
    private int timeout;
    //心跳
    private int keepAlive;
    //是否清理session
    private Boolean cleanSession;
    //是否自动重连
    private Boolean reconnect;
    //启动项目的时候是否启动mqtt
    private Boolean isOpen;
    //连接方式
    private Integer qos;

}

QQ_1732252001748

步骤4.编写客户端回调组件

在config包下建立MqttCallBack.java文件,用于消息发送和接收客户端进行触发,加入如下代码

package com.youluoyuan.config;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * MQTT客户端回调
 */
@Component
public class MqttCallBack implements MqttCallbackExtended {

    private static final Logger logger = LoggerFactory.getLogger(MqttCallBack.class);

    /**
     * 客户端断开后的回调
     * @param throwable
     */
    @Override
    public void connectionLost(Throwable throwable) {
        logger.info("客户端连接已断开");
    }

    /**
     * 客户端接收消息的回调
     * @param topic  主题
     * @param mqttMessage 消息
     */
    @Override
    public void messageArrived(String topic, MqttMessage mqttMessage){
        logger.info("收到消息:主题 => "+ topic+",Qos => "+ mqttMessage.getQos() +",内容 => "  + new String(mqttMessage.getPayload()));
    }


    /**
     * 客户端发送消息的回调
     * @param token
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        String[] topics = token.getTopics();
        try {
            MqttMessage message = token.getMessage();
            byte[] payload = message.getPayload();
            String s = new String(payload, "UTF-8");
            for (String topic : topics) {
                logger.info("消息发送成功,主题为 => "+topic+",内容为 => " + s);
            }
        } catch (Exception e) {
            logger.error("消息发送失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * MQTT连接回调
     * @param reconnect 是否为重连
     * @param serverURI 服务URI
     */
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        logger.info("===客户端" + MqttAcceptClient.client.getClientId() + "连接成功!===");
    }
}

步骤5.编写MQTT的发送客户端和接收客户端

在config包下建立MqttSendClient.java,作为消息发送客户端,代码如下

package com.youluoyuan.config;

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.UUID;

/**
 * MQTT消息发送客户端
 */
@Component
public class MqttSendClient {

    private static final Logger logger = LoggerFactory.getLogger(MqttSendClient.class);

    @Autowired
    private MqttCallBack mqttSendCallBack;

    @Autowired
    private MqttProperties mqttProperties;

    //连接MQTT代理服务器并设置回调
    public MqttClient connect() {
        MqttClient client = null;
        try {
            String clientId = UUID.randomUUID().toString().replaceAll("-", "");
            //获取MQTT客户端
            client = new MqttClient(mqttProperties.getHostUrl(), clientId, new MemoryPersistence());
            //设置连接参数
            MqttConnectOptions options = new MqttConnectOptions();
            options.setUserName(mqttProperties.getUsername());
            options.setPassword(mqttProperties.getPassword().toCharArray());
            options.setConnectionTimeout(mqttProperties.getTimeout());
            options.setKeepAliveInterval(mqttProperties.getKeepAlive());
            options.setCleanSession(mqttProperties.getCleanSession());
            options.setAutomaticReconnect(mqttProperties.getReconnect());
            // 设置回调
            client.setCallback(mqttSendCallBack);
            client.connect(options);
        } catch (Exception e) {
            logger.error("MQTT消息发送客户端连接失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        }
        return client;
    }

    /**
     * 发送消息
     * @param retained 是否保留
     * @param topic 主题
     * @param content 内容
     */
    public void publish(boolean retained, String topic, String content) {
        //创建消息
        MqttMessage message = new MqttMessage();
        //设置消息参数
        message.setQos(mqttProperties.getQos());
        message.setRetained(retained);
        message.setPayload(content.getBytes());
        MqttDeliveryToken token;
        //获取连接
        MqttClient mqttClient = connect();
        try {
            mqttClient.publish(mqttProperties.getTopic(), message);
        } catch (MqttException e) {
            logger.error("MQTT消息发送客户端发送消息失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        } finally {
            disconnect(mqttClient);
            close(mqttClient);
        }
    }

    /**
     * 取消连接
     * @param mqttClient 客户端
     */
    public static void disconnect(MqttClient mqttClient) {
        try {
            if (mqttClient != null)
                mqttClient.disconnect();
        } catch (MqttException e) {
            logger.error("MQTT消息发送客户端取消连接失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 释放资源
     * @param mqttClient 客户端
     */
    public static void close(MqttClient mqttClient) {
        try {
            if (mqttClient != null)
                mqttClient.close();
        } catch (MqttException e) {
            logger.error("MQTT消息发送客户端释放资源失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        }
    }
}

再在config包下建立MqttAcceptClient.java,作为消息接收客户端,代码如下

package com.youluoyuan.config;

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.UUID;


/**
 * MQTT消息接收客户端
 */
@Component
public class MqttAcceptClient {

    private static final Logger logger = LoggerFactory.getLogger(MqttAcceptClient.class);

    @Autowired
    private MqttCallBack mqttCallBack;

    @Autowired
    private MqttProperties mqttProperties;

    public static MqttClient client;

    private static MqttClient getClient() {
        return client;
    }

    private static void setClient(MqttClient client) {
        MqttAcceptClient.client = client;
    }

    //连接MQTT代理服务器并设置回调
    public void connect() {
        MqttClient client;
        try {
            String clientId = UUID.randomUUID().toString().replaceAll("-", "");
            //获取MQTT客户端
            client = new MqttClient(mqttProperties.getHostUrl(), clientId,new MemoryPersistence());
            //设置连接参数
            MqttConnectOptions options = new MqttConnectOptions();
            options.setUserName(mqttProperties.getUsername());
            options.setPassword(mqttProperties.getPassword().toCharArray());
            options.setConnectionTimeout(mqttProperties.getTimeout());
            options.setKeepAliveInterval(mqttProperties.getKeepAlive());
            options.setCleanSession(mqttProperties.getCleanSession());
            options.setAutomaticReconnect(mqttProperties.getReconnect());
            MqttAcceptClient.setClient(client);
            // 设置回调
            client.setCallback(mqttCallBack);
            client.connect(options);
        } catch (Exception e) {
            logger.error("MQTT消息接收客户端连接失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        }
    }

    //重新连接
    public void reconnection() {
        try {
            client.connect();
        } catch (MqttException e) {
            logger.error("MQTT消息接收客户端重新连接失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * 订阅主题
     * @param topic 主题
     * @param qos 连接方式
     */
    public void subscribe(String topic, int qos) {
        logger.info("===MQTT消息接收客户端订阅主题:" + topic + "===");
        try {
            client.subscribe(topic, qos);
        } catch (MqttException e) {
            logger.error("MQTT消息接收客户端订阅主题失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 取消订阅主题
     * @param topic
     */
    public void unsubscribe(String topic) {
        logger.info("===MQTT消息接收客户端取消订阅主题:" + topic + "====");
        try {
            client.unsubscribe(topic);
        } catch (MqttException e) {
            logger.error("MQTT消息接收客户端取消订阅主题失败,错误信息 => {}", e.getMessage());
            e.printStackTrace();
        }
    }
}

有了如上两个客户端,我们的SpringBoot就能既作消息发送者,也能作为消息接收者,也就是可以既能获取到硬件传来的信息,也能通过发送消息去控制硬件

步骤6.编写MQTT监听接收消息的配置类

在config包下建立MqttConfig.java,此配置文件用于启动SpringBoot使,就订阅我们配置的主题进行消息的监听接收,代码与图如下

package com.youluoyuan.config;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 *启动服务的时候开启监听客户端
 */
@Configuration
public class MqttConfig {

    @Autowired
    private MqttAcceptClient mqttAcceptClient;

    @Autowired
    private MqttProperties mqttProperties;

    //订阅主题
    @Bean
    public MqttAcceptClient getMqttPushClient() {
        System.out.println("开启监听客户端");
        mqttAcceptClient.connect();
        mqttAcceptClient.subscribe(mqttProperties.getTopic(),mqttProperties.getQos());
        return mqttAcceptClient;
    }
}

QQ_1732252966566

步骤7.编写控制器测试SpringBoot应用自身消息与发送

在controller包中建立MqttController.java,提供一个GET,用于触发消息的发送,代码与图如下

package com.youluoyuan.controller;

import com.youluoyuan.config.MqttSendClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 测试接口
 */
@RestController
@RequestMapping("/mqtt")
public class MqttController {

    @Autowired
    private MqttSendClient mqttSendClient;

    @GetMapping(value = "/public")
    public String publishTopic(String topic, String msg) {
        mqttSendClient.publish(false, topic, msg);
        return "topic:" + topic + ",msg:" + msg;
    }

}

QQ_1732253048957

然后启动SpringBoot应用,如图可以看到控制台中,我们配置的消息接收监听已经启动了,并且客户端的clientId为uuid,默认启动的端口为8080

QQ_1732253233499

由于我们的接口是GET请求的,直接在浏览器输入如下地址,然后访问,如图

http://localhost:8080/mqtt/public?topic=test/topic&msg=222

QQ_1732253660654

然后可以看到控制台中,日志输出了消息的发送和接收,到这一步,可以说SpringBoot已经做到了既可作为消息发送客户端又可作为消息接收客户端了(如果你请求一次接口,发现输出了多次收到消息,这是因为热部署导致的,步骤9会讲解原因)

QQ_1732253560225

步骤8.利用Python与SpringBoot进行MQTT通信交互

如果你只是需要明白SpingBoot如何整合MQTT,并且对MQTT的通信已经有足够的理解,这一步骤可以跳过,但是步骤9一定要看

本步骤主要是用于使用Python模拟硬件测试与SpringBoot程序MQTT通信

创建定时发布消息的代码如下,注意将BROKER填上自己的EMQX服务所在IP

import paho.mqtt.client as mqtt
import threading
import time

# MQTT 代理配置
BROKER = ""  # 例如 "127.0.0.1" 或 公网IP
PORT = 1883  # MQTT 默认端口(非加密)
TOPIC = "test/topic"  # 要发布/订阅的主题
USERNAME = "123"
PASSWORD = "321"  # 对应的密码
CLIENTID = "testId"

# 连接成功回调(新版 API)
def on_connect(client, userdata, flags, reasonCode, properties=None):
    if reasonCode == 0:
        print("已连接到MQTT代理")
        client.subscribe(TOPIC)  # 订阅主题
        print(f"已订阅主题: {TOPIC}")
    else:
        print(f"连接MQTT代理失败, 响应码为: {reasonCode}")

# 定时发布消息的函数
def publish_message(client):
    while True:
        client.publish(TOPIC, "你好,我定时发布了一条消息", qos=1)
        print("定时消息已发布")
        time.sleep(5)  # 每隔 5 秒发布一次消息

# 创建 MQTT 客户端
client = mqtt.Client()
client.username_pw_set(USERNAME, PASSWORD)
client.on_connect = on_connect

try:
    # 连接到 MQTT 代理
    client.connect(BROKER, PORT, 60)

    # 启动一个线程定时发布消息
    threading.Thread(target=publish_message, args=(client,), daemon=True).start()

    # 启动网络循环,保持连接
    client.loop_forever()
except Exception as e:
    print(f"Error: {e}")

然后启动Python程序,如图可以看到Python程序在定时的发送消息,并且SpringBoot应用也在实时的接收消息

QQ_1732254079552

然后来测试利用SpringBoot中的接口向Python模拟的硬件发送消息,看看是否能收到消息

消息接收代码如下

import paho.mqtt.client as mqtt

# MQTT 代理配置
BROKER = ""  # 例如 "127.0.0.1" 或 公网IP
PORT = 1883  # MQTT 默认端口(非加密)
TOPIC = "test/topic"  # 要发布/订阅的主题
USERNAME = "123"
PASSWORD = "321"  # 对应的密码

# 连接成功回调(新版 API)
def on_connect(client, userdata, flags, reasonCode, properties=None):
    if reasonCode == 0:
        print("已成功连接到 MQTT 代理")
        client.subscribe(TOPIC)  # 订阅主题
        print(f"已订阅主题: {TOPIC}")
    else:
        print(f"连接失败, 响应码为: {reasonCode}")

# 收到消息回调(新版 API)
def on_message(client, userdata, msg, properties=None):
    print(f"接收到消息: {msg.payload.decode()} 来自主题: {msg.topic}")

# 创建 MQTT 客户端
client = mqtt.Client()

# 设置用户名和密码
client.username_pw_set(USERNAME, PASSWORD)

# 绑定回调函数
client.on_connect = on_connect
client.on_message = on_message

try:
    # 连接到 MQTT 代理
    client.connect(BROKER, PORT, 60)

    # 启动网络循环,保持连接并监听消息
    client.loop_forever()
except Exception as e:
    print(f"Error: {e}")

然后还是在浏览器访问我们刚才那个地址,可以看到调用接口后,SpringBoot和Python控制台中都显示出收到消息了,说明我们的模拟没问题

QQ_1732254231555

步骤9.重要的注意事项分析

这里的重要的注意事项分析主要指的是yaml中的参数reconnect,这个参数本身不存在BUG,但是用idea在开发时,由于SpringBoot自身的热部署原因会出现BUG,具体BUG和原因为我们来复现一下

首先将yaml中的reconnect参数设置为true,如图

QQ_1732255749390

然后将MqttSendClient.java文件和MqttAcceptClient.java文件中的connect函数在获取客户端时,将clientId修改为从yaml中读取,不再使用uuid,如图

QQ_1732254595047

然后我们启动SpringBoot项目,刚启动时没什么问题,然后我们在任意java文件中的任意位置随便打上几个空格,然后ctrl+s保存来触发SpringBoot的热部署功能,然后就会发现,控制台中客户端在不断的重连和断开

这是因为我们的客户端使用的是yaml中同一个clientId,热部署后又会重新启动一个客户端,而先前启动的客户端还存在,因此两个客户端会不断的重启将对方挤下去,所以一定要注意开发时,reconnect设置为false,最后不要忘记了,将客户端获取连接时传入的clientId恢复为uuid。

QQ_1732254949418

结语

以上是幽络源原创的SpringBoot整合MQTT,并通过EMQX代理,完成与Python模拟硬件进行MQTT通信的教程。如有不懂之处,可在评论区或加Q群307531422询问交流。

原文链接=>SpringBoot整合MQTT利用EMQX完成消息的发布与接收+Python模拟硬件测试通信

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IntelliJ IDEA 中,自动删除无用导包

在 IntelliJ IDEA 中&#xff0c;自动删除无用导包是一个提升代码整洁性和开发效率的重要功能。以下是实现这一功能的详细步骤&#xff1a; 一、通过快捷键手动删除无用导包 打开Java文件&#xff1a;在IDEA中打开你需要操作的Java文件。 使用快捷键&#xff1a; 在Windows系…

表格数据处理中大语言模型的微调优化策略研究

论文地址 Research on Fine-Tuning Optimization Strategies for Large Language Models in Tabular Data Processing 论文主要内容 这篇论文的主要内容是研究大型语言模型&#xff08;LLMs&#xff09;在处理表格数据时的微调优化策略。具体来说&#xff0c;论文探讨了以下…

如何编写一个 Vue 3 应用:模板插值示例

Vue.js 是一个渐进式的 JavaScript 框架&#xff0c;用于构建用户界面。在本篇博客中&#xff0c;我们将通过一个简单的示例来学习如何使用 Vue 3 创建一个基本的应用。这个示例将展示如何使用 Vue 的模板插值和事件处理来构建一个简单的点击计数器。 步骤 1: 准备工作 首先&…

基于混合ABC和A*算法复现

基于混合ABC和A*算法复现 一、背景介绍二、算法原理&#xff08;一&#xff09;A*算法原理&#xff08;二&#xff09;人工蜂群算法原理&#xff08;三&#xff09;混合ABC和A*算法策略 三、代码实现&#xff08;一&#xff09;数据准备&#xff08;二&#xff09;关键函数实现…

2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略(详细解题思路)

在当下&#xff0c; 日益发展的时代&#xff0c;宠物的数量应该均为稳步上升&#xff0c;在美国出现了下降的趋势&#xff0c; 中国 2019-2020 年也下降&#xff0c;这部分变化可能与疫情相关。需要对该部分进行必要的解释说明。 问题 1: 基于附件 1 中的数据及您的团队收集的额…

鸿蒙MVVM模式介绍与使用

文章目录 鸿蒙MVVM模式介绍与使用背景MVVM模式介绍相关装饰器介绍State状态变量Prop、Link的作用 MVVM架构模式的实现以及相关装饰器的使用具体实现效果 总结 鸿蒙MVVM模式介绍与使用 背景 最近在学习鸿蒙开发,想到了以前写安卓移动端应用时经常会用到的MVVM架构模式,就想着能…

Jmeter测试工具的安装和使用,mac版本,jmeter版本5.2.1

Jmeter测试工具的安装和使用JSON格式请求 一、安装1、安装jdk包和设置java环境2、去官网下载Jmeter3、解压后&#xff0c;打开mac终端&#xff0c;进入apache-jmeter的bin文件开启jmeter 二、使用jmeter1、添加线程2、添加HTTP请求3、配置请求的协议、IP地址、端口号、请求方法…

Spring Boot教程之十: 使用 Spring Boot 实现从数据库动态下拉列表

使用 Spring Boot 实现从数据库动态下拉列表 动态下拉列表&#xff08;或依赖下拉列表&#xff09;的概念令人兴奋&#xff0c;但编写起来却颇具挑战性。动态下拉列表意味着一个下拉列表中的值依赖于前一个下拉列表中选择的值。一个简单的例子是三个下拉框&#xff0c;分别显示…

Vue前端开发2.3.6 列表渲染指令

在Vue.js中&#xff0c;v-for指令是渲染列表的关键工具&#xff0c;支持从数组、对象、数字和字符串中生成列表。它简化了商品列表等重复元素的创建。为了优化性能&#xff0c;key属性为每个列表项提供唯一标识&#xff0c;帮助Vue追踪节点身份&#xff0c;实现元素重用。实战中…

敏捷开发02:敏捷开发之Scrum开发框架介绍

一、什么是 Scrum 1.1 Scrum 定义 Scrum 是敏捷开发方法之一&#xff0c;它使用比较广泛。 敏捷的其它开发方法还有 XP(极限编程)、FDD(特性驱动开发)、Crystal(水晶方法)、TDD(测试驱动开发)、DSDM(动态系统开发)等等敏捷方法。 Scrum-Guide 中定义的 Scrum&#xff1a; S…

使用mingw+CMake在Windows平台编译OpenCV

1. 安装mingw和cmake cmake的安装比较简单&#xff0c;百度一下完成相关操作即可&#xff0c;笔者安装的是3.24.3版本。 Mingw的安装也有很多相关文章&#xff0c;不过我使用的是安装QT时附带安装的mingw&#xff0c;其路径为D:\software\Qt\Tools\mingw1120_64。其中的bin文件…

能源电力企业安全数据内外网文件交换

在数字化浪潮的推动下&#xff0c;能源电力行业数据交换的频率急剧上升&#xff0c;涉及的视频、研发、设计等各类文件数量庞大。这些文件的内外网传输不仅要追求速度&#xff0c;更要确保数据安全。随着国家对数据安全重视程度的提高&#xff0c;《网络安全法》和《数据安全法…

突破内存限制:Mac Mini M2 服务器化实践指南

本篇文章&#xff0c;我们聊聊如何使用 Mac Mini M2 来实现比上篇文章性价比更高的内存服务器使用&#xff0c;分享背后的一些小的思考。 希望对有类似需求的你有帮助。 写在前面 在上文《ThinkPad Redis&#xff1a;构建亿级数据毫秒级查询的平民方案》中&#xff0c;我们…

C++ 二叉搜索树(Binary Search Tree, BST)深度解析与全面指南:从基础概念到高级应用、算法优化及实战案例

&#x1f31f;个人主页&#xff1a;落叶 &#x1f31f;当前专栏: C专栏 目录 ⼆叉搜索树的概念 ⼆叉搜索树的性能分析 ⼆叉搜索树的插⼊ ⼆叉搜索树的查找 二叉搜索树中序遍历 ⼆叉搜索树的删除 cur的左节点为空的情况 cur的右节点为空的情况 左&#xff0c;右节点都不为…

数据库、数据仓库、数据湖、数据中台、湖仓一体的概念和区别

数据库、数据仓库、数据湖、数据中台和湖仓一体是数据管理和分析领域的不同概念&#xff0c;各自有不同的特点和应用场景。以下是它们的主要区别&#xff1a; 1. 数据库&#xff08;Database&#xff09; 定义&#xff1a;结构化的数据存储系统&#xff0c;用于高效地存储、检…

RabbitMQ原理架构解析:消息传递的核心机制

文章目录 一、RabbitMQ简介1.1、概述1.2、特性 二、RabbitMQ原理架构三、RabbitMQ应用场景3.1、简单模式3.2、工作模式3.3、发布订阅3.4、路由模式3.5 主题订阅模式 四、同类中间件对比五、RabbitMQ部署5.1、单机部署5.2、集群部署&#xff08;镜像模式&#xff09;5.3、K8s部署…

idea_常用设置

相关设置 项目的JDK设置out目录取消自动更新设置主题设置菜单和窗口字体大小滚轮调节字体大小显示行号与方法分隔符代码智能提示忽略大小写自动导包配置设置项目文件编码设置控制台的字符编码修改类头的文档注释信息设置自动编译 项目的JDK设置 File -> Project Structure -…

Redis的管道操作

在现代应用程序中&#xff0c;Redis作为一种高性能的内存数据库&#xff0c;被广泛用于缓存、消息队列、实时分析等场景。为了进一步提高Redis的性能&#xff0c;Redis提供了管道&#xff08;Pipeline&#xff09;操作&#xff0c;允许客户端将多个命令一次性发送到服务器&…

详解登录MySQL时出现SSL connection error: unknown error number错误

目录 登录MySQL时出错SSL connection error: unknown error number 出错原因 使用MySQL自带的工具登录MySQL 登陆之后&#xff0c;使用如下命令进行查看 解决方法 找到MySQL8安装目录下的my.ini配置文件 记事本打开my.ini文件&#xff0c;然后按下图所示添加配置 此时再…

E2、UML类图顺序图状态图实训

一、实验目的 在面向对象的设计里面&#xff0c;可维护性复用都是以面向对象设计原则为基础的&#xff0c;这些设计原则首先都是复用的原则&#xff0c;遵循这些设计原则可以有效地提高系统的复用性&#xff0c;同时提高系统的可维护性。在掌握面向对象七个设计原则基础上&…