Day116 若依融合mqtt

MQTT

1.MQTT協議概述

MQTT是一種基于發布/訂閱模式的輕量級消息傳輸協議,設計用于低帶寬、高延遲或不穩定的網絡環境,廣泛應用于物聯網領域

1.1 MQTT協議的應用場景

1.智能家居、車聯網、工業物聯網:MQTT可以用于連接各種家電設備和傳感器,實現設備之間的通信和控制

2.遠程監控和控制 : MQTT可以用于將傳感器數據發布到云平臺,供其他設備或應用程序訂閱和使用

3.消息通知:MQTT可以用于提供實時消息通知功能

4.資源監控與管理:MQTT能夠提供對物聯網設備的實時監控和管理功能

5.數據采集和分析:MQTT也可以用于數據采集和分析

1.2 MQTT協議優勢

1.常見的計算機語言(C/C++、Java、Python、Go…)都有支持MQTT協議的客戶端

2.MQTT協議是建立在TCP/IP協議基礎之上,所以MQTT協議安全可靠

3.服務質量設置,MQTT協議提供了三種服務質量配置分別為:
Qos 0:消息可能丟失
Qos 1:消息不會丟失,但是可能重復
Qos 2:消息不會丟失也不會重復

4.心跳保活:由于網絡問題可能造成連接陷于假死狀態,為了判斷客戶端和代理是否出現異常,MQTT定義自己的心跳機制,定期向代理發送報文,以便于快速識別出異常連接,讓客戶端快速與代理斷開連接

5.持久會話: 代理保留客戶端發送過來的消息,以便于消息訂閱端上線立刻獲取消息

1.3 MQTT協議報文

MQTT報文(數據包)由三部分組成:

1.固定報頭(Fixed header):所有數據包中都包含此報頭,用來表示數據包的類型,以及數據包的分組累標識

2.可變報頭(Variable header):存在于部分MQTT數據包中,數據包類型決定了可變頭是否存在及其具體內容

3.有效載荷(Payload):存在于部分MQTT數據包中,表示客戶端收到的具體內容

在這里插入圖片描述

1.4 MQTT協議的工作原理

在這里插入圖片描述

MQTT協議基于TCP/IP協議,TCP/IP協議是一個安全穩定的協議,通信需要服務端和客戶端經歷三次握手四次揮手,建立一個穩定的通道然后在進行數據傳輸

MQTT協議建立在TCP/IP協議之上,也是需要編寫服務端(上圖中的Broker)和客戶端(消息發布者和消息訂閱者)

2.MQTT代理服務器介紹和搭建

EMQX官網地址: https://www.emqx.io/zh

介紹:

1.開源大規模分布式MQTT代理服務器

2.單臺并發連接數可以高達一億,每秒處理百萬級消息

3.安全可靠的消息傳遞

2.1 EMQX安裝: windows

1.下載地址: https://www.emqx.io/zh/get-started

2.安裝步驟:

第一步: 下載 emqx-5.3.2-windows-amd64.zip 安裝包,版本可能和我這個不同

第二步: 解壓

第三步: 打開命令行(以管理員身份運行),切換到解壓目錄的bin目錄下

第四步: 安裝,在bin目錄下執行EMQX安裝命令 emqx.cmd install,完成之后有類似下面的輸出,說明安裝成功,只需要安裝一次(運行命令)

? D:\app\emqx-5.3.2-windows-amd64\bin>emqx.cmd install
? EMQX_NODE__DB_ROLE [node.role]: core
? EMQX_NODE__DB_BACKEND [node.db_backend]: mnesia
? D:\app\emqx-5.3.2-windows-amd64\erts-13.2.2.4\bin\erlsrv.exe: Service emqx_5.3.2 added to system.
? [SC] ChangeServiceConfig 成功

第五步(可選擇):如果想將EMQX從windows上卸載,可以執行 emqx.cmd uninstall 命令

第六步:去windows服務列表中找到第四步安裝的EMQX的服務,鼠標右鍵啟動

第七步:在命令行輸入 emqx.cmd console 命令,查看是否啟動成功,如果有類似以下日志啟動成功

? D:\app\emqx-5.3.2-windows-amd64\bin>emqx.cmd console
? EMQX_LOG__CONSOLE_HANDLER__ENABLE [log.console.enable]: true
? EMQX_NODE__DB_ROLE [node.role]: core
? EMQX_NODE__DB_BACKEND [node.db_backend]: mnesia

