6. RabbitMQ 死信队列的详细操作编写

6. RabbitMQ 死信队列的详细操作编写

文章目录

  • 6. RabbitMQ 死信队列的详细操作编写
  • 1. 死信的概念
  • 2. 消息 TTL 过期(触发死信队列)
  • 3. 队列超过队列的最大长度(触发死信队列)
  • 4. 消息被拒(触发死信队列)
  • 5. 最后:


1. 死信的概念

先从概念上解释上搞清楚这个定义,死信,顾名思义就是无法被消费者读取/消费的消息 。字面意思可以这样理解,一般来说,producer 将消息投递到 broker 或者直接到 queue 里了,consumer 从 queue 取出消息进行消费,但某些时候由于特定的原因导致 queue 中的某些消息无法被消费 ,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有与之对应的 ——> 死信队列

应用场景: 为了保证订单业务的消息数据不丢失,需要使用到 RabbitMQ 的死信队列机制,当消息消费发生异常时,将消息投入死信队列中,还有比如说:用户在商城下单成功并点击去支付后,在指定时候未支付时,自动失效。

死信的来源: (死信的常见方式,大概时如下三种方式:)

  1. 消息的 TTL 过期。
  2. 队列达到最大长度(队列满了,无法再添加数据到 RabbitMQ 当中了)
  3. 当消息被拒绝(basic.reject 或 basic.nack) 并且 requeue = fasle

在这里插入图片描述

死信的实战案例:

2. 消息 TTL 过期(触发死信队列)

生产者代码

在这里插入图片描述

package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.concurrent.TimeoutException;/*** 死信队列——> 生产者代码*/
public class Producer {// 普通交换机的名称public static final String NORMAL_EXCHANGE = "normal_exchange";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 死信消息,设置 TTL时间AMQP.BasicProperties properties =new AMQP.BasicProperties().builder().expiration("10000").build();for (int i = 0; i < 11; i++) {String message = "info" + i;channel.basicPublish(NORMAL_EXCHANGE,"zhangsan",properties,message.getBytes());//channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", null, message.getBytes());}}}

消费者 C1 代码(启动之后关闭该消费者 模拟其接收不到消息)

特别说明: 配置正常队列,无法处理的队列信息,转发给死信队列的,配置,只需在该正常队列当中配置映射死信队列的信息配置即可,而死信队列就是作为一个正常的队列处理读取/消费死信队列当中的内容即可。

在这里插入图片描述

package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;/*** 死信队列-消费者1(正常队列)*/
public class Consumer01 {// 普通交换机的名称public static final String NORMAL_EXCHANGE = "normal_exchange";// 死信交换机的名称public static final String DEAD_EXCHANGE = "dead_exchange";// 普通队列的名称public static final String NORMAL_QUEUE = "normal_queue";// 死信队列的名称public static final String DEAD_QUEUE = "dead_queue";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 声明死信和普通交换机类型为 directchannel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);// 声明普通队列Map<String, Object> arguments = new HashMap<>();// 过期时间 10s = 10000ms 参数 key 是固定值的不可以随便写//arguments.put("x-message-ttl",100000);//正常队列设置死信交换机 参数 key 是固定值arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);// 设置死信RoutingKeyarguments.put("x-dead-letter-routing-key", "lisi");// 声明的是一个正常的队列channel.queueDeclare(NORMAL_QUEUE, false, false, false, arguments);//// 声明死信队列channel.queueDeclare(DEAD_QUEUE, false, false, false, null);// 绑定普通的交换机与普通的队列进行一个绑定(第一个参数是队列,第二个参数是交换机)channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "zhangsan");System.out.println("等待接收消息");// 接收消息DeliverCallback deliverCallback = (consumerTag, message) -> {System.out.println("Consumer01 正常队列接收到的消息" + new String(message.getBody(), "UTF-8"));};channel.basicConsume(NORMAL_QUEUE, true, deliverCallback, consumerTag -> {});}
}

在这里插入图片描述

消费者 C2 代码(以上步骤完成后 启动 C2 消费者 它消费死信队列里面的消息)

在这里插入图片描述

package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;/*** 死信队列-消费者1(死信队列)*/
public class Consumer02 {;// 死信交换机的名称public static final String DEAD_EXCHANGE = "dead_exchange";// 死信队列的名称public static final String DEAD_QUEUE = "dead_queue";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 声明死信和普通交换机类型为 directchannel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);// 绑定死信的交换机与死信的队列进行一个绑定(第一个参数是队列,第二个参数是交换机)channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, "lisi");// 接收消息DeliverCallback deliverCallback = (consumerTag, message) -> {System.out.println("Consumer02 死信接收到的消息" + new String(message.getBody(), "UTF-8"));};channel.basicConsume(DEAD_QUEUE, true, deliverCallback, consumerTag -> {});}
}

在这里插入图片描述

在这里插入图片描述

3. 队列超过队列的最大长度(触发死信队列)

