6.4 工具-RabbitMQ

news2024/11/18 20:17:41

目录

6.4.1 RabbitMQ概述

6.4.1.1 什么是RabbitMQ

6.4.1.2 Erlang和AMQP

6.4.1.3 RabbitMQ

6.4.1.3.1 RabbitMQ优点

6.4.1.3.2 应用解耦

6.4.1.3.3 异步处理  

6.4.1.3.4 流量削峰

6.4.2 RabbitMQ安装

6.4.3 RabbitMQ架构

6.4.3.1 架构图

6.4.3.1.1 术语

6.4.3.1.2 简单架构图  

6.4.3.1.3 完整架构图

6.4.3.2 消息模式

6.4.4 SpringBoot整合RabbitMQ

6.4.4.1 简单模式

6.4.4.1.1 原生态方式

6.4.4.1.2  SpringBoot整合RabbitMQ方式

6.4.4.2 工作队列模式

6.4.4.2.1 说明

6.4.4.2.2 代码

6.4.4.3 发布订阅模式

6.4.4.3.1 说明

6.4.4.3.2 代码

6.4.4.4 路由模式

6.4.4.4.1 说明

6.4.4.4.2 代码

6.4.4.5 主题模式

6.4.4.5.1 说明

6.4.4.5.2 代码


6.4.1 RabbitMQ概述

6.4.1.1 什么是RabbitMQ

假设有个注册动作,之后的流程如下图所示

 耗时1.5有点长,能不能把后面的邮箱验证,短信验证在用户提交注册后,和添加数据库一起执行

6.4.1.2 Erlang和AMQP

Erlang是一门动态类型的函数式编程语言,它也是一门解释型语言,由Erlang虚拟机解释执行。从语言模型上说,Erlang是基于Actor模型的实现。在Actor模型里面,万物皆Actor,每个Actor都封装着内部状态,Actor相互之间只能通过消息传递这一种方式来进行通信。对应到Erlang里,每个Actor对应着一个Erlang进程,进程之间通过消息传递进行通信。相比共享内存,进程间通过消息传递来通信带来的直接好处就是消除了直接的锁开销(不考虑Erlang虚拟机底层实现中的锁应用)。

AMQP(Advanced Message Queue Protocol)定义了一种消息系统规范。这个规范描述了在一个分布式的系统中各个子系统如何通过消息交互。而RabbitMQ则是AMQP的一种基于erlang的实现。AMQP将分布式系统中各个子系统隔离开来,子系统之间不再有依赖。子系统仅依赖于消息。子系统不关心消息的发送者,也不关心消息的接受者。

6.4.1.3 RabbitMQ

6.4.1.3.1 RabbitMQ优点

常见的MQ:ActiveMQ,RocketMQ,Kafka,RabbitMQ。

  • 语言的支持:ActiveMQ,RocketMQ只支持Java语言,Kafka可以支持多门语言,RabbitMQ支持多种语言。

  • 效率方面:ActiveMQ,RocketMQ,Kafka效率都是毫秒级别,RabbitMQ是微秒级别的。

  • 消息丢失,消息重复问题: RabbitMQ针对消息的持久化,和重复问题都有比较成熟的解决方案。

  • 学习成本:RabbitMQ非常简单。

RabbitMQ是用Erlang实现的一个高并发高可靠AMQP消息队列服务器。支持消息的持久化、事务、拥塞控制、负载均衡等特性,使得RabbitMQ拥有更加广泛的应用场景。

优点

  1. 解耦:降低系统模块的耦合度
  2. 提高系统响应时间
  3. 异步消息
  4. 过载保护,流量削峰

6.4.1.3.2 应用解耦

 用户下单后,订单系统需要通知库存系统,传统的做法就是订单系统调用库存系统的接口.

这种做法有一个缺点:

  • 当库存系统出现故障时,订单就会失败.
  • 订单系统和库存系统高耦合

 引入消息队列

  • 订单系统: 用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
  • 库存系统: 订阅下单的消息,获取下单消息,进行库操作。 就算库存系统出现故障,消息队列也能保证消息的可靠投递,不会导致消息丢失

6.4.1.3.3 异步处理  

 前面讲的用户注册案例

1. 串行的方式

2. 并行的方式  

三个任务同时处理,返回给客户端,并行的方式能提高处理的时间

