# 全面解剖 消息中间件 RocketMQ-(4)

news2024/12/23 10:15:37

全面解剖 消息中间件 RocketMQ-(4)

一、RocketMQ 顺序消息分析

1、消息有序:指的是可以按照消息的发送顺序来消费(FIFO)。RocketMQ 可以严格的保证消息有序,可以分为分区有序或者全局有序。

2、顺序消费的原理解析

在默认的情况下消息发送会采取 Round Robin 轮询方式把消息发送到不同的 queue (分区队列),而消费消息的时候从多个 queue上拉取消息,这种情况发送和消费是不能保证顺序。但是如果控制发送的顺序消息只依次发送到同一个 queue 中,消费的时候只从这个 queue 上依次拉取,则就保证了顺序。当发送和消费参与的 queue 只有一个,则是全局有序;如果多个 queue 参与,则为分区有序,即相对每个 queue,消息都是有序的。

3、下面用订单进行分区有序的示例。一个订单的顺序流程是:创建、付款、推送、完成。订单号相同的消息会被先后发送到同一个队列中,消费时,同一个 Orderld 获取到的肯定是同一个队列。

在这里插入图片描述

二、RocketMQ 顺序消息发送者

1、在工程 rocketmq_demo (模块)中,创建 订单构建 实体类 OrderStep.java


/**
 *  D:\java-test\idea2019\rocketmq_demo\src\main\java\djh\it\mq\rocketmq\order\OrderStep.java
 *
 *  2024-6-2 创建 订单构建 实体类 OrderStep.java
 */

package djh.it.mq.rocketmq.order;

import java.util.ArrayList;
import java.util.List;

public class OrderStep {

    private long orderId;  //订单 id
    private String desc;   //订单描述

    public long getOrderId() {
        return orderId;
    }

    public void setOrderId(long orderId) {
        this.orderId = orderId;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "OrderStep{" +
                "orderId=" + orderId +
                ", desc='" + desc + '\'' +
                '}';
    }