  1. 基于上面代码:将生产者代码去掉 TTL 属性

在这里插入图片描述

package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.concurrent.TimeoutException;/*** 死信队列——> 生产者代码*/
public class Producer {// 普通交换机的名称public static final String NORMAL_EXCHANGE = "normal_exchange";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 死信消息,设置 TTL时间//AMQP.BasicProperties properties =//        new AMQP.BasicProperties()//        .builder().expiration("10000").build();for (int i = 0; i < 11; i++) {String message = "info" + i;//channel.basicPublish(NORMAL_EXCHANGE,"zhangsan",properties,message.getBytes());channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", null, message.getBytes());}}}
  1. C1 消费者修改以下代码(启动之后关闭该消费者 模拟其接收不到消息)

注意此时需要把原先队列删除 因为参数改变了,因为 RabbitMQ 不可以将一个一开始形态的队列,修改成另外一个形态的队列。所以需要删除后在创建。

在这里插入图片描述

package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;/*** 死信队列-消费者1(正常队列)*/
public class Consumer01 {// 普通交换机的名称public static final String NORMAL_EXCHANGE = "normal_exchange";// 死信交换机的名称public static final String DEAD_EXCHANGE = "dead_exchange";// 普通队列的名称public static final String NORMAL_QUEUE = "normal_queue";// 死信队列的名称public static final String DEAD_QUEUE = "dead_queue";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 声明死信和普通交换机类型为 directchannel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);// 声明普通队列Map<String, Object> arguments = new HashMap<>();// 过期时间 10s = 10000ms 参数 key 是固定值的不可以随便写//arguments.put("x-message-ttl",100000);//正常队列设置死信交换机 参数 key 是固定值arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);// 设置死信RoutingKeyarguments.put("x-dead-letter-routing-key", "lisi");// 设置正常队列的长度的限制,x-max-length参数 key 是固定值的,不可以随便写arguments.put("x-max-length",6);// 声明的是一个正常的队列channel.queueDeclare(NORMAL_QUEUE, false, false, false, arguments);//// 声明死信队列channel.queueDeclare(DEAD_QUEUE, false, false, false, null);// 绑定普通的交换机与普通的队列进行一个绑定(第一个参数是队列,第二个参数是交换机)channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "zhangsan");System.out.println("等待接收消息");// 接收消息DeliverCallback deliverCallback = (consumerTag, message) -> {System.out.println("Consumer01 正常队列接收到的消息" + new String(message.getBody(), "UTF-8"));};channel.basicConsume(NORMAL_QUEUE, true, deliverCallback, consumerTag -> {});}
}

在这里插入图片描述

同时 C1 正常队列也是读取到信息了

在这里插入图片描述

然后,启动之后关闭该消费者C1, 模拟其接收不到消息

  1. C2 消费者代码不变(启动 C2 消费者)

启动消费者 1 然后再启动消费者 2

在这里插入图片描述

package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;/*** 死信队列-消费者1(死信队列)*/
public class Consumer02 {;// 死信交换机的名称public static final String DEAD_EXCHANGE = "dead_exchange";// 死信队列的名称public static final String DEAD_QUEUE = "dead_queue";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 声明死信和普通交换机类型为 directchannel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);// 绑定死信的交换机与死信的队列进行一个绑定(第一个参数是队列,第二个参数是交换机)channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, "lisi");// 接收消息DeliverCallback deliverCallback = (consumerTag, message) -> {System.out.println("Consumer02 死信接收到的消息" + new String(message.getBody(), "UTF-8"));};channel.basicConsume(DEAD_QUEUE, true, deliverCallback, consumerTag -> {});}
}

在这里插入图片描述

在这里插入图片描述

4. 消息被拒(触发死信队列)