D:\app\emqx-5.3.2-windows-amd64>D:\app\emqx-5.3.2-windows-amd64\erts-13.2.2.4\bin\erl.exe -mode embedded -boot “D:\app\emqx-5.3.2-windows-amd64\releases\5.3.2\start” -config “D:\app\emqx-5.3.2-windows-amd64\data\configs\app.2024.05.06.16.38.19.config” -args_file “D:\app\emqx-5.3.2-windows-amd64\data\configs\vm.2024.05.06.16.38.19.args” -mnesia dir ‘d:/app/emqx-5.3.2-windows-amd64/data/mnesia/emqx@127.0.0.1’
Listener ssl:default on 0.0.0.0:8883 started.
Listener tcp:default on 0.0.0.0:1883 started.
Listener ws:default on 0.0.0.0:8083 started.
Listener wss:default on 0.0.0.0:8084 started.
Listener http:dashboard on :18083 started.
EMQX 5.3.2 is running now!
Eshell V13.2.2.4 (abort with ^G)
v5.3.2(emqx@127.0.0.1)1>

第八步:通過瀏覽器訪問控制臺http://127.0.0.1:18083,默認初始化用戶名: admin,默認密碼: public,進入之后會讓你重新修改密碼

注意事項: (第六步+第七步)這種啟動方式在開發時使用,如果想正式環境使用請遵循官網命令啟動介紹: 正式環境啟動在bin目錄下直接輸入 emqx start進行EMQX啟動,這時不需要(第六步和第七步)

官網命令詳細使用地址: https://www.emqx.io/docs/zh/latest/admin/cli.html

2.2 MQTT客戶端工具MQTTX

EMQX官網自帶工具MQTTX,官網地址: https://mqttx.app/zh/downloads

傻瓜式安裝,無腦下一步

若依框架融合mqtt

倉庫地址:https://gitee.com/peng-chuanbin/iot-mqtt.git

實現效果:(初步Demo實現)

點擊網頁的按鈕(發送數據),mqtt能夠接收到發送的數據

mqtt發送數據,Java程序能夠接收到,并且存儲到數據庫中

1.下載mqttx

在這里插入圖片描述

2.運行項目

1.新建一個mqtt數據庫,然后運行sql文件,修改yaml中的數據庫配置

在這里插入圖片描述

2.pom.xml添加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>

3.utils包下新建一個mqtt包,添加三個文件

