MQTT从入门到精通之 MQTT 客户端编程
MQTT 客户端编程
1 在VUE中使用MQTT
具体步骤如下所示:
1、初始化vue项目
// 创建一个使用vite构建的前端项目
npm create vite@latest// 进入到项目中,执行如下命令安装项目依赖
npm install
2、安装element plus
// 安装element plus
npm install element-plus --save// 安装mqtt.js依赖
npm install mqtt --save// 在main.js中添加如下代码
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
3、导入课程资料中的MqttDemo.vue页面到components文件夹下
4、更改App.vue页面代码如下所示
<script setup>
import MqttDemo from "./components/MqttDemo.vue";
</script><template><MqttDemo/>
</template><style>
</style>
5、建立和关闭连接
<script setup>
import mqtt from "mqtt";// 定义链接信息对象
const connectionInfo = ref({protocol: 'ws',host: "192.168.136.147",port: 8083,clientId: "emqx_vue3_" + Math.random().toString(16).substring(2, 8),username: "zhangsan",password: "123",clean: true,connectTimeout: 10 * 1000, // msreconnectPeriod: 4000, // ms
})// 创建链接对象
const client = ref({})
const clientInitData = ref({ // 链接初始化相关数据connnected: false
})// 建立连接事件处理函数
const createConnection = () => {const { protocol, host, port , ...options } = connectionInfo.value;const connectUrl = `${protocol}://${host}:${port}/mqtt`;console.log(connectUrl)client.value = mqtt.connect(connectUrl , options); // 建立连接clientInitData.value.connnected = true ;console.info("createConnection successful...")}// 端口链接事件处理函数
const closeConnection = () => {// 关闭链接client.value.end(false , () => { // 如果设置为true,将会立即关闭套接字,并且不发送MQTT DISCONNECT包。如果设置为false(默认值),则会发送MQTT DISCONNECT包给代理,然后关闭套接字。clientInitData.value.connnected = false;console.info("closeConnection successful...")})}
</script><template><div class="mqtt-demo"><el-card><h1>配置信息</h1><el-form label-position="top" ><el-row :gutter="20"><el-col :span="8"><el-form-item prop="protocol" label="选择协议"><el-select v-model="connectionInfo.protocol"><el-option label="ws://" value="ws"></el-option><el-option label="wss://" value="wss"></el-option></el-select></el-form-item></el-col><el-col :span="8"><el-form-item prop="host" label="主机地址"><el-input v-model="connectionInfo.host" ></el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="port" label="端口号"><el-input type="number" v-model="connectionInfo.port" placeholder="8083/8084"></el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="clientId" label="客户端ID"><el-input v-model="connectionInfo.clientId"> </el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="username" label="用户名"><el-input v-model="connectionInfo.username"></el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="password" label="密码"><el-input v-model="connectionInfo.password"></el-input></el-form-item></el-col><el-col :span="24"><el-button type="primary" :disabled="clientInitData.connnected" @click="createConnection">建立连接</el-button><el-button type="danger" :disabled="!clientInitData.connnected" @click="closeConnection">断开连接</el-button></el-col></el-row></el-form></el-card></div>
</template>
6、订阅和取消订阅
<script setup>// 消息质量取值数组
const qosList = [0, 1, 2];
const receivedMessages = ref(null)
const subscriptionInfo = ref({ // 订阅参数数据模型topic: '' ,qos: 0
})
const subscriptionInitData = ref({ // 订阅初始化数据subscription: false
})// 定义定义主题的事件处理函数
const subscriptionTopicHandler = () => {const { topic, qos } = subscriptionInfo.valueconsole.info(qos)client.value.subscribe(topic, { qos } , (error , res) => {if(error) {console.info("subscriptionTopic Error:", error);return ;}subscriptionInitData.value.subscription = true ;console.info("subscriptionTopic successful.... ");// 订阅成功以后,监听发送消息事件client.value.on('message' , (topic , message) => {console.info("topic -----> " + topic + ", message -----> " + message)receivedMessages.value = "topic -----> " + topic + ", message -----> " + message ;})})}// 定义取消订阅的事件处理函数
const unSubscriptionTopicHandler = () => {const {topic, qos } = subscriptionInfo.valueclient.value.unsubscribe(topic, { qos } , (error , res) => {if(error) {console.info("unSubscriptionTopic Error:", error);return ;}subscriptionInitData.value.subscription = false ;console.info("unSubscriptionTopic successful.... ");})
}</script><template><el-card><h1>订阅主题</h1><el-form label-position="top" ><el-row :gutter="20"><el-col :span="8"><el-form-item prop="topic" label="Topic"><el-input v-model="subscriptionInfo.topic"></el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="qos" label="QoS"><el-select v-model="subscriptionInfo.qos"><el-optionv-for="qos in qosList":key="qos":label="qos":value="qos"></el-option></el-select></el-form-item></el-col><el-col :span="8"><el-button type="primary" class="sub-btn" :disabled="subscriptionInitData.subscription" @click="subscriptionTopicHandler">订阅主题</el-button><el-button type="primary" class="sub-btn" :disabled="!subscriptionInitData.subscription" @click="unSubscriptionTopicHandler">取消订阅</el-button></el-col></el-row></el-form></el-card></template>
7、发布消息
<script setup>// 发布消息参数
const publishInfo = ref({topic: '' ,qos: 0,payLoad: ''
})// 定义发布消息的事件处理函数
const doPublish = () => {const {topic , payLoad , qos } = publishInfo.value ;client.value.publish(topic , payLoad , { qos } , (error , res) => {if(error) {console.info("publish msg info error...." , error)return ;}console.info("publish msg info successful....")}) ;}</script>
<template><el-card><h1>发布消息</h1><el-form label-position="top" ><el-row :gutter="20"><el-col :span="8"><el-form-item prop="topic" label="Topic"><el-input v-model="publishInfo.topic"></el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="payload" label="Payload"><el-input v-model="publishInfo.payLoad"></el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="qos" label="QoS"><el-select v-model="publishInfo.qos"><el-optionv-for="qos in qosList":key="qos":label="qos":value="qos"></el-option></el-select></el-form-item></el-col></el-row></el-form><el-col :span="24" class="text-right"><el-button type="primary" @click="doPublish">发布消息</el-button></el-col></el-card></template>
2 在Java中使用MQTT
2.1 Eclipse Paho Java Client
具体步骤:
1、创建一个Spring Boot项目,添加如下依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.0.5</version>
</parent><dependencies><!-- spring boot整合junit单元测试的起步依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!-- mqtt java客户端依赖 --><dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.client.mqttv3</artifactId><version>1.2.5</version></dependency></dependencies>
2、建立连接代码实现
@Test
public void createConnection() throws MqttException {// 定义链接相关参数String broker = "tcp://192.168.136.147:1883";String username = "zhangsan";String password = "123";String clientid = "mqtt_java_client_01";// 创建MqttJava客户端对象// MqttClientPersistence: 代表一个持久的数据存储,用于在传输过程中存储出站和入站的信息MqttClient client = new MqttClient(broker, clientid , new MemoryPersistence()); MqttConnectOptions options = new MqttConnectOptions();options.setUserName(username);options.setPassword(password.toCharArray());client.connect(options);// 阻塞当前线程while (true) ;
}
3、发布消息代码演示
@Test
public void sendMessage() throws MqttException {// 定义链接相关参数String broker = "tcp://192.168.136.147:1883";String username = "zhangsan";String password = "123";String clientid = "mqtt_java_client_01";// 创建MqttJava客户端对象MqttClient client = new MqttClient(broker, clientid , new MemoryPersistence());MqttConnectOptions options = new MqttConnectOptions();options.setUserName(username);options.setPassword(password.toCharArray());client.connect(options);// 创建消息对象QoSString content = "hello mqtt";MqttMessage message = new MqttMessage(content.getBytes());message.setQos(2);message.setRetained(true);// 发送消息client.publish("a/c" , message);// 关闭链接释放资源client.disconnect();client.close();}
4、订阅主题获取消息
@Test
public void receiveMessage() throws MqttException {// 定义链接相关参数String broker = "tcp://192.168.136.147:1883";String username = "zhangsan";String password = "123";String clientid = "mqtt_java_client_02";// 创建MqttJava客户端对象MqttClient client = new MqttClient(broker, clientid , new MemoryPersistence());MqttConnectOptions options = new MqttConnectOptions();options.setUserName(username);options.setPassword(password.toCharArray());// 添加回调函数获取主题消息client.setCallback(new MqttCallback() {@Overridepublic void connectionLost(Throwable cause) { // 连接丢失时被调用System.out.println("connectionLost: " + cause.getMessage());}@Overridepublic void messageArrived(String topic, MqttMessage message) throws Exception { // 接收到消息时被调用System.out.println("topic: " + topic);System.out.println("Qos: " + message.getQos());System.out.println("message content: " + new String(message.getPayload()));}@Overridepublic void deliveryComplete(IMqttDeliveryToken token) { // 消息接收完成时被调用System.out.println("deliveryComplete---------" + token.isComplete());}});// 订阅主题client.connect(options);client.subscribe("a/d" , 2);while(true) ;}
2.2 spring-integration-mqtt
2.2.1 基础环境搭建
1、创建一个Spring Boot项目,并加入如下依赖:
<dependencies><!-- spring boot项目web开发的起步依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- spring boot项目集成消息中间件基础依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration</artifactId></dependency><!-- spring boot项目和mqtt客户端集成起步依赖 --><dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-mqtt</artifactId><version>5.4.3</version></dependency><!-- lombok依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- fastjson依赖 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency></dependencies>
2、编写启动类
@EnableConfigurationProperties(value = MqttConfigurationProperties.class)
@SpringBootApplication
public class MqttDemoApplication {public static void main(String[] args) {SpringApplication.run(MqttDemoApplication.class , args) ;}}
3、在application.yml文件中添加如下配置
spring:mqtt:username: zhangsanpassword: 123url: tcp://192.168.136.147:1883subClientId: sub_client_id_123subTopic: liujh/iot/lamp/linepubClientId: pub_client_id_123
4、创建实体类读取自定义配置
@Data
@ConfigurationProperties(prefix = "spring.mqtt")
public class MqttConfigurationProperties {private String username;private String password;private String url;private String subClientId ;private String subTopic ;private String pubClientId ;}
5、创建配置类配置链接工厂
@Configuration
public class MqttConfiguration {@Autowiredprivate MqttConfigurationProperties mqttConfigurationProperties ;@Beanpublic MqttPahoClientFactory mqttClientFactory(){// 创建客户端工厂DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();// 创建MqttConnectOptions对象MqttConnectOptions options = new MqttConnectOptions();options.setCleanSession(true);options.setUserName(mqttConfigurationProperties.getUsername());options.setPassword(mqttConfigurationProperties.getPassword().toCharArray());options.setServerURIs(new String[]{mqttConfigurationProperties.getUrl()});factory.setConnectionOptions(options);// 返回return factory;}}
2.2.2 订阅主题获取消息
具体步骤:
1、配置入站适配器
@Configuration
public class MqttInboundConfiguration {@Autowiredprivate MqttConfigurationProperties mqttConfigurationProperties ;@Autowiredprivate ReceiverMessageHandler receiverMessageHandler;/*** 配置消息传输通道* @return*/@Beanpublic MessageChannel mqttInputChannel() {return new DirectChannel();}/*** 配置入站适配器*/@Beanpublic MessageProducer messageProducer(MqttPahoClientFactory mqttPahoClientFactory) {MqttPahoMessageDrivenChannelAdapter adapter =new MqttPahoMessageDrivenChannelAdapter(mqttConfigurationProperties.getUrl() ,mqttConfigurationProperties.getSubClientId() ,mqttPahoClientFactory , mqttConfigurationProperties.getSubTopic().split(",")) ;adapter.setConverter(new DefaultPahoMessageConverter());adapter.setQos(1);adapter.setOutputChannel(mqttInputChannel());return adapter ;}/*** 配置入站消息处理器* @return*/@Bean@ServiceActivator(inputChannel = "mqttInputChannel")public MessageHandler messageHandler() {return this.receiverMessageHandler ;}}
2、定义监听主题消息的处理器
@Component
public class ReceiverMessageHandler implements MessageHandler {@Overridepublic void handleMessage(Message<?> message) throws MessagingException {MessageHeaders headers = message.getHeaders();String receivedTopicName = (String) headers.get("mqtt_receivedTopic");if("liujh/iot/lamp/line".equals(receivedTopicName)) {System.out.println("接收到消息:" + message.getPayload());}}}
测试:通过MQTTX向liujh/iot/lamp/line主题发送消息
2.2.3 向指定主题发送消息
具体步骤:
1、配置出站消息处理器
@Configuration
public class MqttOutboundConfiguration {@Autowiredprivate MqttConfigurationProperties mqttConfigurationProperties ;@Autowiredprivate MqttPahoClientFactory pahoClientFactory ;@Beanpublic MessageChannel mqttOutputChannel() {return new DirectChannel();}@Bean@ServiceActivator(inputChannel = "mqttOutputChannel")public MessageHandler mqttOutboundMassageHandler() {MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(mqttConfigurationProperties.getUrl() ,mqttConfigurationProperties.getPubClientId() , pahoClientFactory ) ;messageHandler.setAsync(true);messageHandler.setDefaultQos(0);messageHandler.setDefaultTopic("default");return messageHandler ;}}
2、定义发送消息的网关接口
@MessagingGateway(defaultRequestChannel = "mqttOutputChannel")
public interface MqttGateway {/*** 发送mqtt消息* @param topic 主题* @param payload 内容*/void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);/*** 发送包含qos的消息* @param topic 主题* @param qos 对消息处理的几种机制。* * 0 表示的是订阅者没收到消息不会再次发送,消息会丢失。<br>* * 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息。<br>* * 2 多了一次去重的动作,确保订阅者收到的消息有一次。* @param payload 消息体*/void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);}
3、定义发送消息的服务类
@Component
@AllArgsConstructor
public class MqttMessageSender {private MqttGateway mqttGateway;/*** 发送mqtt消息* @param topic 主题* @param message 内容*/public void send(String topic, String message) {mqttGateway.sendToMqtt(topic, message);}/*** 发送包含qos的消息* @param topic 主题* @param qos 质量* @param message 消息体*/public void send(String topic, int qos, byte[] message){mqttGateway.sendToMqtt(topic, qos, message);}
}
3 智能灯泡案例
需求:
1、智能灯泡设备上线以后向MQTT服务端发送消息,后端服务从MQTT中获取消息记录设备信息到数据库中
2、后端微服务向MQTT服务端发送开灯或者关灯消息,设备端从MQTT中获取消息控制灯泡的开和关
3、设备端对灯泡进行开和关操作的时候向MQTT中发送消息,后端服务获取MQTT消息记录灯泡的开关状态
3.1 服务端获取设备上线消息
3.1.1 环境准备
具体步骤:
1、创建对应的数据库表
-- 智能灯泡设备表
CREATE TABLE `tb_lamp` (`id` bigint NOT NULL AUTO_INCREMENT,`deviceId` varchar(50) DEFAULT NULL,`status` int DEFAULT NULL COMMENT '1:上线 0:下线',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ,`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;-- 智能灯泡设备状态表
CREATE TABLE `tb_lamp_status` (`id` int NOT NULL AUTO_INCREMENT,`deviceId` varchar(50) DEFAULT NULL,`status` int DEFAULT NULL COMMENT '0: 关灯 1:开灯',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2、在spring-integration-mqtt案例中加入如下依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.32</version>
</dependency>
3、在application.yml文件中加入如下依赖
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.136.147:3306/lamp_test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 1234mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: truemapper-locations: classpath*:mapper/*Mapper.xml
4、通过mybatis的逆向工程生成tb_lamp和tb_lamp_status表对应的基础代码
5、在启动类上添加@MapperScan注解指定Mapper接口的包路径
3.1.2 接口说明
接口一:设备上线
当终端设备连接上EMQX以后,发送上线消息到EMQX服务端,说明如下:
主题: liujh/iot/lamp/line
消息内容:{"deviceId": "xxxxxx","online": 1}
数据说明:deviceId: 设备idonline: 上线状态,1表示上线,0表示离线
3.1.3 业务代码
对ReceiverMessageHandler类的代码进行如下改造:
@Component
public class ReceiverMessageHandler implements MessageHandler {@Autowiredprivate TbLampService tbLampService ;@Overridepublic void handleMessage(Message<?> message) throws MessagingException {MessageHeaders headers = message.getHeaders();String receivedTopicName = (String) headers.get("mqtt_receivedTopic");if("liujh/iot/lamp/line".equals(receivedTopicName)) {tbLampService.updateLampOnlineStatus(message.getPayload().toString()) ; // 更新智能灯泡的上线状态}}}
对TbLampServiceImpl类的代码进行如下改造:
@Service
public class TbLampServiceImpl extends ServiceImpl<TbLampMapper, TbLamp> implements TbLampService {@Overridepublic void updateLampOnlineStatus(String jsonInfo) {// 解析消息获取设备id和上线状态Map<String , Object> map = JSON.parseObject(jsonInfo, Map.class);String deviceId = map.get("deviceId").toString();Integer status = Integer.parseInt(map.get("online").toString());// 根据设备的id查询设备数据LambdaQueryWrapper<TbLamp> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;lambdaQueryWrapper.eq(TbLamp::getDeviceid , deviceId) ;TbLamp tbLamp = this.getOne(lambdaQueryWrapper);if(tbLamp == null) { // 设备不存在,新增设备tbLamp = new TbLamp() ;tbLamp.setDeviceid(deviceId);tbLamp.setStatus(status);this.save(tbLamp) ;}else { // 设备已经存在,修改设备的状态tbLamp.setStatus(status);tbLamp.setUpdateTime(new Date());this.updateById(tbLamp) ;}}}
3.2 服务端发送关灯开灯消息到MQTT
3.2.1 接口说明
接口三:后端发送消息控制智能灯泡开关
后端可以发送控制灯泡状态消息到EMQX中,设备端监听指定主题获取消息,控制灯泡的开关状态,说明如下:
主题: liujh/iot/lamp/server/status
消息内容:{"deviceId": "xxxxxx","status": 0}
数据说明: status: 0:关灯 , 1:开灯
3.2.2 业务代码
在spring-integration-mqtt案例中添加如下controller接口方法
@RestController
@RequestMapping(value = "/api/lamp")
public class LampApiController {@Autowiredprivate MqttMessageSender mqttMessageSender;@GetMapping(value = "/{deviceId}/{status}")public String sendStatusLampMsg(@PathVariable(value = "deviceId") String deviceId , @PathVariable(value = "status") Integer status) {Map<String , Object> map = new HashMap<>() ;map.put("deviceId" , deviceId) ;map.put("status" , status) ;String json = JSON.toJSONString(map);mqttMessageSender.send("liujh/iot/lamp/server/status" , json);return "ok" ;}}
3.3 服务端获取设备开灯关灯消息
3.3.1 接口说明
接口四:设备端改变智能灯泡开关的状态,状态发给给后端,后端记录状态
主题:liujh/iot/lamp/device/status
消息内容:{"deviceId": "xxxxx" "status": 0}
数据说明: deviceId:设备idstatus:0:关灯 , 1:开灯
3.3.2 业务代码
对ReceiverMessageHandler类的代码进行如下改造:
// com.liujh.mqtt.receiver.ReceiverMessageHandler
@Override
public void handleMessage(Message<?> message) throws MessagingException {MessageHeaders headers = message.getHeaders();String receivedTopicName = (String) headers.get("mqtt_receivedTopic");if("liujh/iot/lamp/line".equals(receivedTopicName)) {tbLampService.updateLampOnlineStatus(message.getPayload().toString()) ; // 更新智能灯泡的上线状态}else if("liujh/iot/lamp/device/status".equals(receivedTopicName)) {tbLampStatusService.saveDeviceStatus(message.getPayload().toString()) ;}
}
对TbLampStatusServiceImpl类的代码进行如下改造:
@Service
public class TbLampStatusServiceImpl extends ServiceImpl<TbLampStatusMapper, TbLampStatus> implements TbLampStatusService {@Overridepublic void saveDeviceStatus(String json) {// 获取消息内容Map<String , Object> map = JSON.parseObject(json, Map.class);String deviceId = map.get("deviceId").toString();Integer status = Integer.parseInt(map.get("status").toString());// 创建对象封装消息TbLampStatus tbLampStatus = new TbLampStatus() ;tbLampStatus.setDeviceid(deviceId);tbLampStatus.setStatus(status);this.save(tbLampStatus) ;}}
相关文章:
MQTT从入门到精通之 MQTT 客户端编程
MQTT 客户端编程 1 在VUE中使用MQTT 具体步骤如下所示: 1、初始化vue项目 // 创建一个使用vite构建的前端项目 npm create vitelatest// 进入到项目中,执行如下命令安装项目依赖 npm install 2、安装element plus // 安装element plus npm install …...
数据结构-集合
一.集合的表示 一个重要的操作是查某个元素属于哪个集合,另一个操作是合并操作 从这个树的节点去找树根也就是从下往上找,要把树并起来只需把两个根并在一起就可以了 不存在已知一个节点去找孩子节点,根重要的是已知一个节点找它的父亲节点,与之前的二…...
前端 JS面向对象 原型 prototype
目录 一、问题引出 二、prototype原型对象 三、小结 四、constructor 五、__proto__对象原型 六、原型链 一、问题引出 由于JS的构造函数存在内存浪费问题: function Star(name,age){this.namenamethis.ageagethis.singfunction () {console.log("唱歌&…...
Java中的不可变集合:性能与安全并重的最佳实践
Java中的不可变集合:性能与安全并重的最佳实践 在现代软件开发中,集合类(如List、Set和Map)是Java开发者的日常工具。它们用于存储和操作数据,能极大地简化开发工作。但随着并发编程和大规模应用的广泛使用࿰…...
RandomWords随机生成单词
from random_words import RandomWords rw RandomWords() r rw.random_word() print(r) 更多How to use — random_words documentation (randomwords.readthedocs.io) li LoremIpsum()# 这行代码创建了一个 LoremIpsum 类的实例。li.get_sentence()# 这个方法返回一个随机…...
从零开始使用Intel的AIPC使用xpu加速comfyui
Intel的AIPC使用xpu加速跑comfyui 环境安装python环境搭建驱动及oneAPI安装创建python环境验证环境是否生效 ComfyUI的安装下载、汉化comfyui下载checkpoint 测试使用xpu加速测试使用cpu执行测试 环境安装 python环境搭建 直接下载Anaconda 下载地址 安装好后,通…...
PyQt入门指南五十二 版本控制与协作开发
在开发PyQt应用程序时,版本控制和协作开发是提高开发效率和项目可维护性的重要手段。本指南将介绍如何使用Git进行版本控制,以及如何使用GitHub进行协作开发。 版本控制基础 Git简介:Git是一种分布式版本控制系统,用于跟踪代码变…...
思考:linux Vi Vim 编辑器的简明原理,与快速用法之《 7 字真言 》@ “鱼爱返 说 温泉啊“ (**)
Linux vi/vim | 菜鸟教程 https://zhuanlan.zhihu.com/p/602675406 Linux Vim编辑器的基本使用_vim文本编辑器-CSDN博客 这里提出使用 vi / vim 进行简单的编辑操作的原因,主要是在容器镜像中,普遍都是使用这个。 在 linux 服务器应用场景&#x…...
共筑开源技术新篇章 | 2024 CCF中国开源大会盛大开幕
在这个技术革新日新月异的时代,开源精神如同点燃创新火焰的火种,照亮了无数技术探索者的征途。2024年11月9日,备受瞩目的2024 CCF中国开源大会在深圳这座充满活力的创新之城盛大开幕。这场开源领域的顶级盛事,以“湾区聚力 开源启…...
SpringBoot(十八)SpringBoot集成Minio
项目上传文件集成一下Minio,下面是我在项目中集成Minio的全过程。 首先介绍一下Minio:MinIO是高性能的对象存储,单个对象最大可达5TB。适合存储图片、视频、文档、备份数据、安装包等一系列文件。是一款主要采用Golang语言实现发开的高性能、分布式的对象存储系统。客户端支…...
ODOO学习笔记(3):Odoo和Django的区别是什么?
Odoo和Django都是基于Python的开源框架,但它们的设计目标和用途有所不同: 设计目标和用途: Odoo:Odoo是一个企业资源规划(ERP)系统,它提供了一套完整的商业管理软件,包括会计、库存…...
持续收集解决VCcode各种报错的方法
在学习中我们经常会发生各种各样的报错, 1、pip 安装失败的报错 类似下面的 我们有时候纠结在上面会纠结好久,浪费很多时间。(什么轮子我不知道) 常见的解决方法: s-1:先uninstall packing,再重新装一次(有时候会重…...
Windows下使用adb实现在模拟器中ping
文章目录 前言安装adb执行adb命令查找模拟器设备链接模拟器命令行执行ping命令 总结 前言 有时在模拟器中测试应用不像在Windows这种开发环境中那么方便,毕竟Windows或者Linux下的工具五花八门,可以满足各种测试需求,比如应用在模拟器中无法…...
c++之deque和priority_queue
Deque 文档:https://legacy.cplusplus.com/reference/deque/deque/?kwdeque 相关接口: push_back():在尾部插入 #include <iostream> #include <deque>int main () {std::deque<int> mydeque;int myint;std::cout << "…...
SDL渲染器和纹理
文章目录 渲染器 (SDL_Renderer)纹理 (SDL_Texture)代码 渲染器 (SDL_Renderer) :它是渲染内容的接口,负责将内容绘制到窗口中。通过SDL_CreateRenderer创建,可以设置渲染器的背景颜色、绘图颜色、透明度等。所有绘图操作(如绘制…...
基于Matlab 火焰识别技术
课题介绍 森林承担着为人类提供氧气以及回收二氧化碳等废弃气体的作用,森林保护显得尤其重要。但是每年由于火灾引起的事故不计其数,造成重大的损失。如果有一款监测软件,从硬件处获得的图像中监测是否有火焰,从而报警࿰…...
Qt 监控USB设备的插入和移除
Qt 监控USB设备的插入和移除 flyfish Ubuntu22.04 Qt 6.2.4 CMakeLists.txt 内容 # 指定 CMake 的最低版本要求 cmake_minimum_required(VERSION 3.16)# 定义项目的名称和使用的编程语言 project(USBMonitor LANGUAGES CXX)# 开启自动 UIC,MOC 和 RCC 工具 set(…...
终于弄懂了Python自定义模块与代码复用
自定义模块与代码复用 在编写Python代码时,很多时候我们会遇到需要多次使用相同功能的情况。这时候,模块化编程就显得尤为重要。通过将常用的功能代码放入单独的模块中,我们可以轻松地进行代码复用,避免重复编写相同的代码&#…...
从无音响Windows 端到 有音响macOS 端实时音频传输播放
以下是从 Windows 端到 macOS 端传输音频的优化方案,基于上述链接中的思路进行调整: Windows 端操作 安装必要软件 安装 Python(确保版本兼容且已正确配置环境变量)。安装 PyAudio 库,可通过 pip install pyaudio 命令…...
直方图均衡化及Matlab实现
文章目录 直方图均衡化关键点及思路Matlab实现 直方图均衡化 直方图均衡化是一种图像增强技术,主要用于增强图像的对比度,特别是当图像的有用数据的对比度接近时效果显著。通过改变图像的直方图分布,直方图均衡化能够使图像的灰度值更加接近…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
Electron通信流程
前言 今天讲Electron框架的通信流程,首先我们需要知道为什么需要通信。这得益于Electron的多进程模型,它主要模仿chrome的多进程模型如下图: 作为应用开发者,我们将控制两种类型的进程:主进程和渲染器进程 。 …...