  1. .消息生产者代码同上生产者一致,不做修改
package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.concurrent.TimeoutException;/*** 死信队列——> 生产者代码*/
public class Producer {// 普通交换机的名称public static final String NORMAL_EXCHANGE = "normal_exchange";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 死信消息,设置 TTL时间//AMQP.BasicProperties properties =//        new AMQP.BasicProperties()//        .builder().expiration("10000").build();for (int i = 0; i < 11; i++) {String message = "info" + i;//channel.basicPublish(NORMAL_EXCHANGE,"zhangsan",properties,message.getBytes());channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", null, message.getBytes());}}}
  1. C1 消费者代码(启动之后关闭该消费者 模拟其接收不到消息) 添加上拒绝消息的操作。

注意此时需要把原先队列删除 因为参数改变了,因为 RabbitMQ 不可以将一个一开始形态的队列,修改成另外一个形态的队列。所以需要删除后在创建。

在这里插入图片描述

在这里插入图片描述

 // 接收消息DeliverCallback deliverCallback = (consumerTag, message) -> {// 获取到消息信息String msg = new String(message.getBody(), "UTF-8");if (msg.equals("info5")) {System.out.println("Consumer01 接收的消息是: " + msg + "此消息被 Consumer01 拒绝了");} else {System.out.println("Consumer01 接收的消息: " + msg);}};
package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;/*** 死信队列-消费者1(正常队列)*/
public class Consumer01 {// 普通交换机的名称public static final String NORMAL_EXCHANGE = "normal_exchange";// 死信交换机的名称public static final String DEAD_EXCHANGE = "dead_exchange";// 普通队列的名称public static final String NORMAL_QUEUE = "normal_queue";// 死信队列的名称public static final String DEAD_QUEUE = "dead_queue";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 声明死信和普通交换机类型为 directchannel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);// 声明普通队列Map<String, Object> arguments = new HashMap<>();// 过期时间 10s = 10000ms 参数 key 是固定值的不可以随便写//arguments.put("x-message-ttl",100000);//正常队列设置死信交换机 参数 key 是固定值arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);// 设置死信RoutingKeyarguments.put("x-dead-letter-routing-key", "lisi");// 设置正常队列的长度的限制,x-max-length参数 key 是固定值的,不可以随便写//arguments.put("x-max-length", 6);// 声明的是一个正常的队列channel.queueDeclare(NORMAL_QUEUE, false, false, false, arguments);//// 声明死信队列channel.queueDeclare(DEAD_QUEUE, false, false, false, null);// 绑定普通的交换机与普通的队列进行一个绑定(第一个参数是队列,第二个参数是交换机)channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "zhangsan");System.out.println("等待接收消息");// 接收消息DeliverCallback deliverCallback = (consumerTag, message) -> {// 获取到消息信息String msg = new String(message.getBody(), "UTF-8");if (msg.equals("info5")) {System.out.println("Consumer01 接收的消息是: " + msg + "此消息被 Consumer01 拒绝了");// 拒绝对应 message.getEnvelope().getDeliveryTag() 的信息channel.basicReject(message.getEnvelope().getDeliveryTag(), false);} else {System.out.println("Consumer01 接收的消息: " + msg);// 手动应答,接收消息channel.basicAck(message.getEnvelope().getDeliveryTag(), false);}};channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, consumerTag -> {});}
}
  1. C2 消费者代码不变;启动消费者 1 然后再启动消费者 2
package com.rainbowsea.rabbitmq.eight;import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;/*** 死信队列-消费者1(死信队列)*/
public class Consumer02 {;// 死信交换机的名称public static final String DEAD_EXCHANGE = "dead_exchange";// 死信队列的名称public static final String DEAD_QUEUE = "dead_queue";public static void main(String[] args) throws IOException, TimeoutException {Channel channel = RabbitMQUtils.getChannel();// 声明死信和普通交换机类型为 directchannel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);// 绑定死信的交换机与死信的队列进行一个绑定(第一个参数是队列,第二个参数是交换机)channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, "lisi");// 接收消息DeliverCallback deliverCallback = (consumerTag, message) -> {System.out.println("Consumer02 死信接收到的消息" + new String(message.getBody(), "UTF-8"));};channel.basicConsume(DEAD_QUEUE, true, deliverCallback, consumerTag -> {});}
}

在这里插入图片描述

在这里插入图片描述

总结: 上述的,消息TTL过期,队列超过最大长度,消息被拒等等这三种方式,都是让消息无法被正常消费者读取掉,由于消费者没有读取到该消息,有为了防止,该消息被丢失,所以就将其消息放入到一个死信交换机——>死信队列中 ,最后让一个死信消费者读取到保存起来,这样队列当中的消息就没有被丢失了。

特别说明: 配置正常队列,无法处理的队列信息,转发给死信队列的,配置,只需在该正常队列当中配置映射死信队列的信息配置即可,而死信队列就是作为一个正常的队列处理读取/消费死信队列当中的内容即可。

在这里插入图片描述