package com.ruoyi.common.utils.mqtt;@Component
@ConfigurationProperties("spring.mqtt")
public class MqttConfig {@Autowiredprivate MqttPushClient mqttPushClient;/*** 用戶名*/private String username;/*** 密碼*/private String password;/*** 連接地址*/private String hostUrl;/*** 客戶Id*/private String clientId;/*** 默認連接話題*/private String defaultTopic;/*** 超時時間*/private int timeout;/*** 保持連接數*/private int keepalive;/*** mqtt功能使能*/private boolean enabled;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getHostUrl() {return hostUrl;}public void setHostUrl(String hostUrl) {this.hostUrl = hostUrl;}public String getClientId() {return clientId;}public void setClientId(String clientId) {this.clientId = clientId;}public String getDefaultTopic() {return defaultTopic;}public void setDefaultTopic(String defaultTopic) {this.defaultTopic = defaultTopic;}public int getTimeout() {return timeout;}public void setTimeout(int timeout) {this.timeout = timeout;}public int getKeepalive() {return keepalive;}public void setKeepalive(int keepalive) {this.keepalive = keepalive;}public boolean isEnabled() {return enabled;}public void setEnabled(boolean enabled) {this.enabled = enabled;}@Beanpublic MqttPushClient getMqttPushClient() {if (enabled == true) {mqttPushClient.connect(hostUrl, clientId, username, password, timeout, keepalive);//訂閱java主題   #重要,這里確定主題是哪一個mqttPushClient.subscribe("java",0);}return mqttPushClient;}
}

PushCallback

package com.ruoyi.common.utils.mqtt;@Component
public class PushCallback implements MqttCallback {private static final Logger logger = LoggerFactory.getLogger(MqttPushClient.class);@Autowiredprivate MqttConfig mqttConfig;private static MqttClient client;private static String _topic;private static String _qos;private static String _msg;@Overridepublic void connectionLost(Throwable throwable) {// 連接丟失后,一般在這里面進行重連logger.info("連接斷開,可以做重連");if (client == null || !client.isConnected()) {mqttConfig.getMqttPushClient();}}@Overridepublic void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {// subscribe后得到的消息會執行到這里面logger.info("接收消息主題 : " + topic);logger.info("接收消息Qos : " + mqttMessage.getQos());logger.info("接收消息內容 : " + new String(mqttMessage.getPayload()));}@Overridepublic void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {logger.info("deliveryComplete---------" + iMqttDeliveryToken.isComplete());}}

MqttPushClient

package com.ruoyi.common.utils.mqtt;@Component
public class MqttPushClient {private static final Logger logger = LoggerFactory.getLogger(MqttPushClient.class);@Autowiredprivate PushCallback pushCallback;private static MqttClient client;private static MqttClient getClient() {return client;}private static void setClient(MqttClient client) {MqttPushClient.client = client;}/*** 客戶端連接** host  ip+端口* clientID  客戶端Id* username  用戶名* password  密碼* timeout 超時時間* keepalive 保留數*/public void connect(String host, String clientID, String username, String password, int timeout, int keepalive) {MqttClient client;try {client = new MqttClient(host, clientID, new MemoryPersistence());MqttConnectOptions options = new MqttConnectOptions();options.setCleanSession(true);options.setUserName(username);options.setPassword(password.toCharArray());options.setConnectionTimeout(timeout);options.setKeepAliveInterval(keepalive);MqttPushClient.setClient(client);try {client.setCallback(pushCallback);client.connect(options);} catch (Exception e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}}/*** 發布* qos 連接方式* retained 是否保留* topic 主題* pushMessage 消息體*/public AjaxResult publish(int qos, boolean retained, String topic, String pushMessage) {MqttMessage message = new MqttMessage();message.setQos(qos);message.setRetained(retained);message.setPayload(pushMessage.getBytes());MqttTopic mTopic = MqttPushClient.getClient().getTopic(topic);if (null == mTopic) {logger.error("topic not exist");}MqttDeliveryToken token;try {token = mTopic.publish(message);token.waitForCompletion();return success();} catch (MqttPersistenceException e) {e.printStackTrace();return error();} catch (MqttException e) {e.printStackTrace();return error();}}/*** 訂閱某個主題* topic 主題* qos 連接方式*/public void subscribe(String topic, int qos) {logger.info("開始訂閱主題" + topic);try {MqttPushClient.getClient().subscribe(topic, qos);} catch (MqttException e) {e.printStackTrace();}}}

4.application.yml

如果有服務器了,直接修改broker.emqx.io這個就可以了,其他的都無所謂

broker.emqx.io:官方測試的

  # mqttmqtt:username: pcb # 用戶名password: 123456 # 密碼hostUrl: tcp://broker.emqx.io:1883 # tcp://ip:端口   #重要clientId: clientIdBamBam # 客戶端iddefaultTopic: topic,topic1 # 訂閱主題   #重要timeout: 100 # 超時時間 (單位:秒)keepalive: 60 # 心跳 (單位:秒)enabled: true # 是否使能mqtt功能

5.啟動mqttx,運行項目,訪問 http://localhost/ruoyi

在這里插入圖片描述

mqttx發送數據,Java程序接收數據

在這里插入圖片描述

3.設計前端界面

新建一個WlwController

package com.ruoyi.project.system.wlw.controller;@Controller
@RequestMapping("/system/wlw")
public class WlwController {private String prefix = "system/wlw";@GetMapping()public String wlw(){return prefix + "/w";}}

在resources包下的templates包中system包新建一個w.html界面,用來發送數據和顯示數據

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>wlw</title>
</head>
<body>1
</body>
</html>

ShiroConfig放開攔截

