spring-boot对rabbitMQ的操作

news2024/12/24 10:26:24

一、安装rabbitMQ

  • 1、直接使用docker拉取镜像

    docker pull rabbitmq:3.8
    
  • 2、启动容器

    docker run \
     -e RABBITMQ_DEFAULT_USER=admin \
     -e RABBITMQ_DEFAULT_PASS=123456 \
     -v mq-plugins:/plugins \
     --name rabbit01 \
     --hostname rabbit01 --restart=always \
     -p 15672:15672 \
     -p 5672:5672 \
     -d \
     rabbitmq:3.8
    
  • 3、关于端口的介绍

    • 15672的给浏览器控制台使用的
    • 5672是给程序调用的
  • 4、进入到rabbit01容器中

    docker exec -it rabbit01 /bin/bash
    
  • 5、开启可视化界面操作

    rabbitmq-plugins enable rabbitmq_management
    
  • 6、客户端直接访问xx:15672

  • 7、或者直接用别人搞好的镜像

    docker run \
     -e RABBITMQ_DEFAULT_USER=admin \
     -e RABBITMQ_DEFAULT_PASS=123456 \
     -v mq-plugins:/plugins \
     --name rabbit02 \
     --hostname rabbit02 --restart=always \
     -p 15672:15672 \
     -p 5672:5672 \
     -d \
     rabbitmq:3.8-management
    

二、在spring-boot中整合

  • 1、引入依赖包

    <!--   spring boot和junit整合单元测试包     -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!--   rabbitmq的包引入     -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    
  • 2、在配置文件中引入配置

    server.port=8000
    spring.rabbitmq.host=localhost
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=admin
    spring.rabbitmq.password=123456
    spring.rabbitmq.virtual-host=/
    

三、简单模式

  • 1、简单模式就是一个生产者一个消费者

  • 2、生产者代码,运行下面的代码,查看可视化界面,并不存在消息,原因是因为需要手动创建simple_queue这个队列

    @SpringBootTest(classes = ProducerApplication.class)
    public class ProducerTest01 {
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        @Test
        public void test01() {
            /**
             * 第一个参数:表示队列的名称
             * 第二个参数:表示要发送的数据
             */
            rabbitTemplate.convertAndSend("simple_queue", "hello world");
        }
    }
    
  • 3、运行后查看可视化界面

    在这里插入图片描述

  • 4、定义一个消费者来消费消息

    package com.example.listener01;
    
    import org.springframework.amqp.core.Message;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ConsumerListener01 {
        @RabbitListener(queues = "simple_queue")
        public void listener01(Message message) {
            String msg = new String(message.getBody());
            System.out.println("接收到的消息:" + msg);
        }
    }
    

四、work工作模式

  • 1、简单的来理解,就是在上面简单模式下增加几个消费者,如同搬砖一样的,一个搬运工搬不过来,多叫几个人来干活的性质,避免消息堆积

  • 2、同样的要先手动创建队列,在生产者端循环发送数据

    @Test
    public void test02() {
        for (int i = 0; i < 10; i++) {
            rabbitTemplate.convertAndSend("work_queue", "hello world");
        }
    }
    
  • 3、定义2个消费者来一起消费消息

    @Component
    public class ConsumerListener01 {
        @RabbitListener(queues = "work_queue")
        public void listener01(Message message) {
            String msg = new String(message.getBody());
            System.out.println("消费者1接收到的消息:" + msg);
        }
    }
    
  • 4、先运行消费者,然后运行生产者

    在这里插入图片描述

五、发布模式

  • 1、发布模式是指发送一个消息,希望在几个消费者那边都能接收到,上面的工作模式,一条消息被一个消费者消费了,另外一个消费者就接收不到消息,在一些场景需要给每个消费者就要用发布者模式
  • 2、根据交换机的模式可以分为以下几种
    • Fanout,广播模式,将消息全部交给所有与之绑定的队列,这里的router key为空字符串
    • Direct,将消息指定到对应的routing key
    • Topic,通配符模式,这里的routing key根据规则匹配
      • *表示一个单词
      • #表示多个单词
