RabbitMQ 七种工作模式介绍

目录

1.简单模式队列

2.WorkQueue(⼯作队列)

3 Publish/Subscribe(发布/订阅)

4 Routing(路由模式)

5.Topics(通配符模式)

6 RPC(RPC通信)

7 Publisher Confirms(发布确认)


RabbitMQ 共提供了7种⼯作模式供我们进⾏消息传递,接下来一一介绍它的实现与目的

1.简单模式队列

P为生产者  发送信息中间(消息队列)C作为消费者 直接消费消息队列里面的内容

特点:⼀个⽣产者P,⼀个消费者C,消息只能被消费⼀次.也称为点对点(Point-to-Point)模式.

 生产者:

1.创建连接工厂

2.设置工厂参数

3.创建channel

4.声明queue

5 通过channel发送到queue

6. 资源释放

public static void main(String[] args) throws IOException,TimeoutException {//1.创建连接工厂ConnectionFactory factory = new ConnectionFactory();//2.设置工厂参数factory.setHost(Constants.HOST);factory.setPort(Constants.PORT);factory.setUsername(Constants.USER_NAME);factory.setPassword(Constants.PASSWORD);factory.setVirtualHost(Constants.VIRTUAL_HOST);Connection connection = factory.newConnection();//3.创建channelChannel channel = connection.createChannel();//4.声明queue/*** queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,* Map<String, Object> arguments)* 1.队列名称* 2.durable 可持久化 true为持久化* 3.exclusive 是否独占 false* 4. autoDelete 是否自动删除 false* arguments 参数*///如果没有⼀个hello 这样的⼀个队列, 会⾃动创建, 如果有, 则不创建channel.queueDeclare("simple",true,false,false,null);//5 通过channel发送到queue/*** basicPublish(String exchange, String routingKey, AMQP.BasicProperties props,* byte[] body)* 1.exchange 交换机名称 ,简单情况下 一般默认的情况为""* 2.routingKey 路由名称=队列名称* 3.props 配置信息* 4.body 发现信息的数据*/for (int i = 0; i < 10; i++) {String msg = "hello 简单队列~"+i;channel.basicPublish("","simple", null, msg.getBytes());}System.out.println("信息发送成功!");//6. 资源释放channel.close();connection.close();}

消费者:

1.创建连接工厂

2.设置工厂参数

3.创建channel

4.声明queue

5.消费数据

6.资源释放

public static void main(String[] args) throws IOException, TimeoutException {//创建连接工厂ConnectionFactory factory = new ConnectionFactory();//2.设置工厂参数factory.setHost(Constants.HOST);factory.setPort(Constants.PORT);factory.setUsername(Constants.USER_NAME);factory.setPassword(Constants.PASSWORD);factory.setVirtualHost(Constants.VIRTUAL_HOST);Connection connection = factory.newConnection();//3.创建channelChannel channel = connection.createChannel();//4.声明queue/*** queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,* Map<String, Object> arguments)* 1.队列名称* 2.durable 可持久化 true为持久化* 3.exclusive 是否独占 false* 4. autoDelete 是否自动删除 false* arguments 参数*///如果没有⼀个hello 这样的⼀个队列, 会⾃动创建, 如果有, 则不创建channel.queueDeclare("simple",true,false,false,null);//5.接收信息 并消费/*** basicConsume(String queue, boolean autoAck, Consumer callback)* queue :队列名称* autoAck:是否自动确认 消费者接收信息与MQ* callback :回调对象*/DefaultConsumer consumer = new DefaultConsumer(channel) {/*回调方法 当收到信息 自动执行该方法consumerTag*/@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("接收到信息:"+new String(body));}};channel.basicConsume("simple",true,consumer);// 释放资源channel.close();connection.close();}


2.WorkQueue(⼯作队列)

 一个生产者(P) 多个消费者(C) 消息队列会平均分配给消费者

特点:消息不会重复,分配给不同的消费者.
适⽤场景:集群环境中做异步处理

生产者:

跟简单模式类似 或一个队列名称

 public static void main(String[] args) throws IOException,TimeoutException {//1.创建连接工厂ConnectionFactory factory = new ConnectionFactory();//2.设置工厂参数factory.setHost(Constants.HOST);factory.setPort(Constants.PORT);factory.setUsername(Constants.USER_NAME);factory.setPassword(Constants.PASSWORD);factory.setVirtualHost(Constants.VIRTUAL_HOST);Connection connection = factory.newConnection();//3.创建channelChannel channel = connection.createChannel();//4.声明queuechannel.queueDeclare(Constants.WORK_QUEUE,true,false,false,null);//5 通过channel发送到queuefor (int i = 0; i < 10; i++) {String msg = "hello 工作队列~"+i;channel.basicPublish("",Constants.WORK_QUEUE, null, msg.getBytes());}System.out.println("信息发送成功!");//6. 资源释放channel.close();connection.close();}

消费者1:

public static void main(String[] args) throws IOException, TimeoutException {//创建连接工厂ConnectionFactory factory = new ConnectionFactory();//2.设置工厂参数factory.setHost(Constants.HOST);factory.setPort(Constants.PORT);factory.setUsername(Constants.USER_NAME);factory.setPassword(Constants.PASSWORD);factory.setVirtualHost(Constants.VIRTUAL_HOST);Connection connection = factory.newConnection();//3.创建channelChannel channel = connection.createChannel();//4.声明queue//如果没有⼀个hello 这样的⼀个队列, 会⾃动创建, 如果有, 则不创建channel.queueDeclare(Constants.WORK_QUEUE,true,false,false,null);//5.接收信息 并消费DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("接收到信息:"+new String(body));}};channel.basicConsume(Constants.WORK_QUEUE,true,consumer);// 释放资源channel.close();connection.close();}

 消费者2 也是同样的代码


3 Publish/Subscribe(发布/订阅)

Fanout:⼴播,将消息交给所有绑定到交换机的队列(Publish/Subscribe模式)

X作为交换机  将消息复制多份 并且发送多个消费者 并且每个消费者收到相同的信息

比如 P发送了10条消息  C1和C2得消费10条信息

适合场景: 消息需要被多个消费者同时接收的场景. 如: 实时通知或者⼴播消息

 

Exchange(交换机)只负责转发消息, 不具备存储消息的能⼒, 因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息就会丢失

RoutingKey: 路由键.⽣产者将消息发给交换器时, 指定的⼀个字符串, ⽤来告诉交换机应该如何处理这个消息.

Binding Key:绑定. RabbitMQ中通过Binding(绑定)将交换器与队列关联起来, 在绑定的时候⼀般会指定⼀个Binding Key, 这样RabbitMQ就知道如何正确地将消息路由到队列了.

 

生产者:

    public static void main(String[] args) throws IOException, TimeoutException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD);  //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();//3. 声明交换机channel.exchangeDeclare(Constants.FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT, true);//4. 声明队列channel.queueDeclare(Constants.FANOUT_QUEUE1,true,false,false,null);channel.queueDeclare(Constants.FANOUT_QUEUE2,true,false,false,null);//5. 交换机和队列绑定channel.queueBind(Constants.FANOUT_QUEUE1,Constants.FANOUT_EXCHANGE,"");channel.queueBind(Constants.FANOUT_QUEUE2,Constants.FANOUT_EXCHANGE,"");//6. 发布消息for (int i = 0; i < 10; i++) {String msg = "hello 发布订阅队列~"+i;channel.basicPublish(Constants.FANOUT_EXCHANGE,"", null, msg.getBytes());}System.out.println("消息发送成功");//7. 释放资源channel.close();connection.close();}

 

 消费者1

public static void main(String[] args) throws IOException, TimeoutException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD);  //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();//3. 声明队列channel.queueDeclare(Constants.FANOUT_QUEUE1,true,false,false,null);//4. 消费消息DefaultConsumer consumer = new DefaultConsumer(channel){//从队列中收到消息, 就会执行的方法@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("接收到消息:"+ new String(body));}};channel.basicConsume(Constants.FANOUT_QUEUE1, true, consumer);}

消费者2同理 

 


4 Routing(路由模式)

路由模式是发布订阅模式的变种, 在发布订阅基础上, 增加路由key

发布订阅模式是⽆条件的将所有消息分发给所有消费者, 路由模式是Exchange根据RoutingKey的规则, 将数据筛选后发给对应的消费者队列
适合场景: 需要根据特定规则分发消息的场景.

⽐如系统打印⽇志, ⽇志等级分为error, warning, info,debug, 就可以通过这种模式,把不同的⽇志发送到不同的队列, 最终输出到不同的⽂件

生产者:

    public static void main(String[] args) throws IOException, TimeoutException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD);  //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();//3. 声明交换机channel.exchangeDeclare(Constants.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT, true);//4. 声明队列channel.queueDeclare(Constants.DIRECT_QUEUE1,true,false,false,null);channel.queueDeclare(Constants.DIRECT_QUEUE2,true,false,false,null);//5. 交换机和队列绑定channel.queueBind(Constants.DIRECT_QUEUE1,Constants.DIRECT_EXCHANGE,"a");channel.queueBind(Constants.DIRECT_QUEUE2,Constants.DIRECT_EXCHANGE,"a");channel.queueBind(Constants.DIRECT_QUEUE2,Constants.DIRECT_EXCHANGE,"b");channel.queueBind(Constants.DIRECT_QUEUE2,Constants.DIRECT_EXCHANGE,"c");//6. 发布消息String msg_a = "hello 路由队列~ my routingKey is a...";channel.basicPublish(Constants.DIRECT_EXCHANGE,"a", null, msg_a.getBytes());String msg_b = "hello 路由队列~ my routingKey is b...";channel.basicPublish(Constants.DIRECT_EXCHANGE,"b", null, msg_b.getBytes());String msg_c = "hello 路由队列~ my routingKey is c...";channel.basicPublish(Constants.DIRECT_EXCHANGE,"c", null, msg_c.getBytes());System.out.println("消息发送成功");//7. 释放资源channel.close();connection.close();}

消费者1

public class Consumer2 {public static void main(String[] args) throws IOException, TimeoutException {//创建连接工厂ConnectionFactory factory = new ConnectionFactory();//2.设置工厂参数factory.setHost(Constants.HOST);factory.setPort(Constants.PORT);factory.setUsername(Constants.USER_NAME);factory.setPassword(Constants.PASSWORD);factory.setVirtualHost(Constants.VIRTUAL_HOST);Connection connection = factory.newConnection();//3.创建channelChannel channel = connection.createChannel();//4.声明queue//如果没有⼀个hello 这样的⼀个队列, 会⾃动创建, 如果有, 则不创建channel.queueDeclare(Constants.DIRECT_QUEUE1,true,false,false,null);//5.接收信息 并消费DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("接收到信息:"+new String(body));}};channel.basicConsume(Constants.DIRECT_QUEUE1,true,consumer);}

消费者 2同理


5.Topics(通配符模式)

 

路由模式的升级版, 在routingKey的基础上,增加了通配符的功能, 使之更加灵活.

Topics和Routing的基本原理相同,即:⽣产者将消息发给交换机,交换机根据RoutingKey将消息转发给与RoutingKey匹配的队列. 类似于正则表达式的⽅式来定义Routingkey的模式.

适合场景: 需要灵活匹配和过滤消息的场景

生产者:

public static void main(String[] args) throws IOException, TimeoutException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD);  //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();//3. 声明交换机channel.exchangeDeclare(Constants.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC, true);//4. 声明队列channel.queueDeclare(Constants.TOPIC_QUEUE1,true,false,false,null);channel.queueDeclare(Constants.TOPIC_QUEUE2,true,false,false,null);//5. 交换机和队列绑定channel.queueBind(Constants.TOPIC_QUEUE1,Constants.TOPIC_EXCHANGE,"*.a.*");channel.queueBind(Constants.TOPIC_QUEUE2,Constants.TOPIC_EXCHANGE,"*.*.b");channel.queueBind(Constants.TOPIC_QUEUE2,Constants.TOPIC_EXCHANGE,"c.#");//6. 发布消息String msg_a = "hello 路由队列~ my routingKey is ae.a.f...";channel.basicPublish(Constants.TOPIC_EXCHANGE,"ae.a.f", null, msg_a.getBytes());String msg_b = "hello 路由队列~ my routingKey is ef.a.b...";channel.basicPublish(Constants.TOPIC_EXCHANGE,"ef.a.b", null, msg_b.getBytes());String msg_c = "hello 路由队列~ my routingKey is c.ef.d ...";channel.basicPublish(Constants.TOPIC_EXCHANGE,"c.ef.d", null, msg_c.getBytes());System.out.println("消息发送成功");//7. 释放资源channel.close();connection.close();}

消费者1: 只接收*.a.*

 

 

消费者2: 接收*.*.b c.#

 


6 RPC(RPC通信)

 

在RPC通信的过程中, 没有⽣产者和消费者, ⽐较像咱们RPC远程调⽤, ⼤概就是通过两个队列实现了⼀个可回调的过程.

 

客户端:1.发送请求(携带replyTo,correlationId )2.接收响应(验证correlationId)

服务器:1.接收请求 进行响应 2.发送响应(按客户端指定的replyTo,设置correlationId)

 客户端:

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD);  //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();channel.queueDeclare(Constants.RPC_RESPONSE_QUEUE,true,false,false,null);channel.queueDeclare(Constants.RPC_REQUEST_QUEUE,true,false,false,null);//3. 发送请求String msg = "hello rpc...";//设置请求的唯一标识String correlationID = UUID.randomUUID().toString();//设置请求的相关属性AMQP.BasicProperties props = new AMQP.BasicProperties().builder().correlationId(correlationID).replyTo(Constants.RPC_RESPONSE_QUEUE).build();channel.basicPublish("",Constants.RPC_REQUEST_QUEUE,props,msg.getBytes());//4. 接收响应//使用阻塞队列, 来存储响应信息final BlockingQueue<String> response = new ArrayBlockingQueue<>(1);DefaultConsumer consumer = new DefaultConsumer(channel){@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {String respMsg = new String(body);System.out.println("接收到回调消息: "+ respMsg);if (correlationID.equals(properties.getCorrelationId())){//如果correlationID校验一致response.offer(respMsg);}}};channel.basicConsume(Constants.RPC_RESPONSE_QUEUE, true, consumer);String result = response.take();System.out.println("[RPC Client 响应结果]:"+ result);}

 

客户端:

public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD);  //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();channel.queueDeclare(Constants.RPC_RESPONSE_QUEUE,true,false,false,null);channel.queueDeclare(Constants.RPC_REQUEST_QUEUE,true,false,false,null);//3. 发送请求String msg = "hello rpc...";//设置请求的唯一标识String correlationID = UUID.randomUUID().toString();//设置请求的相关属性AMQP.BasicProperties props = new AMQP.BasicProperties().builder().correlationId(correlationID).replyTo(Constants.RPC_RESPONSE_QUEUE).build();channel.basicPublish("",Constants.RPC_REQUEST_QUEUE,props,msg.getBytes());//4. 接收响应//使用阻塞队列, 来存储响应信息final BlockingQueue<String> response = new ArrayBlockingQueue<>(1);DefaultConsumer consumer = new DefaultConsumer(channel){@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {String respMsg = new String(body);System.out.println("接收到回调消息: "+ respMsg);if (correlationID.equals(properties.getCorrelationId())){//如果correlationID校验一致response.offer(respMsg);}}};channel.basicConsume(Constants.RPC_RESPONSE_QUEUE, true, consumer);String result = response.take();System.out.println("[RPC Client 响应结果]:"+ result);}

 