6.4.1.3.4 流量削峰

因为流量过大,导致应用挂掉,为了解决这个问题,一般在应用前端加入消息队列。

6.4.2 RabbitMQ安装

RabbitMQ在window和linux下均可安装。以下仅展示Linux下的RabbitMQ安装

docker-compose.yml

version: "3.1"
services:
  rabbitmq:
    image: daocloud.io/library/rabbitmq:management
    restart: always
    container_name: rabbitmq
    ports:
      - 5672:5672 # 服务器端口
      - 15672:15672 # 客户端访问服务器的端口
    volumes:
      - ./data:/var/lib/rabbitmq
[root@iz8vbdmrir2n6xqzrbd93hz /]# cd /opt
# 创建文件夹
[root@iz8vbdmrir2n6xqzrbd93hz opt]# mkdir docker_rabbitmq
# 进入文件夹
[root@iz8vbdmrir2n6xqzrbd93hz opt]# cd docker_rabbitmq/
# 添加docker-compose.yml 将上面的配置信息粘贴进来
[root@iz8vbdmrir2n6xqzrbd93hz docker_rabbitmq]# vim docker-compose.yml
[root@iz8vbdmrir2n6xqzrbd93hz docker_rabbitmq]# docker-compose-Linux-x86_64 up -d

# 查看所有进程
[root@192 docker_rabbitmq]# docker ps -a

浏览器访问:http://自己的ip:15672

云服务器记得开放 15672 和 5672 端口

用户名和密码默认都是:guest

访问

 RabbitMQ的图形化管理界面

切换到:docker_rabbitmq 下
# down 停止服务并删除
docker-compose-Linux-x86_64 down 
# down 停止服务
docker-compose-Linux-x86_64 stop     
systemctl stop firewalld
systemctl disable firewalld
systemctl restart docker 
# 启动服务
docker-compose-Linux-x86_64 up -d

6.4.3 RabbitMQ架构

6.4.3.1 架构图

6.4.3.1.1 术语

  • Publisher - 生产者:发布消息到RabbitMQ中的Exchange
  • Consumer - 消费者:监听RabbitMQ中的Queue中的消息
  • Exchange - 交换机:和生产者建立连接并接收生产者的消息
  • Queue - 队列:Exchange会将消息分发到指定的Queue,Queue和消费者进行交互
  • Routes - 路由:交换机以什么样的策略将消息发布到Queue

6.4.3.1.2 简单架构图  

Publisher生产消息,将消息放到Exchange上,根据Routes将消息分发到Queue,Consumer处理消息

6.4.3.1.3 完整架构图

 生产者和虚拟机建立连接,建立完连接后创建一个Channel,通过Channel把消息发送到Exchange上

6.4.3.2 消息模式

官网【RabbitMQ Tutorials — RabbitMQ】

常见的五种模式

  1. 简单模式
  2. Work Queues 工作队列模式
  3. Publish/Subscribe发布订阅模式
  4. Routing 路由模式
  5. Topics 主题模式

6.4.4 SpringBoot整合RabbitMQ

6.4.4.1 简单模式

6.4.4.1.1 原生态方式

原生态方式实现简单五种消息模型中的Simple-简单模型。

由于所有的功能都要自己手动引入依赖,手动写代码,所以会比较繁琐

以后用springboot整合后会更简便,springboot会优化代码,同时隐藏一些代码

利用SpringBoot自动生成项目结构

如果不知道如何自动生成点击【6.2 微服务-SpringBoot_老李头喽的博客-CSDN博客】

导入依赖

<!-- amqp依赖 原生方式-->
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.9.0</version>
</dependency>

之后开始创建生产者,消费者

创建Publisher发布者