一、Fanout模式
  • 1、使用配置文件的方式创建交换机和队列,并且将他们绑定在一起

    package com.example.config;
    
    import org.springframework.amqp.core.*;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class RabbitFanoutExchangeConfiguration {
        // 交换机
        @Bean
        public Exchange fanoutExchange() {
            return ExchangeBuilder.fanoutExchange("fanout_exchange").durable(true).build();
        }
    
        // 创建一个队列
        @Bean
        public Queue fanoutQueue1() {
            return QueueBuilder.durable("fanout_queue1").build();
        }
    
        // 创建一个队列
        @Bean
        public Queue fanoutQueue2() {
            return QueueBuilder.durable("fanout_queue2").build();
        }
    
        // 队列和交换机绑定
        @Bean
        public Binding fanoutExchangeQueue01() {
            // with表示路由key
            return BindingBuilder.bind(fanoutQueue1()).to(fanoutExchange()).with("").noargs();
        }
    
        @Bean
        public Binding fanoutExchangeQueue02() {
            // with表示路由key
            return BindingBuilder.bind(fanoutQueue2()).to(fanoutExchange()).with("").noargs();
        }
    }
    
  • 2、生产者发送消息

    @Test
    public void test03() {
        rabbitTemplate.convertAndSend("fanout_exchange", "", "hello world");
    }
    
  • 3、查看可视化界面,会自动创建一个交换机和两个路由key

    在这里插入图片描述

  • 4、定义消费者

    @Component
    public class ConsumerListener01 {
        @RabbitListener(queues = "fanout_queue1")
        public void listener01(Message message) {
            String msg = new String(message.getBody());
            System.out.println("消费者1接收到的消息:" + msg);
        }
    }
    
  • 5、这时候会发现,几个消费者都会同时输出

二、Direct模式
  • 1、其实就是在上面的模式上修改创建交换机的类型,及指定类型,别的都保持不变
三、Topic模式
  • 1、在定义路由key的时候使用*或者#来表示

六、直接在监听上使用注解的方式来创建交换机等

  • 1、正常创建交换机和队列的方式有三种方式

    • 直接在可视化界面手动创建
    • 使用java api方式一个一个创建需要先创建交换机、队列,并且让队列和交换机绑定在一起
    • 直接使用注解的方式来实现
  • 2、使用注解的方式直接来创建交换机和队列

    package com.example.listener04;
    
    import org.springframework.amqp.core.ExchangeTypes;
    import org.springframework.amqp.core.Message;
    import org.springframework.amqp.rabbit.annotation.Exchange;
    import org.springframework.amqp.rabbit.annotation.Queue;
    import org.springframework.amqp.rabbit.annotation.QueueBinding;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ConsumerListener01 {
        @RabbitListener(bindings = @QueueBinding(
                value = @Queue(value = "queue_01", durable = "true"),
                exchange = @Exchange(value = "direct_rabbit_exchange", type = ExchangeTypes.DIRECT),
                key = {"info", "error"}
        ))
        public void listener01(Message message) {
            String msg = new String(message.getBody());
            System.out.println("消费者1接收到的消息:" + msg);
        }
    }
    
  • 3、运行后查看rabbitmq可视化界面

  • 4、定义发送消息的方法

    public void test04() {
        rabbitTemplate.convertAndSend("direct_rabbit_exchange","error","hello world");
    }
    

七、消息丢失

  • 1、消息丢失主要存在的场景
    • 生产者投递消息的时候就丢失,比如写错了交换机的名字
    • 交换机到队列丢失,比如写错了队列名称
    • 队列到接收者数据丢失