    // 普通交换机的名称public static final String NORMAL_EXCHANGE = "normal_exchange";// 死信交换机的名称public static final String DEAD_EXCHANGE = "dead_exchange";// 普通队列的名称public static final String NORMAL_QUEUE = "normal_queue";// 死信队列的名称public static final String DEAD_QUEUE = "dead_queue"; Channel channel = RabbitMQUtils.getChannel();// 声明死信和普通交换机类型为 directchannel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);// 声明普通队列Map<String, Object> arguments = new HashMap<>();// 过期时间 10s = 10000ms 参数 key 是固定值的不可以随便写//arguments.put("x-message-ttl",100000);//正常队列设置死信交换机 参数 key 是固定值arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);// 设置死信RoutingKeyarguments.put("x-dead-letter-routing-key", "lisi");// 设置正常队列的长度的限制,x-max-length参数 key 是固定值的,不可以随便写//arguments.put("x-max-length", 6);// 声明的是一个正常的队列channel.queueDeclare(NORMAL_QUEUE, false, false, false, arguments);//// 声明死信队列channel.queueDeclare(DEAD_QUEUE, false, false, false, null);// 绑定普通的交换机与普通的队列进行一个绑定(第一个参数是队列,第二个参数是交换机)channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "zhangsan");System.out.println("等待接收消息");

5. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

在这里插入图片描述

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

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

相关文章

如何使用Selenium进行自动化测试?

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 对于很多刚入门的测试新手来说&#xff0c;大家都将自动化测试作为自己职业发展的一个主要阶段。可是&#xff0c;在成为一名合格的自动化测试工程师之前&#…

洛谷题单3-P5724 【深基4.习5】求极差 最大跨度值 最大值和最小值的差-python-流程图重构

题目描述 给出 n n n 和 n n n 个整数 a i a_i ai​&#xff0c;求这 n n n 个整数中的极差是什么。极差的意思是一组数中的最大值减去最小值的差。 输入格式 第一行输入一个正整数 n n n&#xff0c;表示整数个数。 第二行输入 n n n 个整数 a 1 , a 2 … a n a_1,…

STM32智能手表——任务线程部分

RTOS和LVGL我没学过&#xff0c;但是应该能硬啃这个项目例程 ├─Application/User/Tasks # 用于存放任务线程的函数 │ ├─user_TaskInit.c # 初始化任务 │ ├─user_HardwareInitTask.c # 硬件初始化任务 │ ├─user_RunModeTasks.c…

ubuntu22.04LTS设置中文输入法

打开搜狗网址直接下载软件&#xff0c;软件下载完成后&#xff0c;会弹出安装教程说明书。 网址:搜狗输入法linux-首页搜狗输入法for linux—支持全拼、简拼、模糊音、云输入、皮肤、中英混输https://shurufa.sogou.com/linux

SQL Server数据库异常-[SqlException (0x80131904): 执行超时已过期] 操作超时问题及数据库日志已满的解决方案

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;获得2024年博客之星荣誉证书&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开发技术&#xff0c…

php8 ?-> nullsafe 操作符 使用教程

简介 PHP 8 引入了 ?->&#xff08;Nullsafe 操作符&#xff09;&#xff0c;用于简化 null 检查&#xff0c;减少繁琐的 if 语句或 isset() 代码&#xff0c;提高可读性。 ?-> Nullsafe 操作符的作用 在 PHP 7 及以下&#xff0c;访问对象的属性或方法时&#xff0…

WORD+VISIO输出PDF图片提高清晰度的方法

WORDVISIO输出PDF图片提高清晰度的方法 part 1: visio 绘图part 2: word 导出 part 1: visio 绘图 先在visio中把图片和对应的文字调整为适合插入到文章中的尺寸&#xff1b; 在visio中把所有元素进行组合&#xff1b; 把组合后的图片长和宽等比例放缩&#xff0c;如放大10倍…

重要头文件下的函数

1、<cctype> #include<cctype>加入这个头文件就可以调用以下函数&#xff1a; 1、isalpha(x) 判断x是否为字母 isalpha 2、isdigit(x) 判断x是否为数字 isdigit 3、islower(x) 判断x是否为小写字母 islower 4、isupper(x) 判断x是否为大写字母 isupper 5、isa…

基于大模型预测不稳定性心绞痛的多维度研究与应用

目录 一、引言 1.1 研究背景与意义 1.2 研究目的 1.3 国内外研究现状 二、不稳定性心绞痛概述 2.1 定义与分类 2.2 发病机制 2.3 临床表现 三、大模型技术原理与应用基础 3.1 大模型介绍 3.2 在医疗领域的应用现状 3.3 用于不稳定性心绞痛预测的可行性 四、术前预…

第一讲—函数的极限与连续(一)

思维导图 笔记 双曲正弦函数及其反函数

Mac VM 卸载 win10 安装win7系统

卸载 找到相应直接删除&#xff08;移动到废纸篓&#xff09; 可参考&#xff1a;mac如何卸载虚拟机win 下载 win7下载地址

免费送源码:Java+SSM+Android Studio 基于Android Studio游戏搜索app的设计与实现 计算机毕业设计原创定制

摘要 本文旨在探讨基于SSM框架和Android Studio的游戏搜索App的设计与实现。首先&#xff0c;我们详细介绍了SSM框架&#xff0c;这是一种经典的Java Web开发框架&#xff0c;由Spring、SpringMVC和MyBatis三个开源项目整合而成&#xff0c;为开发企业级应用提供了高效、灵活、…

网络安全的现状与防护措施

随着数字化和信息化的迅猛发展&#xff0c;互联网已成为人们日常生活、工作和学习不可或缺的一部分。然而&#xff0c;随着网络技术的普及&#xff0c;网络安全问题也日益突出。近年来&#xff0c;数据泄露、恶意软件、网络攻击等事件层出不穷&#xff0c;给企业和个人带来了巨…

android databinding使用教程

Android DataBinding 是一种可以将 UI 组件与数据源绑定的框架&#xff0c;能够减少 findViewById 的使用&#xff0c;并提高代码的可维护性。下面是 DataBinding 的完整使用教程&#xff1a; 1. 启用 DataBinding 在 build.gradle&#xff08;Module 级别&#xff09;中启用 …

python如何快速删除文件夹中的大量文件

在 Python 中&#xff0c;删除文件夹中的大量小图片文件可以通过使用 os 模块或 shutil 模块来实现。以下是一个示例代码&#xff0c;展示了如何快速删除指定文件夹中的所有文件。如果你只需要删除小图片文件&#xff0c;可以添加额外的逻辑来检查文件大小。 以下是一个示例代…

如何使用 IntelliJ IDEA 开发命令行程序(或 Swing 程序)并手动管理依赖(不使用 pom.xml)

以下是详细步骤&#xff1a; 1. 创建项目 1.1 打开 IntelliJ IDEA。 1.2 在启动界面&#xff0c;点击 Create New Project&#xff08;创建新项目&#xff09;。 1.3 选择 Java&#xff0c;然后点击 Next。 1.4 确保 Project SDK 选择了正确的 JDK 版本&#x…

FastAPI-Cache2: 高效Python缓存库

FastAPI-Cache2是一个强大而灵活的Python缓存库&#xff0c;专为提升应用性能而设计。虽然其名称暗示与FastAPI框架的紧密集成&#xff0c;但实际上它可以在任何Python项目中使用&#xff0c;为开发者提供简单而高效的缓存解决方案。 在现代应用开发中&#xff0c;性能优化至关…

android开发:zxing-android-embedded竖屏扫描功能

Android 点击按钮调用竖屏二维码扫描 提示&#xff1a;zxing-android-embedded插件已过时&#xff0c;建议更换别的。 场景&#xff1a;Home页面上有个扫描按钮&#xff0c;点击后打开摄像头完成扫描功能&#xff0c;扫描时要求竖屏。 方案&#xff1a;使用zxing-android-embe…

指令补充+样式绑定+计算属性+监听器

一、指令补充 1. 指令修饰符 1. 作用: 借助指令修饰符, 可以让指令更加强大 2. 分类: 1> 按键修饰符: 用来检测用户的按键, 配合键盘事件使用. keydown 和 keyup 语法: keydown.enter/v-on:keydown.enter 表示当enter按下的时候触发 keyup.enter/v-on:keyup.enter 表示当…

Python基于时间序列分析的降雨量预测系统的设计与实现【附源码、文档说明】

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…