//生产者
public class Publisher {
    public static void main(String[] args) throws Exception{

        /*
        * 1.创建连接工厂
        * 2.获取连接对象
        * 3.创建频道
        * 4.声明队列
        * 5.发布消息
        * 6.释放资源
        */

        System.out.println("Publisher...");
        //1.创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //配置连接参数
        factory.setHost("192.168.72.129");
        //连接服务器端口5672,而不是在浏览器客户端访问端口15672
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");
        //2.获取连接对象
        Connection connection = factory.newConnection();
        //3.创建频道
        Channel channel = connection.createChannel();
        //4.声明队列
        //配置队列参数
        //参数1:queue - 指定队列的名称
        //参数2:durable - 当前队列是否需要持久化,值为true时表示持久化,rabbitmq宕机或重启后,队列依然在
        //参数3:exclusive - 当前队列是否为排他队列,值为true时表示与当前连接(connection)绑定,连接关闭,队列消失
        //参数4:autoDelete - 当前队列是否自动删除,值为true时表示队列中的消息一旦被消费,该队列会消失
        //参数5:arguments - 指定当前队列的相关参数
        channel.queueDeclare("helloworldQueue",false,false,false,null);
        //5.发布消息
        //发布消息到exchange,同时指定路由的规则
        // 参数1:指定exchange,使用"",简单模式没有交换机
        // 参数2:指定路由的规则,使用具体的队列名称
        // 参数3:指定传递的消息所携带的properties,使用null
        // 参数4:指定发布的具体消息,byte[]类型
        channel.basicPublish("","helloworldQueue",null,"发布者发布,helloworld".getBytes());
        //6.释放资源
        //注意顺序
        // channel.close();
        // connection.close();
    }
}

创建Consumer消费者 

//消费者
public class Consumer {
    public static void main(String[] args)throws Exception {
        System.out.println("Consumer...");
        //配置连接参数
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.72.129");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");
        //获取连接
        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();
		//要与生产者中的该方法一致(注:方法中的参数值必须保持一致)
        channel.queueDeclare("helloworldQueue",false,false,false,null);

        // 回调函数:消费(处理业务)的过程
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            //重写DefaultConsumer里的handleDelivery方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者接收到消息:"+new String(body));
            }
        };

        //消费消息
        //参数1:queue - 指定消费哪个队列
        //参数2:autoAck - 指定是否自动ACK (true表示接收到消息后,会立即告知RabbitMQ,false表示不告知)
        //参数3:consumer - 指定消费回调函数
        channel.basicConsume("helloworldQueue",true,defaultConsumer);
    }
}

启动Docker

分别启动生产者和消费者进行测试

运行生产者,Queues中会有一条消息,当运行消费者后,消息会被处理,Queues中消息为0

由于没有设置持久化,服务器宕机后,消息队列会清空

在声明队列时需要配置队列参数
        //参数1:queue - 指定队列的名称
        //参数2:durable - 当前队列是否需要持久化,值为true时表示持久化,rabbitmq宕机或重启后,队列依然在
        //参数3:exclusive - 当前队列是否为排他队列,值为true时表示与当前连接(connection)绑定,连接关闭后队列也会随着消失
        //参数4:autoDelete - 当前队列是否自动删除,值为true时表示队列中的消息一旦被消费,该队列会消失
        //参数5:arguments - 指定当前队列的相关参数

6.4.4.1.2  SpringBoot整合RabbitMQ方式

为了区别上面的原生态方式,新建包

引入启动器 

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

application.properties中增加配置

# 应用名称
spring.application.name=rabbitmq
# 应用服务 WEB 访问端口
server.port=8080

#rabbitMQ配置
spring.rabbitmq.host=192.168.72.129
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

SimpleConfig  

//配置类
@Configuration
public class SimpleConfig {
    @Bean
    public Queue getQueue() {
        return new Queue("simpleQueue", true, false, false, null);
    }
}

注意Queue包 

 Publisher 

//生产者
@Component
public class Publisher {
    @Autowired
    RabbitTemplate rabbitTemplate;
    public void send(){
        System.out.println("生产者:发布消息");
        rabbitTemplate.convertAndSend("","simpleQueue","消息:有一个消息");
    }
}

Consumer 


//消费者
@Component
@RabbitListener(queues = "simpleQueue")  //时刻监听着指定的队列
public class Consumer {
    @RabbitHandler //@RabbitListener监听消息队列中是否有消息,有消息就调用@RabbitHandler标识的方法处理
    public void receive(String msg) {
        System.out.println("接收到消息:" + msg);
    }
}

消费者需要用到@RabbitListener和@RabbitHandler注解

测试类

@SpringBootTest
public class RabbitmqApplication2 {
    @Autowired
    Publisher publisher;
    @Test
    public  void test(){
        publisher.send();
    }
}

由于消费者有监听机制,所以只需要运行测试类里的publisher中的send方法即可,当消息队列中有消息,监听机制会自动使消费者处理消息