一、开启生产者确认机制
  • 1、开启生产者确认机制

    server.port=9000
    spring.rabbitmq.host=123.56.103.229
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=admin
    spring.rabbitmq.password=123456
    spring.rabbitmq.virtual-host=/
    # 开启生产者确认机制
    spring.rabbitmq.publisher-confirm-type=correlated 
    
  • 2、重写RabbitTemplate,只要我们在容器中有一个RabbitTemplate,那么spring boot就不会用对RabbitTemplate自动化配置

    package com.example.config;
    
    import org.springframework.amqp.rabbit.connection.ConnectionFactory;
    import org.springframework.amqp.rabbit.connection.CorrelationData;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class RabbitmqConfiguration {
        /**
         * ConnectionFactory 由于Spring Boot根据连接的配置信息实现自动化配置,在spring容器中是直接存在ConnectionFactory对象
         */
        @Bean
        public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
            RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
            rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){
    
                @Override
                public void confirm(CorrelationData correlationData, boolean ack, String s) {
                    if (ack) {
                        System.out.println("消息正常投递到交换机中");
                    } else {
                        System.out.println("消息投递到交换机失败:"+s);
                    }
                }
            });
            return rabbitTemplate;
        }
    
    }
    
  • 3、发送消息的时候故意写错交换机的名字

    @Test
    public void test04() throws InterruptedException {
        rabbitTemplate.convertAndSend("direct_rabbit_exchange_xx","error","hello world");
        Thread.sleep(2000);
    }
    
  • 4、处理消息投送失败的方式

    • 使用数据库表来保存发送失败的消息,主要字段有:消息唯一id、消息内容、重试次数、当前消息发送状态
    • 在消息投送失败的时候重试几次
    • 定时任务将失败的批量再次发送
  • 5、在发送消息的时候传递当前唯一的识别id,这里使用uuid

    @Test
    public void test04() throws InterruptedException {
        String msgUuid = UUID.randomUUID().toString().replace("-", "");
        CorrelationData correlationData = new CorrelationData(msgUuid);
        rabbitTemplate.convertAndSend("direct_rabbit_exchange", "error", "hello world", correlationData);
        Thread.sleep(2000);
    }
    
  • 6、获取当前消息的唯一识别

    @Configuration
    public class RabbitmqConfiguration {
        /**
         * ConnectionFactory 由于Spring Boot根据连接的配置信息实现自动化配置,在spring容器中是直接存在ConnectionFactory对象
         */
        @Bean
        public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
            RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
            rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){
    
                @Override
                public void confirm(CorrelationData correlationData, boolean ack, String s) {
                    if (ack) {
                        System.out.println("消息正常投递到交换机中");
                    } else {
                        String mesId = correlationData.getId();
                        System.out.println(mesId);
                        System.out.println("消息投递到交换机失败:"+s);
                    }
                }
            });
            return rabbitTemplate;
        }
    }
    
二、交换机到队列的时候出现问题
  • 1、当队列名称写错了,或者不存在的时候会出现这个情况

  • 2、开启生产者回调机制

    server.port=9000
    spring.rabbitmq.host=123.56.103.229
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=admin
    spring.rabbitmq.password=123456
    spring.rabbitmq.virtual-host=/
    # 开启生产者确认机制
    spring.rabbitmq.publisher-confirm-type=correlated
    # 开启生产者回调机制
    spring.rabbitmq.publisher-returns=true
    
  • 3、绑定回退函数

    package com.example.config;
    
    import org.springframework.amqp.core.ReturnedMessage;
    import org.springframework.amqp.rabbit.connection.ConnectionFactory;
    import org.springframework.amqp.rabbit.connection.CorrelationData;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class RabbitmqConfiguration {
        /**
         * ConnectionFactory 由于Spring Boot根据连接的配置信息实现自动化配置,在spring容器中是直接存在ConnectionFactory对象
         */
        @Bean
        public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
            RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
            ...
            // 绑定回退机制的回调函数
            rabbitTemplate.setMandatory(true);
            rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
    
                @Override
                public void returnedMessage(ReturnedMessage returnedMessage) {
                    System.out.println(returnedMessage.getMessage());
                    System.out.println(returnedMessage.getReplyCode());
                    System.out.println(returnedMessage.getReplyText());
                    System.out.println(returnedMessage.getExchange());
                    System.out.println(returnedMessage.getRoutingKey());
                }
            });
            return rabbitTemplate;
        }
    }
    
    
三、消息持久化
  • 1、rabbitmq默认是在内存中存储,当服务宕机后数据直接会丢失,消息在spring boot中持久化是因为框架帮你处理了,修改消息是否持久化可以参考下面

    @Test
    public void test04() throws InterruptedException {
        String msgUuid = UUID.randomUUID().toString().replace("-", "");
        CorrelationData correlationData = new CorrelationData(msgUuid);
        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
    
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                MessageProperties messageProperties = message.getMessageProperties(); // 获取到消息属性对象
                messageProperties.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT); // 设置消息不缓存
                return message;
            }
        };
        rabbitTemplate.convertAndSend("direct_rabbit_exchange", "error", "hello world",messagePostProcessor, correlationData);
        Thread.sleep(2000);
    }
    