    /*** Shiro過濾器配置*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){// Shiro連接約束配置,即過濾鏈的定義LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 對靜態資源設置匿名訪問filterChainDefinitionMap.put("/favicon.ico**", "anon");filterChainDefinitionMap.put("/ruoyi.png**", "anon");filterChainDefinitionMap.put("/html/**", "anon");filterChainDefinitionMap.put("/css/**", "anon");filterChainDefinitionMap.put("/docs/**", "anon");filterChainDefinitionMap.put("/fonts/**", "anon");filterChainDefinitionMap.put("/img/**", "anon");filterChainDefinitionMap.put("/ajax/**", "anon");filterChainDefinitionMap.put("/js/**", "anon");filterChainDefinitionMap.put("/ruoyi/**", "anon");filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");// 退出 logout地址,shiro去清除sessionfilterChainDefinitionMap.put("/logout", "logout");// 不需要攔截的訪問filterChainDefinitionMap.put("/login", "anon,captchaValidate");// 不需要攔截的訪問 wlw   添加這句話filterChainDefinitionMap.put("/system/wlw", "anon,captchaValidate");}

訪問 http:/localhost:80/ruoyi/system/wlw

在這里插入圖片描述

4.設計假數據

新建數據庫表w

在這里插入圖片描述

使用若依自動生成代碼

在這里插入圖片描述

將生成的代碼放到指定位置

在這里插入圖片描述

xml文件,并且添加一句話:在執行插入(INSERT)操作之前,先生成一個主鍵值id,并將其設置到要插入的對象中

在這里插入圖片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.project.system.w.mapper.WMapper"><resultMap type="W" id="WResult"><result property="id"    column="id"    /><result property="topic"    column="topic"    /><result property="data"    column="data"    /></resultMap><sql id="selectWVo">select id, topic, data from w</sql><insert id="insertW" parameterType="W">//添加這句話<selectKey keyProperty="id" resultType="String" order="BEFORE" >SELECT REPLACE(UUID(),'-','') from dual</selectKey>insert into w<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="topic != null">topic,</if><if test="data != null">data,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id},</if><if test="topic != null">#{topic},</if><if test="data != null">#{data},</if></trim></insert></mapper>

前端文件

在這里插入圖片描述

啟動項目,新建菜單

在這里插入圖片描述

新增加一個Java訂閱,新增加了之后數據庫就會顯示一條數據:id=uuid,dtopic=java,data=null

這里要和MqttConfig中,選擇訂閱的主題一樣

在這里插入圖片描述

注意:代碼寫的位置
package com.ruoyi.common.utils.mqtt;@Component
public class PushCallback implements MqttCallback {private static final Logger logger = LoggerFactory.getLogger(MqttPushClient.class);@Autowiredprivate MqttConfig mqttConfig;private static MqttClient client;private static String _topic;private static String _qos;private static String _msg;@Overridepublic void connectionLost(Throwable throwable) {// 連接丟失后,一般在這里面進行重連logger.info("連接斷開,可以做重連");if (client == null || !client.isConnected()) {mqttConfig.getMqttPushClient();}}@Overridepublic void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {// subscribe后得到的消息會執行到這里面logger.info("接收消息主題 : " + topic);logger.info("接收消息Qos : " + mqttMessage.getQos());logger.info("接收消息內容 : " + new String(mqttMessage.getPayload()));//todo 代碼一般寫在這里......}@Overridepublic void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {logger.info("deliveryComplete---------" + iMqttDeliveryToken.isComplete());}}

注意:在MqttConfig中,選擇訂閱的主題

	@Beanpublic MqttPushClient getMqttPushClient() {if (enabled == true) {mqttPushClient.connect(hostUrl, clientId, username, password, timeout, keepalive);//訂閱java主題   mqttPushClient.subscribe("java",0);}return mqttPushClient;}

5.接收數據

編寫代碼,硬件傳來的數據更新保存在數據庫中

先獲取topic=Java的數據,然后可存不存在,存在就j更新,將硬件傳過來的數據更新到data中

package com.ruoyi.common.utils.mqtt;@Component
public class PushCallback implements MqttCallback {private static final Logger logger = LoggerFactory.getLogger(MqttPushClient.class);@Autowiredprivate MqttConfig mqttConfig;@Autowiredprivate IWService wService;private static MqttClient client;private static String _topic;private static String _qos;private static String _msg;@Overridepublic void connectionLost(Throwable throwable) {// 連接丟失后,一般在這里面進行重連logger.info("連接斷開,可以做重連");if (client == null || !client.isConnected()) {mqttConfig.getMqttPushClient();}}@Overridepublic void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {// subscribe后得到的消息會執行到這里面logger.info("接收消息主題 : " + topic);logger.info("接收消息Qos : " + mqttMessage.getQos());logger.info("接收消息內容 : " + new String(mqttMessage.getPayload()));//硬件傳來的數據update在數據庫中
//        @Log(title = "物聯網接收數據", businessType = BusinessType.UPDATE)
//        @PostMapping("/edit")
//        @ResponseBody
//        public AjaxResult editSave (W w){
//            return toAjax(wService.updateW(w));
//        }//查詢更新操作,查詢topic=Java的數據,如果有,就把數據更新到數據庫中(data)W w = new W();w.setTopic("java");//查詢List<W> list = wService.selectWList(w);if (list.size() > 0) {//根據id去查詢w.setId(list.get(0).getId());w.setTopic(null);w.setData(new String(mqttMessage.getPayload()));try {wService.updateW(w);//alt+ctrl+t:拋異常} catch (Exception e) {throw new RuntimeException(e);}}}@Overridepublic void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {logger.info("deliveryComplete---------" + iMqttDeliveryToken.isComplete());}}

運行系統,此時數據庫的data為空(新增加一個Java訂閱的數據)

在這里插入圖片描述

使用mqttx,模擬硬件發Java發消息

在這里插入圖片描述

發送111

在這里插入圖片描述

在這里插入圖片描述

5.1 前端顯示接收的數據

wlw包的w.html編寫前端,編寫一個定時器localhost/ruoyi/system/wlw

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>wlw</title><script th:src="@{/js/jquery.min.js}"></script><script th:inline="javascript">var ctx = [[@{/}]];//定時器,每五秒定時接收數據setInterval(function(){$.ajax({type: "post",url: ctx + "system/w/list",dataType: "json",success: function (result) {console.log(result);}})}, 1000);</script>
</head>
<body><button></button> 
</body>
</html>

shiroConfig,放開攔截

// 不需要攔截的訪問  接收
filterChainDefinitionMap.put("/system/w/list", "anon,captchaValidate");

控制臺接收數據

在這里插入圖片描述

把查詢的數據顯示到界面上

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>wlw</title><script th:src="@{/js/jquery.min.js}"></script><script th:inline="javascript">var ctx = [[@{/}]];//定時器,每五秒定時接收數據setInterval(function () {$.ajax({type: "post",url: ctx + "system/w/list",data: {//根據topic為Java的查topic: "java",},dataType: "json",success: function (result) {if (result.total > 0) {//顯示數據$("div").text(result.rows[0].data);}}})}, 1000);</script>
</head>
<body>
<button></button>
<div></div>
</body>
</html>

使用mqttx模擬硬件發送數據,Java程序接收并顯示在界面上

在這里插入圖片描述

6.發送消息

修改主題(三個地方)

PushCallback,修改為test

       W w = new W();w.setTopic("test");  //test//查詢List<W> list = wService.selectWList(w);if (list.size() > 0) {//根據id去查詢w.setId(list.get(0).getId());w.setTopic(null);w.setData(new String(mqttMessage.getPayload()));try {wService.updateW(w);//alt+ctrl+t:拋異常} catch (Exception e) {throw new RuntimeException(e);}}

MqttConfig

    @Beanpublic MqttPushClient getMqttPushClient() {if (enabled == true) {mqttPushClient.connect(hostUrl, clientId, username, password, timeout, keepalive);//訂閱java主題mqttPushClient.subscribe("test",0);}
//        if(enabled == true){
//            String mqtt_topic[] = StringUtils.split(defaultTopic, ",");
//            mqttPushClient.connect(hostUrl, clientId, username, password, timeout, keepalive);//連接
//            for(int i=0; i<mqtt_topic.length; i++){
//                mqttPushClient.subscribe(mqtt_topic[i], 0);//訂閱主題
//            }
//        }return mqttPushClient;}
}

數據庫中的topic修改為test

前端代碼

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>wlw</title><script th:src="@{/js/jquery.min.js}"></script><script th:inline="javascript">var ctx = [[@{/}]];$(function () {$("button").click(function () {$.ajax({type: "post",url: ctx + "system/wlw/open",//添加這里的代碼data: {//向java主題發送open數據topic: "java",msg: "open"},dataType: "json",success: function (result) {console.log(result);}// data: {//     topic: "java1",//     msg: "open"// },// dataType: "json",// success: function(result) {//     console.log(result);// }})})})</script>
</head>
<body>
<button></button>
<div></div>
</body>
</html>

運行項目,點擊開按鈕,查看mqttx是否接收到了數據

注意:發送的訂閱主題不能和接收的主題一樣,所以前面我們要修改主題為test

在這里插入圖片描述

7.iot-mqtt

半成品項目https://gitee.com/peng-chuanbin/iot-mqtt.git

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/92145.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/92145.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/92145.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PyTorch + PaddlePaddle 語音識別

PyTorch PaddlePaddle 語音識別 目錄 概述環境配置基礎理論數據預處理模型架構設計完整實現案例模型訓練與評估推理與部署性能優化技巧總結 語音識別&#xff08;ASR, Automatic Speech Recognition&#xff09;是將音頻信號轉換為文本的技術。結合PyTorch和PaddlePaddle的…

施耐德 Easy Altivar ATV310 變頻器:高效電機控制的理想選擇(含快速調試步驟及常見故障代碼)

施耐德 Easy Altivar ATV310 變頻器&#xff1a;高效電機控制的理想選擇&#xff08;含快速調試步驟&#xff09;在工業自動化領域&#xff0c;變頻器作為電機控制的核心設備&#xff0c;其性能與可靠性直接影響整個生產系統的效率。施耐德電氣推出的 Easy Altivar ATV310 變頻…

搭建郵件服務器概述

一、電子郵件應用解析標準郵件服務器&#xff08;qq郵箱&#xff09;&#xff1a;1&#xff09;提供電子郵箱&#xff08;lvbuqq.com&#xff09;及存儲空間2&#xff09;為客戶端向外發送郵件給其他郵箱&#xff08;diaochan163.com&#xff09;3&#xff09;接收/投遞其他郵箱…

day28-NFS

1.每日復盤與今日內容1.1復盤Rsync:本地模式、遠程模式&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;、遠程守護模式&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;安裝、配置Rsync啟動、測試服務備份案例1.2今日內容NFS優缺點NFS服…

二叉搜索樹--通往高階數據結構的基石

目錄 前言&#xff1a; 1、二叉搜索樹的概念 2、二叉搜索樹性能分析 3、二叉搜索樹的實現 BinarySelectTree.h test.cpp 4、key 和 key / value&#xff08; map 和 set 的鋪墊 &#xff09; 前言&#xff1a; 又回到數據結構了&#xff0c;這次我們將要學習一些復雜的…

Profinet轉Ethernet IP網關接入五軸車床上下料機械手控制系統的配置實例

本案例為西門子1200PLC借助PROFINET轉EtherNet/IP網關與搬運機器人進行連接的配置案例。所需設備包括&#xff1a;西門子1200PLC、Profinet轉EtherNet/IP網關以及發那科&#xff08;Fanuc&#xff09;機器人。開啟在工業自動化控制領域廣泛應用、功能強大且專業的西門子博圖配置…

專題二_滑動窗口_長度最小的子數組

引入&#xff1a;滑動窗口首先&#xff0c;這是滑動窗口的第一道題&#xff0c;所以簡短的說一下滑動窗口的思路&#xff1a;當我們題目要求找一個滿足要求的區間的時候&#xff0c;且這個區間的left和right指針&#xff0c;都只需要同向移動的時候&#xff0c;就可以使用滑動窗…

解鎖高效開發:AWS 前端 Web 與移動應用解決方案詳解

告別繁雜的部署與運維&#xff0c;AWS 讓前端開發者的精力真正聚焦于創造卓越用戶體驗。在當今快速迭代的數字環境中&#xff0c;Web 與移動應用已成為企業與用戶交互的核心。然而&#xff0c;前端開發者常常面臨諸多挑戰&#xff1a;用戶認證的復雜性、后端 API 的集成難題、跨…

北京JAVA基礎面試30天打卡04

1. 單例模式的實現方式及線程安全 單例模式&#xff08;Singleton Pattern&#xff09;確保一個類只有一個實例&#xff0c;并提供一個全局訪問點。以下是常見的單例模式實現方式&#xff0c;以及如何保證線程安全&#xff1a; 單例模式的實現方式餓漢式&#xff08;Eager Init…

Redis 緩存三大核心問題:穿透、擊穿與雪崩的深度解析

引言在現代互聯網架構中&#xff0c;緩存是提升系統性能、降低數據庫壓力的核心手段之一。而 Redis 作為高性能的內存數據庫&#xff0c;憑借其豐富的數據結構、靈活的配置選項以及高效的網絡模型&#xff0c;已經成為緩存領域的首選工具。本文將從 Redis 的基本原理出發&#…

耘瞳科技國產化點云處理軟件,開啟智能化三維測量新時代

在現代工業制造領域&#xff0c;三維點云數據已成為推動生產效率提升、質量控制優化以及智能制造轉型的關鍵技術之一。三維點云數據能夠提供高精度的物體表面信息&#xff0c;廣泛應用于制造零件的質量檢測&#xff1b;通過點云數據與CAD模型的對比分析&#xff0c;可以快速檢測…

RabbitMQ面試精講 Day 8:死信隊列與延遲隊列實現

【RabbitMQ面試精講 Day 8】死信隊列與延遲隊列實現 文章標簽 RabbitMQ,消息隊列,死信隊列,延遲隊列,面試技巧,分布式系統 文章簡述 本文是"RabbitMQ面試精講"系列第8天&#xff0c;深入講解死信隊列與延遲隊列的實現原理與實戰應用。文章詳細解析死信隊列的觸發…

團結引擎 1.5.0 版本發布:Android App View 功能詳解

核心亮點 原生安卓應用支持 2D & 3D 雙形態呈現 編輯器全流程集成 靈活調控功能 多應用并行展示 智能座艙應用示例 快速入門指南 開發說明 功能支持 實驗性功能 資源鏈接 團結引擎 1.5.0 版本已于 4 月 14 日正式上線。本次更新中&#xff0c;車機版引入了一項突…

基于SpringBoot的OA辦公系統的設計與實現

文章目錄前言詳細視頻演示具體實現截圖后端框架SpringBoot持久層框架MyBaits成功系統案例&#xff1a;代碼參考數據庫源碼獲取前言 博主介紹:CSDN特邀作者、985高校計算機專業畢業、現任某互聯網大廠高級全棧開發工程師、Gitee/掘金/華為云/阿里云/GitHub等平臺持續輸出高質量…

知識隨記-----用 Qt 打造優雅的密碼輸入框:添加右側眼睛圖標切換顯示

Qt 技巧&#xff1a;通過 QLineEdit 右側眼睛圖標實現密碼可見性切換 文章目錄Qt 技巧&#xff1a;通過 QLineEdit 右側眼睛圖標實現密碼可見性切換概要整體架構流程技術名詞解釋技術細節實現效果展示概要 本文介紹如何使用 Qt 框架為 QLineEdit 控件添加一個右側的眼睛圖標&a…

Unity里的對象旋轉數值跳轉問題的原理與解決方案

文章目錄1. 問題描述2. 問題原因3. 解決方案3.1通過多個父子關系從而控制旋轉&#xff08;推薦&#xff09;3.2 使用四元數進行旋轉1. 問題描述 我們現在寫一個3D的Unity程序&#xff0c;我們現在設置了一個物體后&#xff0c;我們想旋轉使其改為我們想要的情況。但是我們如果…

為什么現代 C++ (C++11 及以后) 推薦使用 constexpr和模板 (Templates) 作為宏 (#define) 的替代品??

我們用現實世界的比喻來深入理解??為什么 C 中的宏 (#define) 要謹慎使用&#xff0c;以及為什么現代 C (C11 及以后) 推薦使用 constexpr 和模板 (Templates) 作為替代品。??&#x1f9e9; ??核心問題&#xff1a;宏 (#define) 是文本替換??想象宏是一個 ??“無腦的…

PyCharm vs. VSCode 到底哪個更好用

在 Python 開發者中&#xff0c;關于 PyCharm 和 VSCode 的討論從未停止。一個是功能齊備的集成開發環境&#xff08;IDE&#xff09;&#xff0c;另一個是輕快靈活的代碼編輯器。它們代表了兩種不同的開發哲學&#xff0c;選擇哪個&#xff0c;往往取決于你的項目需求、個人習…

FPGA學習筆記——VGA彩條顯示

目錄 一、任務 二、分析 三、代碼 四、實驗現象 五、更新 一、任務 使用VGA實現彩條顯示&#xff0c;模式是640x48060。 二、分析 首先&#xff0c;模式是640x48060&#xff0c;那么對照以下圖標&#xff0c;知道其它信息&#xff0c;不清楚時序和VGA掃描方式的可以看看這…

ES-301A :讓 Modbus 設備無縫接入工業以太網的高效橋梁

在工業自動化領域&#xff0c;串口設備與以太網的互聯互通是提升系統效率的關鍵。ES-301A 工業以太網串口網關作為上海泗博自動化精心打造的專業解決方案&#xff0c;以強大的協議轉換能力、工業級可靠性和靈活配置特性&#xff0c;成為連接 Modbus RTU/ASCII 設備與 Modbus TC…