6.4.4.2 工作队列模式

6.4.4.2.1 说明

工作队列模式不需要交换机

一个生产者,一个队列,多个消费者,默认采用公平分发

6.4.4.2.2 代码

WorkConfig配置类

@Configuration
public class WorkConfig {
    //工作模式:一个队列,多个消费者
    @Bean
    public Queue workQueue(){
        System.out.println("workqueue模式创建队列");
        return new Queue("workQueue",true);
    }
}

 Publisher生产者

//生产者
@Component
public class Publisher {
    @Autowired
    RabbitTemplate rabbitTemplate;
    public void send(){
        System.out.println("生产者:发布消息");
        rabbitTemplate.convertAndSend("","workQueue","workqueue");
    }
}

 Consumer消费者1 

//消费者
@Component
@RabbitListener(queues = "workQueue")  //时刻监听着指定的队列
public class Consumer {
    @RabbitHandler //@RabbitListener监听消息队列中是否有消息,有消息就调用@RabbitHandler标识的方法处理
    public void receive(String msg) {
        System.out.println("Consumer1 接收到消息:" + msg);
    }
}

Consumer2 消费者2

//消费者
@Component
@RabbitListener(queues = "workQueue")  //时刻监听着指定的队列
public class Consumer2 {
    @RabbitHandler //@RabbitListener监听消息队列中是否有消息,有消息就调用@RabbitHandler标识的方法处理
    public void receive(String msg) {
        System.out.println("Consumer2 接收到消息:" + msg);
    }
}

6.4.4.3 发布订阅模式

6.4.4.3.1 说明

使用该模式需要借助交换机,生产者将消息发送到交换机,再通过交换机到达队列。

交换机分四种:

  • Direct:直接交换机,通过消息上的路由键(Routing key)直接对消息进行分发,相当于精确匹配,一对一
  • Topic:交换机会将路由键和绑定上的模式进行通配符匹配,相当于模糊匹配,一对多
  • Headers:消息头交换机,使用消息头的属性进行消息路由,相当于模糊匹配,一对多
  • Fanout:扇出交换机,会将消息发送到所有和它进行绑定的队列上,广播,群发

默认交换机是Direct,发布订阅模式使用Fanout类型交换器

6.4.4.3.2 代码

FanoutConfig 

@Configuration
public class FanoutConfig {
    //发布订阅模式  一个生产者   一个交换机(FanoutExchange)  两个队列(队列需要绑定到交换机)  两个消费者
    //创建扇出交换机
    @Bean
    public FanoutExchange fanoutExchange(){
        System.out.println("创建交换机");
        return new FanoutExchange("fanoutExchange",true,false);
    }
    //创建队列
    @Bean
    public Queue fanoutqueue1(){
        return new Queue("fanoutqueue1",true);
    }
    @Bean
    public Queue fanoutqueue2(){
        return new Queue("fanoutqueue2",true);
    }
    //将队列绑定到交换机
    //通过方法获得对象
    @Bean
    public Binding bindingqueque1(){
    //通过BindingBuilder的bind方法将队列和交换机绑定在一起
      return  BindingBuilder.bind(fanoutqueue1()).to(fanoutExchange());
    }
    @Bean
    public Binding bindingqueque2(){
        return  BindingBuilder.bind(fanoutqueue2()).to(fanoutExchange());
    }
    //通过形参获得对象

}
//生产者
@Component
public class Publisher {

        @Autowired
        RabbitTemplate rabbitTemplate;
        public void send(){
            System.out.println("生产者:发布消息");
            rabbitTemplate.convertAndSend("fanoutExchange","","生产者:发布订阅模式");
        }
    }

//消费者
@Component
@RabbitListener(queues = "fanoutqueue1")  //时刻监听着指定的队列
public class Consumer1 {
    @RabbitHandler //@RabbitListener监听消息队列中是否有消息,有消息就调用@RabbitHandler标识的方法处理
    public void receive(String msg) {
        System.out.println("Consumer1接收到消息:" + msg);
    }
}
//消费者
@Component
@RabbitListener(queues = "fanoutqueue2")  //时刻监听着指定的队列
public class Consumer2 {
    @RabbitHandler //@RabbitListener监听消息队列中是否有消息,有消息就调用@RabbitHandler标识的方法处理
    public void receive(String msg) {
        System.out.println("Consumer2接收到消息:" + msg);
    }
}