四、消费者消费消息不丢失
  • 1、在spring boot中消费者应答模式主要有以下几种

    • none自动应答,消费者获取到消息以后直接给rabbitmq返回ack
    • auto(默认模式),由spring boot框架根据业务执行特点决定给rabbitmqack还是uack,业务执行正常完成后返回ack,业务执行中出现异常的时候返回uack
    • manual手动应答模式,由程序员自己根据业务执行特点给rabbitmq返回对应的ack还是uack
  • 2、配置应答模式

    server.port=8000
    spring.rabbitmq.host=123.56.103.229
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=admin
    spring.rabbitmq.password=123456
    spring.rabbitmq.virtual-host=/
    # 配置应答模式
    spring.rabbitmq.listener.simple.acknowledge-mode=auto
    
八、消费限流
  • 1、在消费者端添加配置

    server.port=8000
    spring.rabbitmq.host=123.56.103.229
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=admin
    spring.rabbitmq.password=123456
    spring.rabbitmq.virtual-host=/
    spring.rabbitmq.listener.simple.acknowledge-mode=auto
    # 每次处理10个
    spring.rabbitmq.listener.simple.prefetch=10
    

九、死信队列

  • 1、在下面几种情况下会产生死信队列

    • 消息的存活时间到了
    • 队列满了,比如队列只能放10个消息,这时候发送11个消息过来,就有一个消息为死信,在队列中时间最久的那个将为成为死信队列
    • 消费被拒绝了,或者rabbitmq返回uack
  • 2、死信队列的架构图

    在这里插入图片描述

  • 3、创建死信队列

    package com.example.config;
    
    import org.springframework.amqp.core.*;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class RabbitDlxExchangeConfiguration {
        // 创建一个死信交换机
        @Bean
        public Exchange dlxExchange() {
            return ExchangeBuilder.fanoutExchange("dlx_exchange").durable(true).build();
        }
    
        // 创建一个死信队列
        @Bean
        public Queue dlxQueue() {
            return QueueBuilder.durable("dlx_queue").maxLength(10).build();
        }
    
        // 死信交换机和死信队列绑定
        @Bean
        public Binding dlxQueueBinding() {
            return BindingBuilder.bind(dlxQueue()).to(dlxExchange()).with("dead").noargs();
        }
    
        // 创建一个正常的交换机
        @Bean
        public Exchange orderExchange() {
            return ExchangeBuilder.directExchange("order_exchange").durable(true).build();
        }
    
        // 创建一个正常队列
        @Bean
        public Queue orderQueue() {
            return QueueBuilder.durable("order_queue").
                    maxLength(10).
                    deadLetterExchange("dlx_exchange"). // 死信队列的交换机
                    deadLetterRoutingKey("dead"). // 死信队列的routingKey
                    build();
        }
    
        // 正常交换机和正常队列绑定
        @Bean
        public Binding orderQueueBinding() {
            return BindingBuilder.bind(orderQueue()).to(orderExchange()).with("info").noargs();
        }
    }
    
  • 4、发送消息

    @Test
    public void test05() throws InterruptedException {
        for (int i = 0; i < 15; i++) {
            rabbitTemplate.convertAndSend("order_exchange", "info", "hello world" + i);
        }
        Thread.sleep(2000);
    }
    
  • 5、查看可视化界面,进入死信队列的是时间最早的(也就是最先发送的)

    在这里插入图片描述

  • 6、定义消费者

    package com.example.listener05;
    
    import org.springframework.amqp.core.Message;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ConsumerListener01 {
        @RabbitListener(queues = "dlx_queue")
        public void listener01(Message message) {
            String msg = new String(message.getBody());
            System.out.println("接收到的死信队列消息:" + msg);
        }
    
        @RabbitListener(queues = "order_queue")
        public void listener02(Message message) {
            String msg = new String(message.getBody());
            System.out.println("接收到的订单队列消息:" + msg);
        }
    }
    