7 Publisher Confirms(发布确认)

消息丢失其中一种情况 ⽣产者问题. 因为应⽤程序故障, ⽹络抖动等各种原因, ⽣产者没有成功向broker发送消息
可以采⽤发布确认(Publisher Confirms)机制实现

发送⽅确认机制最⼤的好处在于它是异步的, ⽣产者可以同时发布消息和等待信道返回确认消息.

1. 当消息最终得到确认之后, ⽣产者可以通过回调⽅法来处理该确认消息.

2. 如果RabbitMQ因为⾃⾝内部错误导致消息丢失, 就会发送⼀条nack(Basic.Nack)命令, ⽣产者同样 可以在回调⽅法中处理该nack命令.

使⽤发送确认机制, 必须要信道设置成confirm(确认)模式.
 

发布确认有3种策略, 接下来我们来学习这三种策略

(1) Publishing Messages Individually(单独确认)

    private static void publishingMessagesIndividually() throws Exception {try(Connection connection = createConnection()) {//1.开启信道Channel channel = connection.createChannel();//2. 设置信道为confirm模式channel.confirmSelect();//3.声明队列channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE1,true,false,false,null);//4.发送消息,并等待确认Long start = System.currentTimeMillis();for (int i = 0; i < MESSAGE_COUNT; i++) {String msg = "hello publisher confirms"+i;channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE1,null,msg.getBytes());//等待确认channel.waitForConfirmsOrDie(5000);}Long end = System.currentTimeMillis();System.out.printf("单独确认策略, 消息条数: %d, 耗时: %d ms \n",MESSAGE_COUNT, end-start);}}

(2)Publishing Messages in Batches(批量确认) 

private static void publishingMessagesInBatches() throws Exception {try(Connection connection = createConnection()) {//1.开启信道Channel channel = connection.createChannel();//2. 设置信道为confirm模式channel.confirmSelect();//3.声明队列channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE2,true,false,false,null);//4. 发送消息, 并进行确认long start = System.currentTimeMillis();int batchSize = 100;int outstandingMessageCount = 0;for (int i = 0; i < MESSAGE_COUNT; i++) {String msg = "hello publisher confirms"+i;channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE2,null,msg.getBytes());outstandingMessageCount++;if(outstandingMessageCount == batchSize) {channel.waitForConfirmsOrDie(5000);outstandingMessageCount = 0;}}if(outstandingMessageCount > 0) {channel.waitForConfirmsOrDie(5000);}long end = System.currentTimeMillis();System.out.printf("批量确认策略, 消息条数: %d, 耗时: %d ms \n",MESSAGE_COUNT, end-start);}}

(3)Handling Publisher Confirms Asynchronously(异步确认)

    private static void handlingPublisherConfirmsAsynchronously() throws Exception {try(Connection connection = createConnection()) {//1.开启信道Channel channel = connection.createChannel();//2. 设置信道为confirm模式channel.confirmSelect();//3.声明队列channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE3,true,false,false,null);//4. 监听confirm//集合中存储的是未确认的消息IDlong start = System.currentTimeMillis();SortedSet<Long> confirmSeqNo = Collections.synchronizedSortedSet(new TreeSet<>());channel.addConfirmListener(new ConfirmListener() {@Overridepublic void handleAck(long deliveryTag, boolean multiple) throws IOException {if(multiple) {confirmSeqNo.headSet(deliveryTag+1).clear();} else {confirmSeqNo.remove(deliveryTag);}}@Overridepublic void handleNack(long deliveryTag, boolean multiple) throws IOException {if(multiple) {confirmSeqNo.headSet(deliveryTag+1).clear();}else  {confirmSeqNo.remove(deliveryTag);}//业务需要根据实际场景进行处理, 比如重发, 此处代码省略}});for (int i = 0; i < MESSAGE_COUNT; i++) {String msg = "hello publisher confirms"+i;long seqNo = channel.getNextPublishSeqNo();channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE3,null,msg.getBytes());confirmSeqNo.add(seqNo);}while (!confirmSeqNo.isEmpty()) {Thread.sleep(10);}long end = System.currentTimeMillis();System.out.printf("异步确认策略, 消息条数: %d, 耗时: %d ms \n",MESSAGE_COUNT, end-start);}}

 消息数越多, 异步确认的优势越明显


 小结:1-5工作模式重点学习 6-7工作模式了解即可

 

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

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

相关文章

数组类算法【leetcode】

704. 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 二分查找 用于有序数组中&#xff0c;没有重复的数组。…

Pandas 数据分析工具详细教程

Pandas 数据分析工具详细教程 Pandas 是一个强大的 Python 数据分析库&#xff0c;广泛应用于数据科学、数据分析和机器学习等领域。它提供了高效的数据操作和分析功能&#xff0c;使得数据处理变得简单而高效。本文将详细介绍 Pandas 的基本概念、数据结构、常用操作及其在数…

基于 EventBridge + DashVector 打造 RAG 全链路动态语义检索能力

作者&#xff1a;肯梦 本文将演示如何使用事件总线&#xff08;EventBridge&#xff09;&#xff0c;向量检索服务&#xff08;DashVector&#xff09;&#xff0c;函数计算&#xff08;FunctionCompute&#xff09;结合灵积模型服务 [ 1] 上的 Embedding API [ 2] &#xff0…

GooglePlay: 应用和游戏的内容分级

对于后台私信的开发者们,希望能够携带详细过审记录和拒审邮件一同发来,方便我们尽快解决问题 应用与游戏 为您的应用或游戏选择类别和标签选择要添加的标签选择类别并添加标签类别示例与应用、游戏以及两者中所投放广告的内容分级相关的要求应用如何获得内容分级内容分级的用…

将Notepad++添加到右键菜单【一招实现】

一键添加注册表 复制以下代码保存为 Notepad.reg&#xff0c;将红框内路径修改为自己电脑的“Notepad.exe路径”后&#xff0c;再双击运行即可。 Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\*\shell\NotePad] "Notepad" "Icon""D:\\N…

[复健计划][紫书]Chapter 7 暴力求解法

7.1 简单枚举 例7-1 Division uva725 输入正整数n&#xff0c;按从小到大的顺序输出所有形如abcde/fghij n的表达式&#xff0c;其中a&#xff5e;j恰好为数字0&#xff5e;9的一个排列&#xff08;可以有前导0&#xff09;&#xff0c;2≤n≤79。枚举fghij&#xff0c;验证a…

【测试工具篇一】全网最强保姆级教程抓包工具Fiddler(2)

本文接上篇Fiddler介绍&#xff0c;开始讲fiddler如何使用之前&#xff0c;给大家讲讲http以及web方面的小知识&#xff0c;方便大家后面更好得理解fiddler使用。 目录 一、软件体系结构---B/S与C/S架构 B/S架构 C/S架构 二、HTTP基础知识 什么是http请求和响应? http协…

如何基于pdf2image实现pdf批量转换为图片

最近为了将pdf报告解析成为文本和图片&#xff0c;需要将大量多页的pdf文件拆分下单独的一页一页的图像&#xff0c;以便后续进行OCR和图像处理&#xff0c;因此就需要实现将pdf2image&#xff0c;本文主要结合开源的pdf2image和poppler&#xff0c;实现了pdf转换为png格式图片…

【Linux】Linux下查看cpu信息指令(top/mpstat/iostat/pidstat)说明

top命令 top(1) - Linux manual page (man7.org) top查看总的CPU利用率 us: 用户空间消耗的CPU资源占比&#xff0c;进程在用户态执行函数调用&#xff0c;编解码消耗的都是us sy: 内核空间消耗的CPU资源占比&#xff0c;进程调用系统调用达到内核后会增加sy的消耗 ni&…

Java学习者的福音:SpringBoot教学辅助平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理教学辅助平台的相关信息成为必然。开发合适…

csrf令牌

csrf get请求 路由 // index.php Route::get(/, function () {// return view(welcome);return view(login); });Route::get(d3,function(Request $request){echo "输入的内容是" . "<font color>".$request -> input(mytext)."</fon…

高校实验室安全巡检系统设计与实现(源码+定制+开发)高校实验室巡检系统、实验室安全管理平台、实验室安全监控系统、智能实验室巡查系统、高校实验室风险管理

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

容器内pip安装Apache Airflow的经历:如何重置初始密码

背景 Apache Airflow™https://github.com/apache/airflow 是一个开源平台&#xff0c;用于开发、调度和监控面向批处理的工作流程。Airflow 可扩展的 Python 框架使您能够构建几乎可以连接任何技术的工作流程。Web 界面有助于管理工作流程的状态。Airflow 可以通过多种方式部…

微服务透传日志traceId

问题 在微服务架构中&#xff0c;一次业务执行完可能需要跨多个服务&#xff0c;这个时候&#xff0c;我们想看到业务完整的日志信息&#xff0c;就要从各个服务中获取&#xff0c;即便是使用了ELK把日志收集到一起&#xff0c;但如果不做处理&#xff0c;也是无法完整把一次业…

精心整理教育研究专题数据资源大全-最新出炉_附下载链接

教育研究专题数据资源大全V1.0 下载链接-点它&#x1f449;&#x1f449;&#x1f449;&#xff1a;教育研究专题数据资源大全-最新出炉.zip 资源介绍 一、中国教育统计年鉴面板数据 简介&#xff1a;《中国教育统计年鉴》是由教育部发展规划司根据全国各省、自治区、直辖市…

汽修行业员工培训SOP的智能化搭建

汽修行业正经历着技术革新和服务模式的双重变革&#xff0c;员工的专业培训变得尤为重要。智能化的员工培训标准操作程序&#xff08;SOP&#xff09;在线知识库不仅能够提升培训效率&#xff0c;还能确保服务质量和作业安全。本文将探讨汽修行业如何智能化地搭建员工培训的SOP…

还在担心Mac卸载不干净?XApp帮你干净完成卸载

Mac的卸载机制非常独特&#xff0c;虽然将app拖拽到废纸篓也能够完成卸载&#xff0c;但是会有很多的文件残留&#xff0c;那么如何卸载干净非常重要 XApp&#xff0c;免费的Mac卸载工具&#xff0c;有着强大的垃圾检测机制&#xff0c;检测出更深层的垃圾&#xff0c;卸载更干…

游戏测试之浅谈测试思维

一、游戏测试与软件测试的区别 1、测试目标 软件测试&#xff1a;主要目标是确保软件在功能、性能、安全性等方面达到预期质量标准。关注点主要是软件的正确性、稳定性、安全性和效率。 游戏测试&#xff1a;不仅关注游戏的功能性和稳定性&#xff0c;还要关注游戏的体验性、平…

为什么Uptime+Kuma本地部署与远程使用是网站监控新选择?

文章目录 前言1.关于Uptime Kuma2.安装Docker3.本地部署Uptime Kuma4.使用Uptime Kuma5.cpolar内网穿透工具安装6.创建远程连接公网地址7.固定Uptime Kuma公网地址 前言 本篇文章介绍如何在本地部署Uptime Kuma&#xff0c;并结合cpolar内网穿透实现公网远程访问。 说起网站相…

使用Python创建自助抢单插件的完整指南

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…