6.4.4.4 路由模式

6.4.4.4.1 说明

一个生产者,一个交换机,多个队列,多个消费者  

生产者将消息发送到Direct交换机(路由模式需要借助直连交换机实现),在绑定队列和交换机的时候有一个路由键(Routing key),生产者发送的消息会指定一个路由键,那么消息只会发送到相应key相同的队列,接着监听该队列的消费者消费消息。消费者可以选择性的接收消息

6.4.4.4.2 代码

RoutingConfig 

//路由模式 一个生产者 一个交换机(直连交换机) 两个队列(路由key) 两个消费者
@Configuration
public class RoutingConfig {
    //创建直连交换机
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange("directExchange");
    }
    //队列
    @Bean
    public Queue routingQueue1(){
        return new Queue("routingQueue1");
    }
    @Bean
    public Queue routingQueue2(){
        return new Queue("routingQueue2");
    }
    //绑定
    @Bean
    public Binding bingroutingQueue1(){
        //直连交换机必须带routingkey
        return BindingBuilder.bind(routingQueue1()).to(directExchange()).with("1");
    }
    @Bean
    public Binding bingroutingQueue2(){
        //直连交换机必须带routingkey
        return BindingBuilder.bind(routingQueue2()).to(directExchange()).with("2");
    }
}

注意: 路由模式,绑定队列和交换机时需要指定路由键

RoutingPublisher  

//生产者
@Component
public class RoutingPublisher {

        @Autowired
        RabbitTemplate rabbitTemplate;
        public void send(){
                System.out.println("生产者:发布消息");
            //设置routingkey
            rabbitTemplate.convertAndSend("directExchange","1","生产者:消息 1");
            rabbitTemplate.convertAndSend("directExchange","2","生产者:消息 2");
            rabbitTemplate.convertAndSend("directExchange","3","生产者:消息 3");
        }
    }
//消费者
@Component
@RabbitListener(queues = "routingQueue1")  //时刻监听着指定的队列
public class RoutingConsumer1 {
    @RabbitHandler //@RabbitListener监听消息队列中是否有消息,有消息就调用@RabbitHandler标识的方法处理
    public void receive(String msg) {
        System.out.println("Consumer1接收到消息:" + msg);
    }
}
//消费者
@Component
@RabbitListener(queues = "routingQueue2")  //时刻监听着指定的队列
public class RoutingConsumer2 {
    @RabbitHandler //@RabbitListener监听消息队列中是否有消息,有消息就调用@RabbitHandler标识的方法处理
    public void receive(String msg) {
        System.out.println("Consumer2接收到消息:" + msg);
    }
}

6.4.4.5 主题模式

6.4.4.5.1 说明

一个生产者,一个交换机,多个队列,多个消费者

主题模式又称通配符模式

使用直连交换机可以改善我们的系统,但是它仍有局限性,它不能实现多重条件的路由。

在消息系统中,我们不仅想要订阅基于路由键的队列,还想订阅基于生产消息的源。这时候可以使用Topic交换机。

使用主题交换机时不能采用任意写法的路由键,路由键的形式应该是由点分割的有意义的单词。例如"goods.stock.info"等。路由key最多255字节。

  • * :代表一个单词
  • # :代表0个或多个单词

6.4.4.5.2 代码

@Configuration
public class TopicConfig {

    @Bean
    public Queue topicQueue1(){
        return new Queue("topicQueue1");
    }

    @Bean
    public Queue topicQueue2(){
        return new Queue("topicQueue2");
    }

    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange("topicExchange");
    }

    @Bean
    public Binding bingTopicQueue1(){
        return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with("China.*");
    }

    @Bean
    public Binding bingTopicQueue2(){
        return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with("America.#");
    }
}
@Component
public class TopicPublisher {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private TopicExchange topicExchange;

    public void send() {
        System.out.println("TopicPublisher");
        rabbitTemplate.convertAndSend(topicExchange.getName(), "China.beijing", "中国北京");
        rabbitTemplate.convertAndSend(topicExchange.getName(), "America.Texas.Houston", "美国德克萨斯休斯顿");
    }
}
@Component
@RabbitListener(queues = "topicQueue1")
public class TopicCustomer1 {