十、延迟任务

  • 1、在rabbitmq中没有真正意义上的延迟队列任务,只是采用ttl+死信队列来完成的

  • 2、延迟任务主要用于场景

    • 文章定时发布
    • 订单多少分钟后取消支付
  • 3、延迟任务的结构图

    在这里插入图片描述

  • 4、创建一个延迟任务的队列

    @Configuration
    public class RabbitDlxExchangeConfiguration {
        ...
        @Bean
        public Queue orderQueue() {
            return QueueBuilder.durable("order_queue").
                    // maxLength(10).
                    ttl(2000). // 过期时间
                    deadLetterExchange("dlx_exchange"). // 死信队列的交换机
                    deadLetterRoutingKey("dead"). // 死信队列的routingKey
                    build();
        }
    }
    
  • 5、发送消息,观察可视化界面,时间到了就会进入到死信队列中

    @Test
    public void test06() throws InterruptedException {
        rabbitTemplate.convertAndSend("order_exchange", "info", "hello world");
        Thread.sleep(2000);
    }
    
  • 6、在死信队列中监听数据来改变数据库状态

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

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

相关文章

在微服务架构中的数据一致性

当从传统的单体应用架构转移到微服务架构时&#xff0c;特别是涉及数据一致性时&#xff0c;数据一致性是微服务架构中最困难的部分。传统的单体应用中&#xff0c;一个共享的关系型数据库负责处理数据一致性。在微服务架构中&#xff0c;如果使用“每个服务一个数据库”的模式…

碧莲盛 x Tapdata:实时数据如何赋能医疗美容行业,助力医疗决策及个性化服务升级

使用 Tapdata&#xff0c;化繁为简&#xff0c;轻量代替 OGG、DSG 这样的同步工具&#xff0c;以及 Kettle、Informatica、Python 这样的 ETL 工具或脚本&#xff0c;帮助企业在五花八门的数据需求面前&#xff0c;实现“做且仅做最后一次 ETL”的目标&#xff0c;这绝非纸上谈…

TIME_WAIT状态TCP连接导致套接字无法重用实验

理论相关知识可以看一下《TIME_WAIT相关知识》。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #include<errno.h> #include<syslog.h> #inc…

API接口测试工具的主要作用及选择指南

API接口测试是现代软件开发中至关重要的一环。为了确保不同组件之间的无缝集成和功能正常运作&#xff0c;API接口测试工具应运而生。本文将介绍API接口测试工具的主要作用&#xff0c;以及在选择适合项目的工具时需要考虑的因素。 1、功能测试&#xff1a;API接口测试工具的首…

基于Python+requests编写的自动化测试项目-实现流程化的接口串联

框架产生目的&#xff1a;公司走的是敏捷开发模式&#xff0c;编写这种框架是为了能够满足当前这种发展模式&#xff0c;用于前后端联调之前&#xff08;后端开发完接口&#xff0c;前端还没有将业务处理完毕的时候&#xff09;以及日后回归阶段&#xff0c;方便为自己腾出学(m…

Stable Diffusion绘画系列【3】:二次元动漫画风

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

C语言——求π的近似值

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> #include<math.h> int main() {int s;double n,t,pi;t1;pi0;n1.0;s1;while (fabs(t)>1e-6){pipit; nn2; s-s; ts/n;}pipi*4;printf("pi%lf\n",pi);return 0; }这里是求小数点后6位——1e-6&#…

漏洞环境靶场搭建(内含DVWA SQLi-LABS upload-labs等)