    public static List<OrderStep> buildOrders() {

        // 1039L    : 创建 付款 推送 完成
        // 1065L    : 创建 付款
        // 7235L    : 创建 付款

        List<OrderStep> orderList = new ArrayList<OrderStep>();

        OrderStep orderDemo = new OrderStep();
        orderDemo.setOrderId(1039L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(1065L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(1039L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(7235L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(1065L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(7235L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(1065L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(1039L);
        orderDemo.setDesc("推送");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(7235L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(1039L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        return orderList;

    }
}


2、在工程 rocketmq_demo (模块)中,创建 顺序消息发送 类 Producer.java


/**
 *   rocketmq_demo\src\main\java\djh\it\mq\rocketmq\order\Producer.java
 *
 *   2024-6-2  创建 顺序消息发送 类 Producer.java
 */
package djh.it.mq.rocketmq.order;

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;

import java.util.List;


public class Producer {

    public static void main(String[] args) throws Exception {
       
		//1.创建消息生产者 producer,并制定生产者组名
		DefaultMQProducer producer = new DefaultMQProducer("group1");

		//2.指定 Nameserver 地址(集群配置)
		//producer.setNamesrvAddr("192.168.25.135:9876;192.168.25.138:9876");

		//2.指定 Nameserver 地址(非集群配置)
		producer.setNamesrvAddr("172.18.30.110:9876");

		//3.启动 producer
		producer.start();

		//构建消息集合
		List<OrderStep> orderSteps = OrderStep.buildOrders();

		//发送消息
		for(int i=0; i<orderSteps.size(); i++){
			String body = orderSteps.get(i)+"";
			//4.创建消息对象,指定主题 Topic、Tag 和消息体
			//参数一:消息对象, 参数二:消息队列选择器, 参数三:选择队列的业务标识(订单id)
			Message message = new Message("OrderTopic", "Order", "i"+i, body.getBytes());
			
			//5.发送 异步 消息
			SendResult sendResult = producer.send(message, new MessageQueueSelector(){

				/**
				 *
				 * @param mqs :队列集合
				 * @param msg :消息对象				 *
				 * @param arg :业务标识的参数
				 * @return
				 */
				public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
					long orderId = (Long) arg;
					long index = orderId % mqs.size();
					return mqs.get((int) index);
				}
			}, orderSteps.get(i).getOrderId());

			System.out.println("发送结果:"+sendResult);
		}
		//6.关闭生产者 producer。
	    producer.shutdown();  	   
    }
}

三、RocketMQ 顺序消息消费者

1、在工程 rocketmq_demo (模块)中,创建 顺序消息消费 类 Consumer.java


/**
 *   rocketmq_demo\src\main\java\djh\it\mq\rocketmq\order\Consumer.java
 *
 *   2024-6-2  创建 顺序消息消费 类 Consumer.java 。
 */
package djh.it.mq.rocketmq.order;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.*;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;

import java.util.List;


public class Consumer {

	public static void main(String[] args) throws Exception {

		//1.创建消费者 Consumer,制定消费者组名
		DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group1");

		//2.指定 Nameserver 地址(集群配置)
		//consumer.setNamesrvAddr("192.168.25.135:9876;192.168.25.138:9876");

		//2.指定 Nameserver 地址(非集群配置)
		consumer.setNamesrvAddr("172.18.30.110:9876");

		//3.订阅主题 Topic 和 Tag
		consumer.subscribe("OrderTopic", "*");  //接收所有消息。

		//4.注册消息监听器
		consumer.registerMessageListener(new MessageListenerOrderly() {
			public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
				for(MessageExt msg : msgs){
					System.out.println("线程名称:【"+Thread.currentThread().getName() + "】 消费消息:" + new String(msg.getBody()));  //转换为字符串消息
				}

				return ConsumeOrderlyStatus.SUCCESS;
			}
		});

		//5.启动消费者 consumer。
		consumer.start();
		System.out.println("消费消息启动了");
	}
}

2、先启动 顺序消息发送 类 Producer.java,再启动 顺序消息消费 类 Consumer.java 进行测试。

在这里插入图片描述

四、RocketMQ 延迟消息

1、RocketMQ 延迟消息

比如电商里,提交了一个订单就可以发送一个延时消息,1h 后去检查这个订单的状态,
如果还是未付款就取消订单释放库存。

2、RocketMQ 延迟消息 使用限制

//org/apache/rocketmg/store/config/Messagestoreconfig.java

private string messageDelayLevel = “1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”.

现在 RocketMg 并不支持任意时间的延时,需要设置几个固定的延时等级,从 1s 到 2h 分别对应着等级 1 到 18。

3、在工程 rocketmq_demo (模块)中,创建 延迟消息 发送 类 Producer.java


/**
 *   rocketmq_demo\src\main\java\djh\it\mq\rocketmq\delay\Producer.java
 *
 *   2024-6-2  创建 延迟消息 发送 类 Producer.java
 */
package djh.it.mq.rocketmq.delay;

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import java.util.concurrent.TimeUnit;

public class Producer {

    public static void main(String[] args) throws Exception {
       
		//1.创建消息生产者 producer,并制定生产者组名
		DefaultMQProducer producer = new DefaultMQProducer("group1");

		//2.指定 Nameserver 地址(集群配置)
		//producer.setNamesrvAddr("192.168.25.135:9876;192.168.25.138:9876");

		//2.指定 Nameserver 地址(非集群配置)
		producer.setNamesrvAddr("172.18.30.110:9876");

		//3.启动 producer
		producer.start();

		//发送消息
		for(int i=0; i<10; i++){
			//4.创建消息对象,指定主题 Topic、Tag 和消息体
			//参数一:消息主题 Topic, 参数二:消息 Tag, 参数三:消息内容
			Message msg = new Message("DelayTopic", "Tag1", ("Hello World"+i).getBytes());

			//设定延迟发送 时间为 5 秒(目前 rocketmq 支持的延迟等级:"1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h".)
			msg.setDelayTimeLevel(2);

			//5.发送消息
			SendResult result = producer.send(msg);

			System.out.println("发送结果:"+result);
			TimeUnit.SECONDS.sleep(1);  //线程睡1秒
		}
		//6.关闭生产者 producer。
		producer.shutdown();
    }
}

4、在工程 rocketmq_demo (模块)中,创建 延迟消息 消费 类 Consumer.java 。


/**
 *   rocketmq_demo\src\main\java\djh\it\mq\rocketmq\delay\Consumer.java
 *
 *   2024-6-2  创建 延迟消息 消费 类 Consumer.java 。
 */
package djh.it.mq.rocketmq.delay;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.*;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;

import java.util.List;

public class Consumer {

	public static void main(String[] args) throws Exception {

		//1.创建消费者 Consumer,制定消费者组名
		DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group1");

		//2.指定 Nameserver 地址(集群配置)
		//consumer.setNamesrvAddr("192.168.25.135:9876;192.168.25.138:9876");

		//2.指定 Nameserver 地址(非集群配置)
		consumer.setNamesrvAddr("172.18.30.110:9876");

		//3.订阅主题 Topic 和 Tag
		//consumer.subscribe("base", "Tag1");  //接收同步消息
		//consumer.subscribe("base", "Tag2");  //接收异步消息前,可以让先发送异步消息。
		//consumer.subscribe("base", "Tag1 | Tag2");  //接收同步消息 和 异步消息
		consumer.subscribe("DelayTopic", "*");  //接收所有消息。

		//添加消费模式
		//consumer.setMessageModel(MessageModel.CLUSTERING);  //默认是负载均衡模式消费
		consumer.setMessageModel(MessageModel.BROADCASTING);  //广播模式消费

		//4.设置回调函数,处理消息
		consumer.registerMessageListener(new MessageListenerConcurrently(){
			//接受消息内容
			public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context){
				//System.out.println(msgs); //接收到的消息是未转换的字节码

				for(MessageExt msg : msgs){
					System.out.println("消息ID:【" + msg.getMsgId()+"】,延迟时间:"+(System.currentTimeMillis()-msg.getStoreTimestamp()));  //转换为字符串消息
				}

				return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
			}
		});

		//5.启动消费者 consumer。
		consumer.start();

		System.out.println("消费者启动");
	}
}

5、先启动 延迟消息 消费 类 Consumer.java 再启动 延迟消息 发送 类 Producer.java 进行测试。

在这里插入图片描述

五、RocketMQ 批量消息发送

1、批量发送消息能显著提高传递小消息的性能。限制是这些批量消息应该有相同的 topic,相同的 waitstoreMsgOK,而且不能是延时消息。此外,这一批消息的总大小不应超过無 4MB。如果消息的总长度可能大于4MB时,这时候最好把消息进行分割。

2、在工程 rocketmq_demo (模块)中,创建 批量消息发送 发送 类 Producer.java


/**
 *   rocketmq_demo\src\main\java\djh\it\mq\rocketmq\batch\Producer.java
 *
 *   2024-6-2  创建 批量消息发送的 发送 类 Producer.java
 */
package djh.it.mq.rocketmq.batch;

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class Producer {

    public static void main(String[] args) throws Exception {
       
		//1.创建消息生产者 producer,并制定生产者组名
		DefaultMQProducer producer = new DefaultMQProducer("group1");

		//2.指定 Nameserver 地址(集群配置)
		//producer.setNamesrvAddr("192.168.25.135:9876;192.168.25.138:9876");

		//2.指定 Nameserver 地址(非集群配置)
		producer.setNamesrvAddr("172.18.30.110:9876");

		//3.启动 producer
		producer.start();

		//创建一个集合
		List<Message> msgs = new ArrayList<Message>();

		//发送消息

		//4.创建消息对象,指定主题 Topic、Tag 和消息体
		//参数一:消息主题 Topic, 参数二:消息 Tag, 参数三:消息内容
		Message msg1 = new Message("BatchTopic", "Tag1", ("Hello World"+1).getBytes());
		Message msg2 = new Message("BatchTopic", "Tag1", ("Hello World"+2).getBytes());
		Message msg3 = new Message("BatchTopic", "Tag1", ("Hello World"+3).getBytes());

		msgs.add(msg1);
		msgs.add(msg2);
		msgs.add(msg3);

		//5.发送消息
		SendResult result = producer.send(msgs);

		System.out.println("发送结果:"+result);
		TimeUnit.SECONDS.sleep(1);  //线程睡1秒

		//6.关闭生产者 producer。
		producer.shutdown();
    }
}

3、在工程 rocketmq_demo (模块)中,创建 批量消息发送 消费 类 Consumer.java 。


/**
 *   rocketmq_demo\src\main\java\djh\it\mq\rocketmq\batch\Consumer.java
 *
 *   2024-6-2  创建 批量消息发送 消费 类 Consumer.java 。
 */
package djh.it.mq.rocketmq.batch;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;

import java.util.List;

public class Consumer {

	public static void main(String[] args) throws Exception {

		//1.创建消费者 Consumer,制定消费者组名
		DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group1");

		//2.指定 Nameserver 地址(集群配置)
		//consumer.setNamesrvAddr("192.168.25.135:9876;192.168.25.138:9876");

		//2.指定 Nameserver 地址(非集群配置)
		consumer.setNamesrvAddr("172.18.30.110:9876");

		//3.订阅主题 Topic 和 Tag
		consumer.subscribe("BatchTopic", "*");  //接收所有消息。

		//4.设置回调函数,处理消息
		consumer.registerMessageListener(new MessageListenerConcurrently(){
			//接受消息内容
			public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context){
			//System.out.println(msgs); //接收到的消息是未转换的字节码

			for(MessageExt msg : msgs){
				System.out.println("consumeThread=" + Thread.currentThread().getName()+", "+new String(msg.getBody()));  //转换为字符串消息
			}

			return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
			}
		});

		//5.启动消费者 consumer。
		consumer.start();

		System.out.println("消费者启动");
	}
}

4、先启动 批量消息发送 消费 类 Consumer.java 再启动 批量消息发送 发送 类 Producer.java 进行测试。

在这里插入图片描述
上一节关联链接请点击:
# 全面解剖 消息中间件 RocketMQ-(3)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

oracle报错ORA-01940: cannot drop a user that is currently connected解决方法

目录 一.原因 二.解决方法 1.查询活动会话 2.记下SID和SERIAL# 3.断开会话 4.删除用户 一.原因 ORA-01940代表你正在删除一个有活动会话的用户 二.解决方法 1.查询活动会话 SQL> SELECT sid, serial#, username, programFROM v$sessionWHERE username 你要删除的u…

使用 Django Channels 构建实时聊天应用(包含用户认证和消息持久化)

文章目录 准备工作创建 Django 项目创建应用程序配置项目编写 Consumer编写路由创建 URL 路由运行应用用户认证消息持久化显示历史消息结论 Django Channels 是 Django 的一个扩展&#xff0c;允许在 Web 应用中添加实时功能&#xff0c;例如 Websockets、HTTP2 和其他协议。本…

CasaOS玩客云如何部署小雅AList并结合内网穿透远程访问海量资源

文章目录 前言1. 本地部署AList2. AList挂载网盘3. 部署小雅alist3.1 Token获取3.2 部署小雅3.3 挂载小雅alist到AList中 4. Cpolar内网穿透安装5. 创建公网地址6. 配置固定公网地址 前言 本文主要介绍如何在安装了CasaOS的玩客云主机中部署小雅AList&#xff0c;并在AList中挂…

原来Stable Diffusion是这样工作的

stable diffusion是一种潜在扩散模型&#xff0c;可以从文本生成人工智能图像。为什么叫做潜在扩散模型呢&#xff1f;这是因为与在高维图像空间中操作不同&#xff0c;它首先将图像压缩到潜在空间中&#xff0c;然后再进行操作。 在这篇文章中&#xff0c;我们将深入了解它到…

23中设计模式之一— — — —命令模式的详细介绍

命令模式 Command Pattern讲解 概念描述模式结构主要角色模式的UIM类图模式优点模式缺点应用场景实例演示类图代码演示运行结果 概念 命令模式&#xff08;别名&#xff1a;动作&#xff0c;事务&#xff09; 命令模式是一种行为设计模式&#xff0c;将一个请求封装为一个对象…

内网-2(代理)

一、代理概述 1、代理服务器(proxy server)&#xff1a;代理网络用户去取得网络信息&#xff0c;介于浏览器与web服务器之间的一条服务器。 注&#xff1a;为了方便&#xff0c;以下用B来代表浏览器的主机&#xff0c;S来代表服务器的主机。 2、正向代理和反向代理 正向代…

shell(一)

shell 既是脚本语言又是应用程序 查看自己linux系统的默认解析&#xff1a;echo $SHELL 创建第一个shell 文件 touch 01.sh编辑 vi 01.sh01.sh 文件内容 #!/bin/bash echo felicia保存 按Esc 然后输入:wq 定义以开头&#xff1a;#!/bin/bash #!用来声明脚本由什么shell解释…

如何在路由器上安装代理服务:详细教程

如何在路由器上安装代理服务&#xff1a;详细教程 步骤一&#xff1a;通过漏洞进入路由器系统开启Telnet服务使用Telnet登录路由器系统查看系统信息和CPU信息步骤二&#xff1a;交叉编译MIPS程序 Go对MIPS的支持 安装TFTP Server使用BusyBox tftp传输文件在路由器系统中下载编译…

Linux.小技巧快捷键

1. ctrl c 强制停止 终止某些程序的运行 也可以取消某行命令 2. ctrl d 退出或登出 进入python环境中&#xff0c;使用ctrl d 退出 3.history 查看历史使用了哪些命令 4. ! 历史最近使用的命令的开头 5.使用ctrl r 搜索历史使用的命令 按下 ctrl r 会进入 reverse -…

GIS赋能低空经济:开辟天空新蓝海

在21世纪的科技浪潮中&#xff0c;低空经济作为新兴业态正悄然崛起&#xff0c;成为继陆地、海洋之后的又一战略要地。本文旨在探讨GIS如何赋能低空经济&#xff0c;推动无人机应用、空中交通管理、低空物流、城市空域规划等领域的发展&#xff0c;开启天空经济的新纪元。 GIS…

Xmind Pro 2024 专业版激活码(附下载链接)

说到思维导图&#xff0c;就不能不提 Xmind。这是一款优秀的思维导图工具&#xff0c;拥有着丰富的导图模板&#xff0c;漂亮的界面和配色&#xff0c;以及各种各样的创意工具。 新架构速度更快 采用全新 Snowdancer 引擎&#xff0c;一种堪称「黑科技」的先进图形渲染技术。…

CrawlSpace爬虫部署框架介绍

CrawlSpace爬虫部署框架介绍 全新的爬虫部署框架&#xff0c;为了适应工作的爬虫部署的使用&#xff0c;需要自己开发一个在线编写爬虫及部署爬虫的框架&#xff0c;框架采用的是Django2.2bootstap依赖scrapyd开发的全新通用爬虫在线编辑部署及scrapy项目的部署框架。项目实现的…

VCRUNTIME140_1.dll是什么?VCRUNTIME140_1.dll缺失的7个不同解决方法详解

vcruntime140_1.dll是Microsoft Visual C 2015运行时库的一部分&#xff0c;它为使用Visual C 2015编译的应用程序提供了必要的运行时支持。该文件包含多个关键的运行时组件&#xff0c;包括标准模板库(STL)、C异常处理、内存管理等。 功能: vcruntime140_1.dll确保应用程序能…

在人工智能背景下,程序员要有什么职业素养,怎么改进

文章目录 1. 持续学习和适应能力原因改善方法 2. 跨学科知识原因改善方法 3. 高效的计算资源利用原因改善方法 4. 模型解释性和可控性原因改善方法 5. 数据隐私和安全意识原因改善方法 在AI大模型的背景下&#xff0c;程序员要有什么职业素养&#xff0c;怎么改进&#xff0c;才…

电流继电器JL-31 柜内固定安装 约瑟JOSEF

JL系列电流继电器型号&#xff1a; 电流继电器JL-31 电流继电器JL-31C/1 电流继电器JL-31A 电流继电器JL-31/B 电流继电器JL-32BP 电流继电器JL-22 电流继电器JL-21 电流继电器JL-21B 电流继电器JL-23 电流继电器JL-11 电流继电器JL-11/2G 电流继电器JL-11C 电流继电器J…

5.23.3 乳腺癌成像中的深度学习:十年的进展和未来方向

乳腺影像学在早期诊断和干预以改善乳腺癌患者的预后方面发挥着重要作用。在过去的十年中,深度学习在乳腺癌成像分析方面取得了显着进展,在解释乳腺成像模式的丰富信息和复杂背景方面具有巨大前景。 基于深度学习的乳腺癌成像研究涵盖了对乳房X光检查、超声、磁共振成像和数字…

无人机推流/RTMP视频推拉流EasyDSS无法卸载软件是什么原因?

视频推拉流/直播点播EasyDSS平台支持音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务&#xff0c;在应用场景中可实现视频直播、点播、转码、管理、录像、检索、时移回看等。此外&#xff0c;平台还支持用户自行上传视频文件&#xff0c;也可将上传的点播…

记Codes开源免费研发项目管理平台——流程驱动缺陷管理的创新实现

继上一回合日报与工时融合集中式填报的创新实现后&#xff0c;本篇我们来讲一讲流程驱动缺陷管理的创新实现。 肯定会有人说&#xff0c;不就缺陷管理嘛&#xff01;几个状态完事&#xff0c;爱咋整就咋整&#xff0c;没必要搞流程化&#xff0c;搞流程就是把简单事情复杂化。 …

ViewModel原理分析

认识 ViewModel ViewModel 是一种用来存储和管理UI相关数据的类。 ViewModel 的作用可以从两个方面去理解&#xff1a; UI界面控制器&#xff1a;在最初的MVC模式中&#xff0c;由于 Activity / Fragment 承担的职责过重&#xff0c;因此在后续的 MVP、MVVM 模式中&#xff…

iOS 通过PacketLogger 抓包蓝牙数据包

当使用iOS平台调试蓝牙外设时&#xff0c;需要抓取蓝牙数据包&#xff0c;那么如何获取iOS端设备与蓝牙设备之间通信的蓝牙数据包呢&#xff1f; 一、资料准备 1、苹果手机 2、Xcode开发工具 3、Apple开发者账户 二、环境搭建 2.1、手机环境搭建 手机浏览器访问地址&…