    @RabbitHandler
    public void receive(String msg) {
        System.out.println("TopicCustomer1:" + msg);
    }
}
@Component
@RabbitListener(queues = "topicQueue2")
public class TopicCustomer2 {

    @RabbitHandler
    public void receive(String msg) {
        System.out.println("TopicCustomer2:" + msg);
    }
}

但是如果将 TopicPublisher 中修改为

 rabbitTemplate.convertAndSend(topicExchange.getName(), "China.beijing.haidian", "中国北京海淀区");

结果 TopicCustomer1就接收不到消息中国北京海淀

 原因就是

  • * :代表一个单词
  • # :代表0个或多个单词

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

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

相关文章

MongoDB入门学习(二)GridFS、GridFS整合SpringBoot

文章目录GridFSGridFS简介GridFS存储原理GridFS整合SpringBoot新增store()查询与下载find()、findOne()删除delete()Demo案例GridFS GridFS简介 GridFS是MongoDB的一个用来存储/获取大型数据&#xff08;图像、音频、视频等类型的文件&#xff09;的规范。相当于一个存储文件…

Java中创建不可变集合、Stream流、异常体系、日志框架

创建不可变集合、Stream流、异常体系、日志框架创建不可变集合什么是不可变集合&#xff1f;为什么要创建不可变集合&#xff1f;如何创建不可变集合&#xff1f;不可变集合的特点&#xff1f;Stream流Stream流的概述Stream流的获取Stream流的常用API&#xff08;中间操作方法&…

Index Tree(树状数组)

1、引入 线段树解决的是 区间查询 和 区间更新 的问题&#xff0c; O(logn)O(logn)O(logn) 复杂度。 人为规定&#xff1a;数组下标从 1 开始。 如果要计算数组某个范围 L 到 R 的累加和&#xff0c;那么可以准备一个前缀和数组 help&#xff0c;得到前缀和数组后&#xff0…