一、docker环境搭建(以redhat8为例&#xff0c;centos7命令基本一致) 1、安装docker yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin 2、启动docker systemctl start docker 3、配置镜像加速 vim /etc/docker/daemon.json {"registr…

Linux下基于MPI的hello程序设计

Linux下基于MPI的hello程序设计 一、MPICH并行计算库安装实验环境部署创建SSH信任连接&#xff0c;实现免密钥互相连接node1安装MPICH 3.4配置NFS注意(一定要先看)环境测试 二、HELLO WORLD并行程序设计 一、MPICH并行计算库安装 在Linux环境下安装MPICH执行环境&#xff0c;配…

Photoshop Elements 2023 v21.0(ps简化版)

Photoshop Elements 2023是一款ps简化版图像处理软件&#xff0c;它加入了一些新的功能和工具&#xff0c;以帮助用户更高效地处理图片。 新功能&#xff1a;软件加入了黑科技&#xff0c;采用Adobe Sensei AI技术&#xff0c;主打人工智能&#xff0c;一键P图&#xff0c;新增…

tabs切换,当点击tabItem时候,改变选中样式,以及content内容区域

效果图展示&#xff1a; html原生代码&#xff1a; <div><div class"buttons-row nav-select riskType" style"padding: 10px;"><div class"shoucang-title-box flex-start"><div class"shoucang-title-item active&q…

Django回顾【二】

目录 一、Web框架 二、WSGI协议 三、 Django框架 1、MVC与MTV模型 2、Django的下载与使用 补充 3、启动django项目 补充 5、 Django请求生命周期 四、路由控制 1、路由是什么&#xff1f; 2、如何使用 3、path详细使用 4、re_path详细使用 5、反向解析 6、路由…

The Sandbox 与 Shemaroo Entertainment 达成合作,将宝莱坞标杆作品带入元宇宙

我们非常高兴地宣布与印度领先的媒体和娱乐集团 Shemaroo Entertainment 建立合作伙伴关系。BharatBox 是全新的文化元宇宙中心&#xff0c;将展示印度娱乐业的知名艺术家和品牌。该项目标志着 Shemaroo 将逐步涉足数字领域&#xff0c;将电影传统与最先进的技术相结合&#xf…

算法之插入排序及希尔排序(C语言版)

我们来实现上述排序 一.插入排序. 当插入第i(i>1)个元素时&#xff0c;前面的array[0],array[1],.,array[i-1]已经排好序&#xff0c;此时用array[i的排序码与array[i-1]array[i-2].的排序码顺序进行比较&#xff0c;找到插入位置即将arrayU插入&#xff0c;原来位置上的元…

【小布_ORACLE】Part11-1--RMAN Backups笔记

Oracle的数据备份于恢复RMAN Backups 学习第11章需要掌握&#xff1a; 一.RMAN的备份类型 二.使用backup命令创建备份集 三.创建备份文件 四.备份归档日志文件 五.使用RMAN的copy命令创建镜像拷贝 文章目录 Oracle的数据备份于恢复RMAN Backups1.RMAN Backup Concepts&#x…

安卓开发学习---kotlin版---笔记(一)

Hello word 前言&#xff1a;上次学习安卓&#xff0c;学了Java开发&#xff0c;简单的搭了几个安卓界面。这次要学习Kotlin语言&#xff0c;然后开发安卓&#xff0c;趁着还年轻&#xff0c;学点新东西&#xff0c;坚持~ 未来的你会感谢现在努力的你~ 主要学习资料&#xff1a…

使用Python进行帧提取及指定帧插入实现文本隐写(CTF杂项出题方向)

视频是由一系列连续的图像帧组成的&#xff0c;每一帧都是视频的静止画面。这些帧以一定的速率播放&#xff0c;就形成了运动的视频。以下是视频帧的一些基本概念&#xff1a; 帧率&#xff08;Frame Rate&#xff09;&#xff1a; 帧率表示每秒播放的图像帧数量。通常以“帧/秒…

性能自动化测试?

一、思考❓❔ 1.什么是性能自动化测试? 性能 系统负载能力超负荷运行下的稳定性系统瓶颈 自动化测试 使用程序代替手工提升测试效率性能自动化 使用代码模拟大批量用户让用户并发请求多页面多用户并发请求采集参数&#xff0c;统计系统负载能力生成报告 2.Python中的性能…

【JavaEE初阶】——Linux 基本使用和 web 程序部署(下)

文章目录 前言一、Linux 常用命令 1.1 ls 命令 1.2 pwd 命令 1.3 cd 命令 1.4 touch 命令 1.5 cat 命令 1.6 mkdir 命令 1.7 rm 命令 1.8 cp 命令 1.9 mv 命令 1.10 man 命令 1.11 less 命令 1.12 head 命令 1.13 tail 命…

leetcode LCR24反转单链表

反转单链表 题目描述 题目分析 先来说迭代的思想&#xff1a; 上面next cur->next应该放在cur->next pre前面执行&#xff0c;这里笔误 再来说递归的思想&#xff1a; 题目代码 这个代码里面我加了我自己写的测试数据&#xff0c;自己可以去找对应的部分&#xff0c…