【寒假每日一题】洛谷 P6263 [COCI2014-2015#3] STROJOPIS

题目链接&#xff1a;P6263 [COCI2014-2015#3] STROJOPIS - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 正确的打字正成为文化的重要组成部分。如果你仍然没有使用所有的十根手指来打字&#xff0c;你必须重新学习打字——然后你会打字更快&#xff0c;感觉更舒适…

Web进阶:Day1 字体图标、平面转换、空间转换、动画

Web进阶&#xff1a;Day1 Date: October 3, 2022 Summary: 字体图标、平面转换、空间转换、动画 字体图标 字体图标 字体图标展示的是图标&#xff0c;本质是字体 处理简单的、颜色单一的图片 注&#xff1a;复杂的用CSS精灵&#xff0c;简单的用字体图标 字体图标的优点&…

Verilog语法笔记(夏宇闻第三版)-条件语句

目录 if_else语句&#xff1a; 五点说明&#xff1a; case语句&#xff1a; 真值表&#xff1a; ​例&#xff1a; ​由于使用条件语句不当在设计中生成了原本没想到有的锁存器&#xff1a; if_else语句&#xff1a; if语句是用来判定所给定的条件是否满足&#xff0c;…

(十四)面向对象的三大特征

目录 前言: 一、面向对象三大特征之一:封装 二、面向对象三大特征之二:继承 三、面向对象三大特征之三:多态 前言: 面向对象的三大特征:封装、继承、多态。 一、面向对象三大特征之一:封装 1.概述: 封装是把过程和数据包围起来&#xff0c;对数据的访问只能通过已定义的接口…

使用Idea编码常用的28种技巧方式

一丶列表: 1丶查看代码历史版本 2丶调整idea的虚拟内存&#xff1a; 3丶idea设置成eclipse的快捷键 4丶设置提示词忽略大小写 5丶关闭代码检查 6丶设置文档注释模板 7丶显示方法分隔符 8丶设置多行tab 9丶快速匹配方法的大括号位置 10丶代码结尾补全 11丶模糊搜索方法 12丶预览…

用 Python selenium爬取股票新闻并存入mysql数据库中带翻页功能demo可下载

用 Python selenium爬取实时股票新闻并存入mysql数据库中1.分析需求2.创建表3.分析需要爬取的网页内容4.python里面selenium进行爬虫操作1.添加包2.连接数据库3.selenium爬虫前配置4.对股票新闻内容爬取并存入mysql中5.翻页功能6.运行程序首先我们先明确我们的主要目标就是要爬…

5、SySeVR复现——Data preprocess(上)

目录 1、环境 2、生成切片对应的hash 3、获取要删除的切片位置信息 4、对切片进行token化 1、环境 从数据预处理开始&#xff0c;操作系统&#xff1a;windows 10 &#xff0c;软件&#xff1a;pycharm 注&#xff1a;对官方提供的文件&#xff0c;做了一些改动&#xff0c…

插槽 slot

文章目录一、什么是插槽二、插槽内容三、渲染作用域四、默认内容五、具名插槽六、作用域插槽一、什么是插槽 我们使用 <slot> 作为一个占位符&#xff0c;父组件就可以把要传递的内容显示到占位符所在位置上&#xff0c;提高组件使用的灵活性。 二、插槽内容 父组件向…

安信可VC系列语音识别的使用教程

安信可VC-02语音识别的应用&#xff0c;本篇只讲述在Windows系统下的应用。Linux下的请参考官方文档介绍和说明。 1-安信可VC-02离线语音识别简介 VC系列模组是我司开发的一款AI离线语音识别的产品&#xff0c;主芯片是云知声推出的离线语音识别芯片锋鸟M(US516P6)&#xff0c…

Redis基础语法和SpringBoot集成使用

在初期&#xff0c;已经讲述了Redis安装问题。现在正式进入Redis的入门阶段。 Redis客户端 命令行客户端 redis-cli [options] [commands]常用到的 options 有&#xff1a; -h 127.0.0.1: 指定要连接的Redis的IP地址【默认127.0.0.1】-p 6379: 指定连接Redis的端口【默认63…

jenkins前端页面自动运维值yarn编译运行项目

配置步骤如下 首先需要在系统管理中心安装node相关插件 安装完成之后&#xff0c;在系统管理——>全局工具配置——>NodeJS 点击新增Nodejs 此处自定义别名&#xff0c;我这里是Nodejs16&#xff0c;取消自动安装前面的复选框&#xff0c;下方选择我们的nodejs安装目录&…

云服务器定时执行python脚本

文章目录前言crontab简介基本语法定时任务具体内容python 脚本定时任务前言 在服务器上定时执行任务有两种方式&#xff0c;一种是at定时任务&#xff0c;一种是crond任务调度&#xff0c;at命令是一次性定时计划任务&#xff0c;at的守护进程 atd会以后台模式运行&#xff0c…

Spring注解之@validated使用

概念 spring-boot中可以用validated来校验数据&#xff0c;如果数据异常则会统一抛出异常&#xff0c;方便异常中心统一处理。 注解源码&#xff1a; Validated 作用在类、方法和参数上 Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) Retention(…

python初级教程十一 urllib

urllib Python urllib 库用于操作网页 URL&#xff0c;并对网页的内容进行抓取处理。 本文主要介绍 Python3 的 urllib。 urllib 包 包含以下几个模块&#xff1a; urllib.request - 打开和读取 URL。 urllib.error - 包含 urllib.request 抛出的异常。 urllib.parse - 解…

【Python入门指北】操作数据库

文章目录一、1.数据库2.练手案例二、redis数据库一、 1.创建一个数据库 [guanmaster1 ~]$ mysql -uroot -p123456 mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL…

Apache IoTDB PMC 乔嘉林荣获 2022 杰出开源贡献者|开源技术强大,开源文化活跃...

2022 年 12 月 29 日至 30 日&#xff0c;2022 木兰峰会正式召开&#xff0c;会上发布了中国开源云联盟 2022 年度评选名单。本次评审专家包括数十位开源领域专家、社区领袖、科研院所专家&#xff0c;共评选出杰出开源贡献者 3 人。其中&#xff0c;清华大学助理研究员、博士后…

【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.16 完结和后续:《Qt开发专题-自定义控件》

本节对应的视频讲解&#xff1a;B_站_视_频 https://www.bilibili.com/video/BV1NW4y1K7eL 1. 为什么需要自定义控件 绘图最大的一个应用场景就是自定义控件&#xff0c;Qt 本身提供的一些控件是有限的&#xff0c;并且它提供的一些控件很可能不满足我们的需要 这种情况下&a…