RabbitMQ(基本使用)

1.RabbitMQ(基本理解)

​ 1.它是一个消息中间件

​ 2.主要作用: 给进程(微服务) 提供消息通信的桥梁

​ 3.好处: 解决数据高峰的作用(有一个高可靠性的保证)

2.学前必读

​ 1.Java的基本编码有一定的了解和使用,(比如封装、继承、多态等)

​ 2.学习工具

                    2.1  IntelliJ IDEA 2019.3 
	        2.2 Maven(3.6.3)	
3.事宜人群

​ 1.有一定的Java基础(上面讲过了)

​ 2.想快速的学习一种消息中间件

​ 3.有解决大量消息通信导致收发端程序崩溃的需求

4.学习顺序

​ 1.RabbitMQ基础讲解

​ 2.RabbitMQ整合SpringBoot

5.基本流程图

​ 注意: RabbitMQ 此时为快递公司(都会在以下讲解)
image-20200522103917055.png
也可以定义虚拟主机 (也就是接受不同的快递) (都会在以下讲解)
image-20200522104134568.png

也可以定义死信交换机 (都会在以下讲解)

image-20200522104437126.png

6.RabbitMQ环境安装(基于Linux)
6.1系统准备

VMWare 15.0

RHEL7.2/CentOS 7.2

6.2 安装软件-erlang

http://www.erlang.org/

http://www.erlang.org/downloads

rpm –i er*

6.3 安装软件-socat

https://pkgs.org/download/socat

rpm –I so*

6.4 安装软件-RabbitMQ-SERVER

http://www.rabbitmq.com/

http://www.rabbitmq.com/download.html

rpm –I rabb*

6.5 设置开机启动

chkconfig rabbitmq-server on

6.6 启动关闭RabbbitMQ-Server

启动 rabbitmq-server start &

停止 rabbitmqctl app_stop

管理插件:rabbitmq-plugins enable rabbitmq_management

访问地址:http://127.0.0.1:15672/

管理员帐号:guest/guest

lsof –i:5672 检查是否启动,可以看到rabbitmq使用的amqp协议
image-20200522111309716.png

7.RabbitMQ环境安装(基于windows)

如有不懂,可以查看我写的其他的文章

8、RabbitMQ基础开发
1、 Maven添加依RabbitMQ的jar包依赖

配置Maven,添加依赖。把下面的依赖包加入到dependency

<!-- 添加rabbitmq的依赖 -->
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
        </dependency>
2、创建生产者(Producer)用于测试RabbitMQ 用于发送数据
package com.study.rabbitmq.demo;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/22 15:46
 * @description Producer 生产者
 *      创建创建连接和信道
 */
public class Producer {

    public static void main(String[] args) throws IOException, TimeoutException {

        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();

        /**
         * 声明一个队列(货架子)
         *
         * (这个属性是在第二个参数里设置)
         * durable:表示是否持久化写入到磁盘中 如果为true则表示关闭了服务重启后依然有数据 如果为false则表			*		   示关闭了服务就没有数据了
         *          这个属性则表示如果有必要为持久化那就设置为true 没有必要就为false节省内存空间,提高吞吐		*		   量
         *
         * (这个属性是在第三个参数里设置)
         * exclusive:独占 如果设置为true那就表示为整个程序只能让它自己使用,别的程序那就不能使用这个货架子		  *				  主要特点: 同一时刻,只能有一个程序连接队列。独占队列必定是自动删除的队列,给自己		   *			   用的,无法实现进程间的通信。
	    *
         *                如果设置为false 则表示所有的程序都可以使用这个货架子,一般我们会把它设置为false		   *			    的
         */
        channel.queueDeclare("queueXiaoMi",true,false,false,null);

        /**
         *  channel.basicPublish("","queueXiaoMi",basicProperties,oneData.getBytes());
         *  上面方法的作用是:发送数据
         *
         *  (就是第三个参数)
         *  props:表示是否要传入什么数据 这里的数据是持久化的,是保存到本地磁盘的
         *  	   如果为null则表示什么都不传入
         *  也可以传入数据 比如:MessageProperties.PERSISTENT_BASIC 这是系统自带的 当然也可以自己new一个		  *				(保存一些自定义的一些数据)
         *  如下代码:
         * */   
        Map<String,Object> headers = new HashMap<>();
        headers.put("姓名","老王");
        headers.put("电话","15110012023");
        headers.put("地址","江西");
        
         AMQP.BasicProperties basicProperties = new AMQP.BasicProperties()
                .builder()
                //设置字符编码集
                .contentEncoding("UTF-8")
                //设置保存时间是多少 毫秒为单位,如果10秒中内数据没有被消费,那就自动删除了
                .expiration("1000000")
                //设置它的保存模式 有两种保存模式 1为保存,但不会保存到磁盘上,
                //                             2为保存,但会保存到磁盘上
                .deliveryMode(2)
                //自定义的一些属性详情 存放一个Map集合
                .headers(headers)
                .build();
        
        String oneData = "hello rabbitMq";
        
        //这是以前的,是没有传入持久化的
        //channel.basicPublish("","queueXiaoMi",null,oneData.getBytes());

        //这是现在的,传入持久化的 
        //其实最终发送的还是hello rabbitMq这句话,只不过在它的基础上增加了一些附带						   //的信息。比如清单信息
        channel.basicPublish("","queueXiaoMi",basicProperties,oneData.getBytes());
        
        //关闭信道和连接 顺序从小到大
        channel.close();
        connection.close();



    }

}
3、创建消费者(Consumer)用于测试RabbitMQ 用于接收数据
package com.study.rabbitmq.demo;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/22 16:33
 * @description Consumer 消费者
 *
 *  最简单的消息接收
 */
public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();

        //接收数据 最简单的消息接收
        //不使用交换机,路由规则即交换机的方式
        DefaultConsumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body)
                    throws IOException
            {
                String strRecv = "我收到了" + new String(body);
                System.out.println(strRecv);
                
                //获取快递清单数据
                System.out.println("同时我还获取了快递的清单的详情信息");
                Map<String, Object> headers = properties.getHeaders();
                if(headers != null){
                    for (Object value : headers.entrySet()) {
                        System.out.println(value);
                    }
                }
            }

        };

        channel.basicConsume("queueXiaoMi",true,consumer);

    }

}

9、交换机Exchange

交换机的好处是可以更灵活的配置把消息路由到队列

交换机的几种类型:直连型交换机,fanout交换机,topic交换机,header型交换机 (前三种用的比较多)
image-20200525092531616.png

1、创建直连型交换机-绑定队列-发送数据 (发送了,还没有接收)
package com.study.rabbitmq.p02directdemo;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/25 09:36
 * @description
 */
public class Producer {

    public static void main(String[] args) throws IOException, TimeoutException {

        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();

        //声明一个交换机
        //第一个参数是它的名字(最好是英文,见名知意),
        //第二个参数是它的交换机的类型,
        //第三个参数是否要保存到本地磁盘中
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.exchangeDeclare("交换机direct","direct",true,false,null);


        //有了交换机,再申明一个队列出来
        //第一个参数是它的名字(最好是英文,见名知意),
        //第二个参数是否要保存到本地磁盘中
        //第三个参数是否要独占(如果是独占,那就只能让它自己使用了,这样不太好)
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.queueDeclare("队列direct",true,false,false,null);


        //绑定队列
        //第一个参数表示 要绑定的队列名称
        //第二个参数表示 要把队列绑定到那个交换机上
        //第三个参数表示 路由键 (因为这里是直连型交换机,暂时没有路由键,所以可以暂时随便写一个,比如:小兔子乖乖)
        channel.queueBind("队列direct","交换机direct","小兔子乖乖");


        //发送数据到交换机
        //第一个参数表示 要绑定的交换机名称(要发送给哪个交换机)
        //第二个参数表示 路由键  跟上面的路由键保持一致
        //第三个参数表示 携带的头信息数据(这里暂时没有)
        //第四个参数表示 要发送的数据 (这里为了演示,发送了一句话,正常情况下,我们会发送真实的数据)
        String oneData = "这是新买的洗面奶";
        channel.basicPublish("交换机direct","小兔子乖乖",null,oneData.getBytes());


        //关闭信道和连接 顺序从小到大
        channel.close();
        connection.close();


    }



}

2、直连型交换机 控制台观察队列和交换机的绑定关系-消费数据 (接收了)
package com.study.rabbitmq.p02directdemo;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/25 09:36
 * @description
 */
public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();


        DefaultConsumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body)
                    throws IOException
            {
                String strRecv = "我收到了" + new String(body);
                System.out.println(strRecv);
            }
        };

        //获取生产者生产出来的数据
        //第一个参数表示 要从哪个队列里获取数据
        //第二个参数表示 是否要自动确认
        //第三个参数表示 主要通过它来获取数据
        channel.basicConsume("队列direct",true, consumer);



        //关闭信道和连接 顺序从小到大
        /*channel.close();
        connection.close();*/
    }


}

3、直连型交换机总结

主要是处理跟生产者的关系,然后把数据按照一定的路由规则,放到相应的队列里 这样的一个作用

4、fanout型交换机(废掉路由规则) 创建-绑定-数据消费

不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的

image-20200525110940569.png

生产数据 fanout型交换机**

package com.study.rabbitmq.p02directdemo;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/25 09:36
 * @description
 */
public class Producer {

    public static void main(String[] args) throws IOException, TimeoutException {

        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();

        
        //========================fanout型交换机====================================
        //声明一个fanout型交换机
        //第一个参数是它的名字(最好是英文,见名知意),
        //第二个参数是它的交换机的类型,
        //第三个参数是否要保存到本地磁盘中
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.exchangeDeclare("交换机fanout","fanout",true,false,null);


        //有了交换机,再申明一个队列出来
        //第一个参数是它的名字(最好是英文,见名知意),
        //第二个参数是否要保存到本地磁盘中
        //第三个参数是否要独占(如果是独占,那就只能让它自己使用了,这样不太好)
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.queueDeclare("队列fanout",true,false,false,null);

        //绑定队列
        //第一个参数表示 要绑定的队列名称
        //第二个参数表示 要把队列绑定到那个交换机上
        //第三个参数表示 路由键 这里使用的是fanout型交换机(它给废弃了,所以写和不写都一样)
        channel.queueBind("队列fanout","交换机fanout","abc");

        //发送数据到交换机
        //第一个参数表示 要绑定的交换机名称(要发送给哪个交换机)
        //第二个参数表示 路由键 这里使用的是fanout型交换机(它给废弃了,所以写和不写都一样)
        //第三个参数表示 携带的头信息数据(这里暂时没有)
        //第四个参数表示 要发送的数据 (这里为了演示,发送了一句话,正常情况下,我们会发送真实的数据)
        String oneData2 = "这是新买的蛋糕";
        channel.basicPublish("交换机fanout","efg",null,oneData2.getBytes());


        
        //关闭信道和连接 顺序从小到大
        channel.close();
        connection.close();
    }



}

消费数据 fanout型交换机

package com.study.rabbitmq.p02directdemo;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @author 武帅
* @date 2020/5/25 09:36
* @description
*/
public class Consumer {

   public static void main(String[] args) throws IOException, TimeoutException {
       // 创建连接工厂,用来修建高速公路
       ConnectionFactory connectionFactory = new ConnectionFactory();

       //设置基本配置
       connectionFactory.setHost("localhost");
       connectionFactory.setPort(5672);
       connectionFactory.setUsername("guest");
       connectionFactory.setPassword("guest");

       //修建一条高速公路
       Connection connection = connectionFactory.newConnection();

       //画定双向车道
       Channel channel = connection.createChannel();


       DefaultConsumer consumer = new DefaultConsumer(channel){
           @Override
           public void handleDelivery(String consumerTag,
                                      Envelope envelope,
                                      AMQP.BasicProperties properties,
                                      byte[] body)
                   throws IOException
           {
               String strRecv = "我收到了" + new String(body);
               System.out.println(strRecv);
           }
       };

       //========================fanout型交换机====================================
       //获取生产者生产出来的数据
       //第一个参数表示 要从哪个队列里获取数据
       //第二个参数表示 是否要自动确认
       //第三个参数表示 主要通过它来获取数据
       channel.basicConsume("队列fanout",true, consumer);

       

       //关闭信道和连接 顺序从小到大
       /*channel.close();
       connection.close();*/
   }


}
5、topic主题型交换机(主题匹配)用的也是最多的

将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。

“.”单词的分隔符(不是必须,可以使用其他分隔符)

“*” 可以匹配一个单词,也只可以是0个单词

“#” 可以匹配多个单词,或者是0个

当一个队列被绑定为routing key为”#”时,它将会接收所有的消息,此时等价于fanout类型交换机。当routing key不包含”*”和”#”时,等价于direct型交换机。
image-20200528090641677.png

生产数据 topic主题型交换机 #匹配**

package com.study.rabbitmq.p02directdemo;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/25 09:36
 * @description
 */
public class Producer {

    public static void main(String[] args) throws IOException, TimeoutException {

        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();


        //========================topic主题型交换机#匹配====================================
        //声明一个topic主题型交换机
        //第一个参数是它的名字(最好是英文,见名知意),
        //      “.”单词的分隔符(不是必须,可以使用其他分隔符)
        //      “*” 可以匹配一个单词,也只可以是0个单词
        //      “#” 可以匹配多个单词,或者是0个
        //第二个参数是它的交换机的类型,
        //第三个参数是否要保存到本地磁盘中
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.exchangeDeclare("交换机topic#","topic",true,false,null);


        //有了交换机,再申明一个队列出来
        //第一个参数是它的名字(最好是英文,见名知意)
        //      “.”单词的分隔符(不是必须,可以使用其他分隔符)
        //      “*” 可以匹配一个单词,也只可以是0个单词
        //      “#” 可以匹配多个单词,或者是0个
        //第二个参数是否要保存到本地磁盘中
        //第三个参数是否要独占(如果是独占,那就只能让它自己使用了,这样不太好)
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.queueDeclare("队列topic#",true,false,false,null);


        //绑定队列
        //第一个参数表示 要绑定的队列名称
        //第二个参数表示 要把队列绑定到那个交换机上
        //第三个参数表示 路由键 这里使用的是topic主体型交换机 可以使用通配符
        //      “.”单词的分隔符(不是必须,可以使用其他分隔符)
        //      “*” 可以匹配一个单词,也只可以是0个单词
        //      “#” 可以匹配多个单词,或者是0个
        channel.queueBind("队列topic#","交换机topic#","#.乖乖");

        //发送数据到交换机
        //第一个参数表示 要绑定的交换机名称(要发送给哪个交换机)
        //第二个参数表示 路由键 这里使用的是topic主体型交换机 可以使用通配符
        //        “.”单词的分隔符(不是必须,可以使用其他分隔符)
        //        “*” 可以匹配一个单词,也只可以是0个单词
        //        “#” 可以匹配多个单词,或者是0个
        //第三个参数表示 携带的头信息数据(这里暂时没有)
        //第四个参数表示 要发送的数据 (这里为了演示,发送了一句话,正常情况下,我们会发送真实的数据)
        String oneData2 = "应该发送到(队列topic#里的数据)这是新买的iPad";
        channel.basicPublish("交换机topic#","小兔子.乖乖",null,oneData2.getBytes());


        //关闭信道和连接 顺序从小到大
        channel.close();
        connection.close();
    }



}

消费数据 topic#主题型交换机 #匹配

package com.study.rabbitmq.p02directdemo;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/25 09:36
 * @description
 */
public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();


        DefaultConsumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body)
                    throws IOException
            {
                String strRecv = "我收到了" + new String(body);
                System.out.println(strRecv);
            }
        };
 
        //========================topic主题型交换机#匹配====================================
        //获取生产者生产出来的数据
        //第一个参数表示 要从哪个队列里获取数据
        //第二个参数表示 是否要自动确认
        //第三个参数表示 主要通过它来获取数据
        channel.basicConsume("队列topic#",true, consumer);

        //关闭信道和连接 顺序从小到大
        /*channel.close();
        connection.close();*/
    }

}

*生产数据 topic主题型交换机 匹配

package com.study.rabbitmq.p02directdemo;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/25 09:36
 * @description
 */
public class Producer {

    public static void main(String[] args) throws IOException, TimeoutException {

        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();

        

        //========================topic主题型交换机*匹配====================================
        //声明一个topic主题型交换机
        //第一个参数是它的名字(最好是英文,见名知意),
        //      “.”单词的分隔符(不是必须,可以使用其他分隔符)
        //      “*” 可以匹配一个单词,也只可以是0个单词
        //      “#” 可以匹配多个单词,或者是0个
        //第二个参数是它的交换机的类型,
        //第三个参数是否要保存到本地磁盘中
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.exchangeDeclare("交换机topic*","topic",true,false,null);


        //有了交换机,再申明一个队列出来
        //第一个参数是它的名字(最好是英文,见名知意)
        //      “.”单词的分隔符(不是必须,可以使用其他分隔符)
        //      “*” 可以匹配一个单词,也只可以是0个单词
        //      “#” 可以匹配多个单词,或者是0个
        //第二个参数是否要保存到本地磁盘中
        //第三个参数是否要独占(如果是独占,那就只能让它自己使用了,这样不太好)
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.queueDeclare("队列topic*",true,false,false,null);


        //绑定队列
        //第一个参数表示 要绑定的队列名称
        //第二个参数表示 要把队列绑定到那个交换机上
        //第三个参数表示 路由键 这里使用的是topic主体型交换机 可以使用通配符
        //      “.”单词的分隔符(不是必须,可以使用其他分隔符)
        //      “*” 可以匹配一个单词,也只可以是0个单词
        //      “#” 可以匹配多个单词,或者是0个
        channel.queueBind("队列topic*","交换机topic*","*.乖乖");

        //发送数据到交换机
        //第一个参数表示 要绑定的交换机名称(要发送给哪个交换机)
        //第二个参数表示 路由键 这里使用的是topic主体型交换机 可以使用通配符
        //        “.”单词的分隔符(不是必须,可以使用其他分隔符)
        //        “*” 可以匹配一个单词,也只可以是0个单词
        //        “#” 可以匹配多个单词,或者是0个
        //第三个参数表示 携带的头信息数据(这里暂时没有)
        //第四个参数表示 要发送的数据 (这里为了演示,发送了一句话,正常情况下,我们会发送真实的数据)
        String oneData2 = "应该发送到(队列topic*里的数据)这是新买的iPad";
        channel.basicPublish("交换机topic*","小兔子.乖乖",null,oneData2.getBytes());


        //关闭信道和连接 顺序从小到大
        channel.close();
        connection.close();
    }

}

*消费数据 topic#主题型交换机 匹配

package com.study.rabbitmq.p02directdemo;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/25 09:36
 * @description
 */
public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = connectionFactory.newConnection();

        //画定双向车道
        Channel channel = connection.createChannel();


        DefaultConsumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body)
                    throws IOException
            {
                String strRecv = "我收到了" + new String(body);
                System.out.println(strRecv);
            }
        };

       
        //========================topic主题型交换机 *匹配====================================
        //获取生产者生产出来的数据
        //第一个参数表示 要从哪个队列里获取数据
        //第二个参数表示 是否要自动确认
        //第三个参数表示 主要通过它来获取数据
        channel.basicConsume("队列topic*",true, consumer);


        //关闭信道和连接 顺序从小到大
        /*channel.close();
        connection.close();*/
    }


}

6、Header自定义属性型交换机

不处理路由键。而是根据发送的消息内容中的headers属性进行匹配。在绑定Queue与Exchange时指定一组键值对;当消息发送到RabbitMQ时会取到该消息的headers与Exchange绑定时指定的键值对进行匹配;如果完全匹配则消息会路由到该队列,否则不会路由到该队列。

匹配规则x-match有下列两种类型:

x-match = all :表示所有的键值对都匹配才能接受到消息(不包括x-match)

x-match = any :表示至少有一个键值对匹配就能接受到消息

详情见视频 http://www.sikiedu.com/course/629/task/51898/show

// header交换机

channel.exchangeDeclare("exchange交换机小米-header-mathc-all","headers",true,false,null);

channel.queueDeclare("Queue小米header-mathc-all", true, false, false, null);

//设置消息头键值对信息

Map<String, Object> headers = new Hashtable<String,Object>();

//这里x-match有两种类型

//all:表示所有的键值对都匹配才能接受到消息

//any:表示最少一个键值对匹配就能接受到消息

headers.put("x-match", "any");

headers.put("name", "jack");

headers.put("age" , 31);

channel.queueBind("Queue小米header-mathc-all","exchange交换机小米-header-mathc-all", "", headers);

10、设置大小限制的队列
package com.study.rabbitmq.p03MaxLengthQueue;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/28 10:55
 * @description
 */
public class ProducerMaxLengthQueue {

    public static void main(String[] args) {


        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            Map<String,Object> map = new HashMap<>();
            map.put("x-max-length",2);    //最大保存2个消息(包括2个消息)


            //第一个参数是它的名字(最好是英文,见名知意)
            //第二个参数是否持久化到磁盘中
            //第三个参数是否独占
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息  比如设置大小限制的队列
            channel.queueDeclare("队列-最多保存2个消息",true,false,false,map);

            String str = "最大限制为2";
            channel.basicPublish("","队列-最多保存2个消息", null, str.getBytes());

            //关闭信道和连接 顺序从小到大
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }


    }
}

11、 生产端确认消息是否发送到了MQ

生产者将信道设置成confirm模式,一旦消息被被MQ接收了,MQ就会发送一个确认给生产者(包含消息的唯一ID);否则就表示消息没有到达MQ,可能由于网络闪断等原因。

image-20200528111848849.png

package com.study.rabbitmq.p04ConfirmListener;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/28 10:55
 * @description
 */
public class ProducerConfirmListener {

    public static void main(String[] args) {


        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            //第一个参数是它的名字(最好是英文,见名知意)
            //第二个参数是否持久化到磁盘中
            //第三个参数是否独占
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息 这里没有
            channel.queueDeclare("确认消息是否收到",true,false,false,null);


            String str = "确认消息是否收到MQ";


            //打开生产者的确认模式
            channel.confirmSelect();
            //添加确认监听
            channel.addConfirmListener((deliveryTag, multiple) -> {
                System.out.println("数据成功到达MQ");
            }, (deliveryTag, multiple)->{
                System.out.println("数据出错,可能原因是网络闪断,请排错");
            });

            channel.basicPublish("","确认消息是否收到", null, str.getBytes());

            //关闭信道和连接 顺序从小到大
            //channel.close();
            //connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }

    }
}
12、 Return 作用(确保路由规则设置正确)

在某种情况下,如果我们在发送消息的时候,当前的路由key错误,需要监听这种不可达的消息,就要使用return listener。

basicPublish 的参数Mandatory为false时,如果消息无法正确路由到队列后,会被MQ直接丢失

basicPublish 的参数mandatory设置true,消息无法正确路由到队列后,会返还给发送者

package com.study.rabbitmq.p05ReturnListener;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/29 09:51
 * @description
 */
public class ProducerReturnListener {

    public static void main(String[] args) {


        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            //创建一个交换机
            //声明一个直连型交换机
            //第一个参数是它的名字(最好是英文,见名知意),
            //第二个参数是它的交换机的类型,
            //第三个参数是否要保存到本地磁盘中
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息(这里暂时没有)
            channel.exchangeDeclare("交换机ReturnListener","direct",true,false,null);


            //有了交换机就创建一个相对应的队列
            //第一个参数是它的名字(最好是英文,见名知意)
            //第二个参数是否持久化到磁盘中
            //第三个参数是否独占
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息 这里没有
            channel.queueDeclare("队列ReturnListener",true,false,false,null);


            //进行绑定
            channel.queueBind("队列ReturnListener","交换机ReturnListener","有内鬼停止交易");


            String str = "确认消息是否收到MQ";

            //添加确认监听
            channel.addReturnListener(
                    // 第一个参数 返回的数字码
                    // 第二个参数 返回的文本信息
                    // 第三个参数 是哪个交换机
                    // 第四个参数 路由键
                    // 第五个参数 附带的信息 (信息清单等)
                    // 第六个参数 真正传输的数据是什么
                    new ReturnListener() {
                        @Override
                        public void handleReturn(
                                int replyCode,
                                String replyText,
                                String exchange,
                                String routingKey,
                                AMQP.BasicProperties properties,
                                byte[] body) throws IOException {

                            System.out.println(replyCode);
                            System.out.println(replyText);
                            System.out.println(exchange);
                            System.out.println(routingKey);
                            System.out.println(properties);
                            System.out.println(body);
                        }
                    }
            );


            //basicPublish方法,里面的参数mandatory设置true,消息无法正确路由到队列后,会返还给发送者
            // mandatory 则表示手动处理返回的信息 上面的ReturnListener才会得到错误的路由信息
            channel.basicPublish("交换机ReturnListener","有内鬼停止交易000", true, null, str.getBytes());

            //关闭信道和连接 顺序从小到大
            //channel.close();
            //connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }


    }


}

13、消费者限流QOS(削峰作用、重回队列)

//同一时刻服务器只会发送一条消息给消费者

channel.basicQos(10000);

//据说prefetchSize 和global这两项,rabbitmq没有实现,暂且不研究

channel.basicQos(0, 10000, false);

//消费者确认一条,再处理一条。

//最后一个false,是否为多条。

channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);

//消费时必须取消自动确认

channel.basicConsume("队列Qos限流",true,cosumer);

​ 示例代码:

package com.study.rabbitmq.p06ConsumerQos;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/29 10:42
 * @description 消费者
 */
public class ConsumerTomato {

    public static void main(String[] args) {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            //消费之前,先限流
            //第二个参数起到作用,表示每次最多处理一条消息
            channel.basicQos(0,1,false);


            DefaultConsumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
                    String strRecv = "我收到了" + new String(body);
                    System.out.println(strRecv);

                    //收到消息后,在通知消息中间件,在给我数据
                    // 第一个参数用于标识唯一包裹
                    // 第二个参数用于批处理 一般为false
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            };


            //autoAck  消费时必须取消自动确认,否则消息会直接都扔过来
            channel.basicConsume("队列Qos限流",false,consumer);


            //关闭信道和连接 顺序从小到大
           // channel.close();
           // connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }

}

14、自定义消费者处理

自己写的工具类

package com.study.rabbitmq.p07CustomConsumerClass;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;

/**
 * @author 武帅
 * @date 2020/5/30 09:28
 * @description 自己定义一个工具类
 */
public class ConsumerTomatoTool extends DefaultConsumer {


    public ConsumerTomatoTool(Channel channel) {
        super(channel);
    }

    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        String strRecv = "我收到了" + new String(body);
        System.out.println(strRecv);

        //收到消息后,在通知消息中间件,在给我数据
        // 第一个参数用于标识唯一包裹
        // 第二个参数用于批处理 一般为false
        getChannel().basicAck(envelope.getDeliveryTag(), false);
    }
}

生产者代码 其实没变

package com.study.rabbitmq.p07CustomConsumerClass;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/29 10:36
 * @description
 */
public class ProducerTomato {

    public static void main(String[] args) {


        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            //创建一个交换机
            //声明一个直连型交换机
            //第一个参数是它的名字(最好是英文,见名知意),
            //第二个参数是它的交换机的类型,
            //第三个参数是否要保存到本地磁盘中
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息(这里暂时没有)
            channel.exchangeDeclare("交换机Qos限流","direct",true,false,null);


            //有了交换机就创建一个相对应的队列
            //第一个参数是它的名字(最好是英文,见名知意)
            //第二个参数是否持久化到磁盘中
            //第三个参数是否独占
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息 这里没有
            channel.queueDeclare("队列Qos限流",true,false,false,null);


            //进行绑定
            channel.queueBind("队列Qos限流","交换机Qos限流","西红柿好吃吗");


            String str = "我爱西红柿";

            for (int i = 1; i <=5 ; i++) {
                channel.basicPublish("交换机Qos限流","西红柿好吃吗", false,null, str.getBytes());
            }

            //关闭信道和连接 顺序从小到大
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }

    }


}

消费者代码

package com.study.rabbitmq.p07CustomConsumerClass;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/29 10:42
 * @description 消费者
 */
public class ConsumerTomato {

    public static void main(String[] args) {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            //消费之前,先限流
            //第二个参数起到作用,表示每次最多处理一条消息
            channel.basicQos(0,1,false);

            //自己定义的工具类
            ConsumerTomatoTool consumer = new ConsumerTomatoTool(channel);

            //autoAck  消费时必须取消自动确认,否则消息会直接都扔过来
            channel.basicConsume("队列Qos限流",false,consumer);


            //关闭信道和连接 顺序从小到大
           // channel.close();
           // connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }

}
16、 TTL(消息的最大生存时长)
  1. TTL是Time To Live的缩写, 也就是生存时间

  2. RabbitMQ支持消息的过期时间, 在消息发送时可以进行指定

  3. RabbitMQ支持队列的过期时间, 从消息入队列开始计算, 只要超过了队列的超时时间配置, 那么消息会自动清除

队列里的所有消息最长的生存时间60秒

package com.study.rabbitmq.p08QueueTTL;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/30 09:53
 * @description
 */
public class ProducerBanana {

    public static void main(String[] args) {

        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            //创建一个交换机
            //声明一个直连型交换机
            //第一个参数是它的名字(最好是英文,见名知意),
            //第二个参数是它的交换机的类型,
            //第三个参数是否要保存到本地磁盘中
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息(这里暂时没有)
            channel.exchangeDeclare("交换机TTL60秒","direct",true,false,null);

            // 定义整个队列的所有的消息的TTL(最大存活时间)为20秒 当然通常情况下,时间控制的不会这么短
            Map<String,Object> map = new HashMap<>();
            // 20秒后消息还没有被消费,会被丢弃
            map.put("x-message-ttl",20000);

            //有了交换机就创建一个相对应的队列
            //第一个参数是它的名字(最好是英文,见名知意)
            //第二个参数是否持久化到磁盘中
            //第三个参数是否独占
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息 这里携带的是,数据最多的存活时间 如果使用则写在最后一个参数里,再把str注释打开
            channel.queueDeclare("队列TTL60秒",true,false,false,null);


            //进行绑定
            channel.queueBind("队列TTL60秒","交换机TTL60秒","香蕉好吃吗");


            //String str = "我爱吃香蕉";

            //channel.basicPublish("交换机TTL60秒","香蕉好吃吗", false,null, str.getBytes());


           //这个是设置某一条消息的最大存活时间 为7秒
            String str222 = "我爱吃香蕉222";
            AMQP.BasicProperties properties = new AMQP.BasicProperties()
                                                .builder()
                                                .expiration("7000")
                                                .build();

            channel.basicPublish("交换机TTL60秒","香蕉好吃吗", false,properties, str222.getBytes());


            //关闭信道和连接 顺序从小到大
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }


    }

}

17、 死信队列(问题产品(专用)货架)

测试时,让消息过期后,消息会被转移到死信队列上

出现死信的三种情况

​ 1、消息被拒绝(basic.reject/ basic.nack)并且requeue=false

​ 2、消息TTL过期(参考:RabbitMQ之TTL(Time-To-Live 过期时间))

​ 3、队列达到最大长度

给一个正常队列A添加一个死信队列DLX,当A中出现死信时,会被自动路由到DLX交换机对应的队列,从而不去影响正常的队列处理数据

死信队列的原理和作用:
image-20200530103953414.png

image-20200530104005393.png

准备基本的生产者和消费者的代码

​ 生产者

package com.study.rabbitmq.p09DeadLetter;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/30 09:53
 * @description
 */
public class ProducerBanana {

    public static void main(String[] args) {

        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            //创建一个交换机
            //声明一个直连型交换机
            //第一个参数是它的名字(最好是英文,见名知意),
            //第二个参数是它的交换机的类型,
            //第三个参数是否要保存到本地磁盘中
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息(这里暂时没有)
            channel.exchangeDeclare("交换机正常生产20秒","direct",true,false,null);

            // 定义整个队列的所有的消息的TTL(最大存活时间)为20秒 当然通常情况下,时间控制的不会这么短
            Map<String,Object> map = new HashMap<>();
            // 20秒后消息还没有被消费,会被丢弃
            map.put("x-message-ttl",20000);

            //有了交换机就创建一个相对应的队列
            //第一个参数是它的名字(最好是英文,见名知意)
            //第二个参数是否持久化到磁盘中
            //第三个参数是否独占
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息 这里携带的是,数据最多的存活时间 如果使用则写在最后一个参数里, 再把str注释打开
            channel.queueDeclare("队列正常生产活20秒",true,false,false,map);


            //进行绑定
            channel.queueBind("队列正常生产活20秒","交换机正常生产20秒","香蕉好吃吗");


            String str = "我爱吃香蕉";

            channel.basicPublish("交换机正常生产20秒","香蕉好吃吗", false,null, str.getBytes());


            //关闭信道和连接 顺序从小到大
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }


    }

}

消费者

package com.study.rabbitmq.p09DeadLetter;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/30 11:00
 * @description
 */
public class ConsumerBanana {

    public static void main(String[] args) {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            DefaultConsumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
                    String strRecv = "我收到了" + new String(body);
                    System.out.println(strRecv);

                    //收到消息后,在通知消息中间件,在给我数据
                    // 第一个参数用于标识唯一包裹
                    // 第二个参数用于批处理 一般为false
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            };

		   //autoAck  消费时必须取消自动确认,否则消息会直接都扔过来
            channel.basicConsume("交换机正常生产",false,consumer);


            //关闭信道和连接 顺序从小到大
            // channel.close();
            // connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }


    }

}
准备死信的生产者和死信的消费者的代码

死信的生产者 在这里死信的生产者和基本的生产者是写在一个类里面

package com.study.rabbitmq.p09DeadLetter;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/30 09:53
 * @description
 */
public class ProducerBanana {

    public static void main(String[] args) {

        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();

            //创建一个死信交换机
            channel.exchangeDeclare("交换机---处理死信","topic",true,false,null);

            //创建一个死信队列
            channel.queueDeclare("队列---处理死信",true,false,false,null);

            //死信交换机和死信队列 进行绑定
            channel.queueBind("队列---处理死信","交换机---处理死信","#");


            //创建一个交换机
            //声明一个直连型交换机
            //第一个参数是它的名字(最好是英文,见名知意),
            //第二个参数是它的交换机的类型,
            //第三个参数是否要保存到本地磁盘中
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息(这里暂时没有)
            channel.exchangeDeclare("交换机正常生产20秒","direct",true,false,null);

            // 定义整个队列的所有的消息的TTL(最大存活时间)为20秒 当然通常情况下,时间控制的不会这么短
            Map<String,Object> map = new HashMap<>();
            // 20秒后消息还没有被消费,会被丢弃
            map.put("x-message-ttl",20000);
            // 正常队列 和 死信交换机进行绑定
            map.put("x-dead-letter-exchange","交换机---处理死信");

            //有了交换机就创建一个相对应的队列
            //第一个参数是它的名字(最好是英文,见名知意)
            //第二个参数是否持久化到磁盘中
            //第三个参数是否独占
            //第四个参数是否要自动删除
            //第五个参数是它要携带的头信息 这里携带的是,数据最多的存活时间 如果使用则写在最后一个参数里, 再把str注释打开
            channel.queueDeclare("队列正常生产活20秒",true,false,false,map);


            //进行绑定
            channel.queueBind("队列正常生产活20秒","交换机正常生产20秒","香蕉好吃吗");


            String str = "我爱吃香蕉";

            channel.basicPublish("交换机正常生产20秒","香蕉好吃吗", false,null, str.getBytes());


            //关闭信道和连接 顺序从小到大
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }


    }

}

死信的消费者

package com.study.rabbitmq.p09DeadLetter;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author 武帅
 * @date 2020/5/30 11:00
 * @description
 */
public class ConsumerDeadLetter {

    public static void main(String[] args) {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            DefaultConsumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
                    String strRecv = "我收到了" + new String(body);
                    System.out.println("确认了死信的信息:"+strRecv);

                    //收到消息后,在通知消息中间件,在给我数据
                    // 第一个参数用于标识唯一包裹
                    // 第二个参数用于批处理 一般为false
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            };


            //autoAck  消费时必须取消自动确认,否则消息会直接都扔过来
            channel.basicConsume("队列---处理死信",false,consumer);


            //关闭信道和连接 顺序从小到大
            // channel.close();
            // connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }

    }

}

拒绝消息队列的代码
public static void main(String[] args) {
        // 创建连接工厂,用来修建高速公路
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //设置基本配置
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //修建一条高速公路
        Connection connection = null;
        try {
            connection = connectionFactory.newConnection();
            //画定双向车道
            Channel channel = connection.createChannel();


            DefaultConsumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body)
                        throws IOException
                {
                    String strRecv = "我收到了" + new String(body);
                    System.out.println("确认了死信的信息:"+strRecv+"拒绝消息");


                    // 拒绝 消费队列的消息
                    // 第一个参数用于标识唯一包裹
                    // 第二个参数用于批处理 一般为false
                    channel.basicReject(envelope.getDeliveryTag(), false);
                }
            };


            //autoAck  消费时必须取消自动确认,否则消息会直接都扔过来
            channel.basicConsume("队列---处理死信",false,consumer);


            //关闭信道和连接 顺序从小到大
            // channel.close();
            // connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }

    }
死信处理 ---队列达到最大长度

public static void main(String[] args) {

    // 创建连接工厂,用来修建高速公路
    ConnectionFactory connectionFactory = new ConnectionFactory();

    //设置基本配置
    connectionFactory.setHost("localhost");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");

    //修建一条高速公路
    Connection connection = null;
    try {
        connection = connectionFactory.newConnection();
        //画定双向车道
        Channel channel = connection.createChannel();


        //创建一个交换机
        //声明一个直连型交换机
        //第一个参数是它的名字(最好是英文,见名知意),
        //第二个参数是它的交换机的类型,
        //第三个参数是否要保存到本地磁盘中
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息(这里暂时没有)
        channel.exchangeDeclare("交换机正常生产-队列最多保存2个","direct",true,false,null);

        Map<String,Object> map = new HashMap<>();
        map.put("x-max-length",2);
        map.put("x-dead-letter-exchange","交换机---处理死信");


        //有了交换机就创建一个相对应的队列
        //第一个参数是它的名字(最好是英文,见名知意)
        //第二个参数是否持久化到磁盘中
        //第三个参数是否独占
        //第四个参数是否要自动删除
        //第五个参数是它要携带的头信息 这里携带的是,最多保存多少个数据 如果使用则写在最后一个参数里
        channel.queueDeclare("队列正常生产-队列最多保存2个",true,false,false,map);


        //进行绑定
        channel.queueBind("队列正常生产-队列最多保存2个","交换机正常生产-队列最多保存2个","香蕉好吃吗");


        String str = "我爱吃香蕉";

        for (int i = 1; i <=3 ; i++) {
            channel.basicPublish("交换机正常生产-队列最多保存2个","香蕉好吃吗", false,null, str.getBytes());
        }

        //关闭信道和连接 顺序从小到大
        channel.close();
        connection.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (TimeoutException e) {
        e.printStackTrace();
    }


}
18、RabbitMQ和Spring的整合
1、 重要的类

RabbitAdmin可以很好的处理交换机和队列,修改,删除并且可以注解到spring里

RabbitTemplate类负责收发消息

2、创建SpringBoot工程
<!-- 添加rabbitmq的基本依赖 -->   
<dependency>
	<groupid>com.rabbitmq</groupid>
	<artifactid>amqp-client<artifactid>
</dependency>
    
 <!-- Spring对rabbitmq支持的依赖 -->
<dependency>
	<groupId>org.springframework.amqp</groupId>
	<artifactId>spring-rabbit</artifactId>
</dependency>
 
<!-- SpringBoot对rabbitmq支持的依赖 -->
<dependency>
	<groupid>com.springframework.boot<groupid>
	<artifactid>spring-boot-starter-amqp<artifactid>
</dependency>
        
版本使用boot默认
3、创建一个配置类
package com.study.rabbitmq;

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author 武帅
 * @date 2020/5/31 10:04
 * @description
 */
//等价于配置文件(***.xml)
@Configuration
public class ConfigurationRabbitmq {

    //连接工厂
    //ConnectionFactory 注意不再是rabbit里的了,而是spring里面的
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses("localhost:5672");
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        return connectionFactory;
    }



    //管理交换机和队列的RabbitAdmin
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }


}
4、RabbitAdmin声明队列交换机并进行绑定
package com.study.rabbitmq;

import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class RabbitmqApplicationTests {

    @Autowired
    private RabbitAdmin rabbitAdmin;


    @Test
    void test测试产生队列交换机进行绑定(){

        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchange = new DirectExchange("交换机spring短信",true,false,null);

        //创建交换机
        rabbitAdmin.declareExchange(exchange);


        //需要导入这个类 import org.springframework.amqp.core.Queue;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否独占 (一般不使用独占,除非是特殊业务)
        //第四个参数 是否自动删除
        Queue queue = new Queue("队列spring短信",true,false,false);

        //创建队列
        rabbitAdmin.declareQueue(queue);


        //需要引入这个包 import org.springframework.amqp.core.Binding;
        //第一个参数 需要绑定的队列名字
        //第二个参数 绑定的类型 (是一个枚举)
        //第三个参数 需要绑定的交换机名字
        //第四个参数 路由键 (这里是直连型交换机。路由键必须保持一致)
        //第五个参数 携带的头信息 这里暂时没有
        Binding binding = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信","发送短信",null);

        //进行绑定
        rabbitAdmin.declareBinding(binding);

    }

}
5、RabbitAdmin创建四种类型的交换机并绑定到一个队列

​ 代码如下:

package com.study.rabbitmq;

import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.Map;

@SpringBootTest
class RabbitmqApplicationTests {

    @Autowired
    private RabbitAdmin rabbitAdmin;


    @Test
    void test测试产生队列交换机进行绑定(){

        //创建直连型交换机
        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchangeDirect = new DirectExchange("交换机spring短信",true,false,null);

        //把上面的值进行入参
        rabbitAdmin.declareExchange(exchangeDirect);


        //创建fanout型交换机
        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchangeFanout = new FanoutExchange("交换机spring短信-fanout",true,false,null);

        //把上面的值进行入参
        rabbitAdmin.declareExchange(exchangeFanout);


        //创建topic型交换机
        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchangeTopicStar = new TopicExchange("交换机spring短信-topic",true,false,null);

        //把上面的值进行入参
        rabbitAdmin.declareExchange(exchangeTopicStar);


        //创建header型交换机
        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchangeHeader = new HeadersExchange("交换机spring短信-header",true,false,null);

        //把上面的值进行入参
        rabbitAdmin.declareExchange(exchangeHeader);



        //创建队列 这里就创建了一个队列和4个交换机进行绑定
        //需要导入这个类 import org.springframework.amqp.core.Queue;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否独占 (一般不使用独占,除非是特殊业务)
        //第四个参数 是否自动删除
        Queue queue = new Queue("队列spring短信",true,false,false);

        //把上面的值传递过来
        rabbitAdmin.declareQueue(queue);


        //使用直连型交换机和队列进行绑定
        //需要引入这个包 import org.springframework.amqp.core.Binding;
        //第一个参数 需要绑定的队列名字
        //第二个参数 绑定的类型 (是一个枚举)
        //第三个参数 需要绑定的交换机名字
        //第四个参数 路由键 (这里是直连型交换机。路由键必须保持一致)
        //第五个参数 携带的头信息 这里暂时没有
        Binding binding = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信","发送短信",null);

        //把上面的参数传递过来
        rabbitAdmin.declareBinding(binding);


        //使用fanout型交换机和队列进行绑定
        //需要引入这个包 import org.springframework.amqp.core.Binding;
        //第一个参数 需要绑定的队列名字
        //第二个参数 绑定的类型 (是一个枚举)
        //第三个参数 需要绑定的交换机名字
        //第四个参数 路由键 (这里是fanout型交换机。没有路由键也可以)
        //第五个参数 携带的头信息 这里暂时没有
        Binding bindingFanout = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信-fanout","",null);

        //把上面的参数传递过来
        rabbitAdmin.declareBinding(bindingFanout);

        //使用topic型交换机和队列进行绑定
        //需要引入这个包 import org.springframework.amqp.core.Binding;
        //第一个参数 需要绑定的队列名字
        //第二个参数 绑定的类型 (是一个枚举)
        //第三个参数 需要绑定的交换机名字
        //第四个参数 路由键 (这里是topic型交换机)
        //                  .*代表没有,或者一个(不能多个)
        //第五个参数 携带的头信息 这里暂时没有
        Binding bindingTopic = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信-topic","0086.*",null);

        //把上面的参数传递过来
        rabbitAdmin.declareBinding(bindingTopic);


        //header型交换机的参数 这里的all表示除去第一个参数,其余的都得有和正确才行, any表示有一个就可以
        Map<String,Object> map = new HashMap<>();
        map.put("x-match","all");
        map.put("userName","华为");
        map.put("passWord","123456");

        //使用header型交换机和队列进行绑定
        //需要引入这个包 import org.springframework.amqp.core.Binding;
        //第一个参数 需要绑定的队列名字
        //第二个参数 绑定的类型 (是一个枚举)
        //第三个参数 需要绑定的交换机名字
        //第四个参数 路由键 (这里是header型交换机。没有路由键也可以)
        //第五个参数 携带的头信息 这里暂时没有
        Binding bindingHeader = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信-header","",map);

        //把上面的参数传递过来
        rabbitAdmin.declareBinding(bindingHeader);





    }

}

6、RabbitAdmin清空和删除队列API

​ 代码如下:

    //测试删除队列和清除队列消息   Purge : 清除
    @Test
    void testDeleteQueuesAndPurgeQueueMessage(){

        //清除队列消息 只有这个队列存在和队列名字正确,才可以清除,系统不报错
        rabbitAdmin.purgeQueue("队列topic*");


        //删除队列
        rabbitAdmin.deleteQueue("队列spring短信");

        //删除交换机
        rabbitAdmin.deleteExchange("交换机spring短信");
        rabbitAdmin.deleteExchange("交换机spring短信-fanout");
        rabbitAdmin.deleteExchange("交换机spring短信-topic");
        rabbitAdmin.deleteExchange("交换机spring短信-header");

    }
7、使用Bean注解创建交换机和队列绑定

也就是使用Spring创建交换机和队列

代码如下:

@Configuration
public class ConfigurationRabbitmq //这个类里多出来的代码
    
    //使用Bean注解创建队列  也就是使用Spring创建队列
    @Bean
    public Queue queueSMS(){
        //创建队列
        //需要导入这个类 import org.springframework.amqp.core.Queue;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否独占 (一般不使用独占,除非是特殊业务)
        //第四个参数 是否自动删除
        Queue queue = new Queue("队列spring短信",true,false,false);
        return queue;
    }


    //使用Bean注解创建直连型交换机  也就是使用Spring创建直连型交换机
	//如果嫌这种入参方式麻烦,也可以使用链式编程,连续...的方式 
                            //queueSMS()表示队列的名字
                            //exchangeDirect()表示交换机的名字
                            //"发送短信" 表示 路由键
                            //and(null); null 表示附加的值
                            //Binding binding = 	  BindingBuilder.bind(queueSMS()).to(exchangeDirect()).with("发送短信").and(null);
    @Bean
    public Exchange exchangeDirect(){
        //创建直连型交换机
        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchangeDirect = new DirectExchange("交换机spring短信",true,false,null);
        return exchangeDirect;
    }


    //使用Bean注解创建fanout交换机  也就是使用Spring创建fanout交换机
    @Bean
    public Exchange exchangeFanout(){
        //创建fanout型交换机
        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchangeFanout = new FanoutExchange("交换机spring短信-fanout",true,false,null);
        return exchangeFanout;
    }


    //使用Bean注解创建topic交换机  也就是使用Spring创建topic交换机
    @Bean
    public Exchange exchangeTopicStar(){
        //创建topic型交换机
        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchangeTopicStar = new TopicExchange("交换机spring短信-topic",true,false,null);
        return exchangeTopicStar;
    }


    //使用Bean注解创建header交换机  也就是使用Spring创建header交换机
    @Bean
    public Exchange exchangeHeader(){
        //创建header型交换机
        //需要导入这个类 import org.springframework.amqp.core.Exchange;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否自动删除
        //第四个参数 携带的头信息 这里暂时没有
        Exchange exchangeHeader = new HeadersExchange("交换机spring短信-header",true,false,null);
        return exchangeHeader;
    }

    //使用Bean注解绑定直连型交换机
    @Bean
    public Binding bindingDirect(){
        Binding binding = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信","发送短信",null);
        return binding;
    }

    //使用Bean注解绑定fanout型交换机
    @Bean
    public Binding bindingFanout(){
        Binding bindingFanout = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信-fanout","",null);
        return bindingFanout;
    }

    //使用Bean注解绑定topic型交换机
    @Bean
    public Binding bindingTopic(){
        Binding bindingTopic = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信-topic","0086.*",null);
        return bindingTopic;
    }

    //使用Bean注解绑定header型交换机
    @Bean
    public Binding bindingHeader(){
        //header型交换机的参数 这里的all表示除去第一个参数,其余的都得有和正确才行, any表示有一个就可以
        Map<String,Object> map = new HashMap<>();
        map.put("x-match","all");
        map.put("userName","华为");
        map.put("passWord","123456");

        Binding bindingHeader = new Binding("队列spring短信",Binding.DestinationType.QUEUE,"交换机spring短信-header","",map);
        return bindingHeader;
    }
   

测试类里的代码:

 	@Autowired
    private Binding bindingDirect;

    @Autowired
    private Binding bindingFanout;

    @Autowired
    private Binding bindingTopic;

    @Autowired
    private Binding bindingHeader;

    //使用Bean注解创建交换机和队列绑定  也就是使用Spring创建交换机和队列
    @Test
    void testDefineQueueExchangeBindingBySpring(){
        rabbitAdmin.declareBinding(bindingDirect);
        rabbitAdmin.declareBinding(bindingFanout);
        rabbitAdmin.declareBinding(bindingTopic);
        rabbitAdmin.declareBinding(bindingHeader);
    }
8、RabbitTemplate使用convertAndSend方法发送消息

配置类的代码:

	//创建一个可以收发消息的模板 (这个平时用的比较多)
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

测试类代码:

@SpringBootTest
class TestRabbitmqTemplate {


    @Autowired
    private RabbitTemplate rabbitTemplate;

    //使用RabbitMq模板给交换机发送消息 使用convertAndSend()方法
    @Test
    void TestSimpleSend(){

        //第一个参数 交换机的名字
        //第二个参数 路由键 (因为是直连型交换机,所以路由键必须一致)
        //第三个参数 发送的具体信息 (这里不用使用 .getBytes()方法了)
        //也可以使用第4个参数 携带的头信息
        String sendSMS = "直连型交换机发送短信";
        rabbitTemplate.convertAndSend("交换机spring短信", "发送短信", sendSMS, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().getHeaders().put("登录次数",2);
                return message;
            }
        });


    }


}
9、RabbitTemplate使用Send方法发送消息

​ 代码如下:

//使用RabbitMq模板给交换机发送消息 使用send()方法
    @Test
    void testSend(){

        String sendSMS = "使用send()方法来发送短信";

        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        properties.getHeaders().put("登录次数",3);

        Message message = new Message(sendSMS.getBytes(),properties);

        rabbitTemplate.send("交换机spring短信-fanout","",message);
    }


    //使用RabbitMq模板给交换机发送消息 使用send()方法
    @Test
    void testSendTopicAndHeaders(){

        //给Topic交换机上发送消息
        String sendSMSTopic = "使用send()方法来发送短信---Topic型交换机";

        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        properties.getHeaders().put("登录次数",4);

        Message message = new Message(sendSMSTopic.getBytes(),properties);

        rabbitTemplate.send("交换机spring短信-topic","0086.18734910102",message);


        //给Header交换机上发送消息
        String sendSMSHeader = "使用send()方法来发送短信---Header型交换机";

        MessageProperties propertiesHeader = new MessageProperties();
        propertiesHeader.setContentEncoding("UTF-8");
        propertiesHeader.getHeaders().put("userName","华为");
        propertiesHeader.getHeaders().put("passWord","123456");
        propertiesHeader.getHeaders().put("登录次数",5);


        Message messageHeaders = new Message(sendSMSHeader.getBytes(),propertiesHeader);

        rabbitTemplate.send("交换机spring短信-header","",messageHeaders);
    }
10、RabbitTemplate使用Receive方法接收消息
package com.study.rabbitmq.p02TestRabbitmqTemplate;

import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Map;

/**
 * @author 武帅
 * @date 2020/6/5 09:26
 * @description
 */
@SpringBootTest
class TestRabbitmqTemplateReceive {


    @Autowired
    private RabbitTemplate rabbitTemplate;

    //使用RabbitMq模板接收消息
    @Test
    void testReceive(){

        //一般不怎么使用while循环true 这里只是为了测试用下
        while (true){
            //第一个参数 交换机的名字
            //第二个参数 毫秒数 如果2秒中内,没有消息就退出这个消息
            Message message = rabbitTemplate.receive("队列spring短信", 2000);

            if(message == null){
                break;
            }
            String str = new String(message.getBody());
            System.out.println("收到了" + str);

            //获取头信息
            Map<String, Object> headers = message.getMessageProperties().getHeaders();

            //遍历头信息
            for (Map.Entry<String, Object> entry : headers.entrySet()) {
                System.out.println(entry);
            }

        }
    }



}
11、SimpleMessageListenerContainer基本属性和标识策略, 使用MessageListener接收并处理消息

要在SpringBoot下启动,如果在测试单元下,则会出现问题

package com.study.rabbitmq;

import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.ConsumerTagStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

/**
 * @author 武帅
 * @date 2020/6/5 11:14
 * @description 消费者的配置文件
 */
@Configuration
public class ConfigurationConsumer {


    //使用Bean注解创建队列  也就是使用Spring创建队列
    @Bean
    public Queue queueXiaoMi(){
        //创建队列
        //需要导入这个类 import org.springframework.amqp.core.Queue;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否独占 (一般不使用独占,除非是特殊业务)
        //第四个参数 是否自动删除
        Queue queue = new Queue("队列spring-监听器-小米",true,false,false);
        return queue;
    }

    //使用Bean注解创建队列  也就是使用Spring创建队列
    @Bean
    public Queue queueHongMi(){
        //创建队列
        //需要导入这个类 import org.springframework.amqp.core.Queue;
        //第一个参数 名字(最好是英文)见名知意
        //第二个参数 是否要持久化到本地磁盘中
        //第三个参数 是否独占 (一般不使用独占,除非是特殊业务)
        //第四个参数 是否自动删除
        Queue queue = new Queue("队列spring-监听器-红米",true,false,false);
        return queue;
    }


    private Integer num = 0;

    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO表示为自动模式
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //设置消息监听器
        simpleMessageListenerContainer.setMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message message) {
                //获取出消息,在打印
                String oneData = new String(message.getBody());
                System.out.println( "收到了消息:" + oneData);

                //获取信息的自定义内容
                Map<String, Object> headers = message.getMessageProperties().getHeaders();

                //遍历获取信息的自定义内容
                for (Map.Entry<String, Object> entry : headers.entrySet()) {
                    System.out.println(entry);
                }

            }
        });


        return simpleMessageListenerContainer;
    }

}

使用生产者生产数据,测试数据

//使用RabbitMq模板给交换机发送消息 使用send()方法
    @Test
    void testSendTopicAndHeaders(){

        //给Topic交换机上发送消息
        String sendSMSTopic = "使用send()方法来发送短信---Topic型交换机";

        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        properties.getHeaders().put("登录次数",4);

        Message message = new Message(sendSMSTopic.getBytes(),properties);

        rabbitTemplate.send("交换机spring短信-topic","0086.18734910102",message);


        //给Header交换机上发送消息
        String sendSMSHeader = "使用send()方法来发送短信---Header型交换机";

        MessageProperties propertiesHeader = new MessageProperties();
        propertiesHeader.setContentEncoding("UTF-8");
        propertiesHeader.getHeaders().put("userName","华为");
        propertiesHeader.getHeaders().put("passWord","123456");
        propertiesHeader.getHeaders().put("登录次数",5);


        Message messageHeaders = new Message(sendSMSHeader.getBytes(),propertiesHeader);

        rabbitTemplate.send("交换机spring短信-header","",messageHeaders);
    }
12、使用ChannelAwareMessageListener接收消息-手动确认消息
//测试手动接受消息确认
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.MANUAL表示手动接收消息
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.MANUAL);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //设置消息监听器
        simpleMessageListenerContainer.setMessageListener(new ChannelAwareMessageListener() {
            @Override
            public void onMessage(Message message, Channel channel) throws Exception {
                //获取出消息,在打印
                String oneData = new String(message.getBody());
                System.out.println( "收到了消息:" + oneData);

                //获取信息的自定义内容
                Map<String, Object> headers = message.getMessageProperties().getHeaders();

                //遍历获取信息的自定义内容
                for (Map.Entry<String, Object> entry : headers.entrySet()) {
                    System.out.println(entry);
                }

                //对消息进行了手动的确认  第二个参数表示:是否批量(这里我们是一条一条处理,所以不用批量)
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);

                //也可以使用这种方法 nack增加了重回队列的参数,最后一个false代表不用重回
                //channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);



            }

        });

        return simpleMessageListenerContainer;
    }

使用生产者生产数据,测试数据

//使用RabbitMq模板给交换机发送消息 使用send()方法
    @Test
    void testSendTopicAndHeaders(){

        //给Topic交换机上发送消息
        String sendSMSTopic = "使用send()方法来发送短信---Topic型交换机";

        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        properties.getHeaders().put("登录次数",4);

        Message message = new Message(sendSMSTopic.getBytes(),properties);

        rabbitTemplate.send("交换机spring短信-topic","0086.18734910102",message);


        //给Header交换机上发送消息
        String sendSMSHeader = "使用send()方法来发送短信---Header型交换机";

        MessageProperties propertiesHeader = new MessageProperties();
        propertiesHeader.setContentEncoding("UTF-8");
        propertiesHeader.getHeaders().put("userName","华为");
        propertiesHeader.getHeaders().put("passWord","123456");
        propertiesHeader.getHeaders().put("登录次数",5);


        Message messageHeaders = new Message(sendSMSHeader.getBytes(),propertiesHeader);

        rabbitTemplate.send("交换机spring短信-header","",messageHeaders);
    }
13、 使用MessageListenerAdapter类进行消息接收并处理 消息监听适配器(在实际中运用的比较多)

使用MessageListenerAdapter处理器进行消息队列监听处理,如果容器没有设置setDefaultListenerMethod,则处理器中默认的处理方法名是handleMessage,如果设置了setDefaultListenerMethod,则处理器中处理消息的方法名就是setDefaultListenerMethod方法参数设置的值。也可以通过setQueueOrTagToMethodName方法为不同的队列设置不同的消息处理方法

自定义消息处理类,注意方法名和参数类型必须要一致

首先自己先定义一个MessageDelegate

package com.study.rabbitmq.p10TestSpringListenerAdaper;

/**
 * @author 武帅
 * @date 2020/6/7 10:55
 * @description
 */
public class MyMessageDelegate {

    public void handleMessage(byte[] body){
        String strMessage = new String(body);
        System.out.println("我收到了:" + strMessage);
    }


}

然后再自己写监听适配器对消息进行接受和消费

    //使用监听适配器对消息进行接受和消费
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO 表示对消息进行自动确认
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //使用MessageListenerAdapter类进行消息接收并处理
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter();
        //new MyMessageDelegate() 这里使用自己的方法
        messageListenerAdapter.setDelegate(new MyMessageDelegate());

        //进行绑定
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);

        return simpleMessageListenerContainer;
    }

发送数据

   //使用RabbitMq模板给交换机发送消息 使用send()方法
    @Test
    void testSendTopicAndHeaders(){

        //给Topic交换机上发送消息
        String sendSMSTopic = "使用send()方法来发送短信---Topic型交换机";

        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        properties.getHeaders().put("登录次数",4);

        Message message = new Message(sendSMSTopic.getBytes(),properties);

        rabbitTemplate.send("交换机spring短信-topic","0086.18734910102",message);


        //给Header交换机上发送消息
        String sendSMSHeader = "使用send()方法来发送短信---Header型交换机";

        MessageProperties propertiesHeader = new MessageProperties();
        propertiesHeader.setContentEncoding("UTF-8");
        propertiesHeader.getHeaders().put("userName","华为");
        propertiesHeader.getHeaders().put("passWord","123456");
        propertiesHeader.getHeaders().put("登录次数",5);


        Message messageHeaders = new Message(sendSMSHeader.getBytes(),propertiesHeader);

        rabbitTemplate.send("交换机spring短信-header","",messageHeaders);
    }

注意:这里和上面的使用方法为:必须是先使用测试单元,添加数据(添加之前先注释自己写好的@Bean),然后再解除注释,然后再次启动SpringBoot

14、MessageListenerAdapter自定义方法接收消息-绑定队列和处理方法

自定义方法接收消息的代码:

	//自定义的处理消息的方法名称
    public void myHandleMessage(byte[] body){
        String strMessage = new String(body);
        System.out.println("自定义名称的方法 我收到了:" + strMessage);
    }

​ 配置类的代码

  	//使用监听适配器对消息进行接受和消费
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO 表示对消息进行自动确认
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //使用MessageListenerAdapter类进行消息接收并处理
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter();
        //new MyMessageDelegate() 这里使用自己的方法
        messageListenerAdapter.setDelegate(new MyMessageDelegate());

        //使用自己定义的MessageDelegate
        messageListenerAdapter.setDefaultListenerMethod("myHandleMessage");

        //进行绑定
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);

        return simpleMessageListenerContainer;
    }

生产者生产的代码

	//使用RabbitMq模板给交换机发送消息 使用send()方法
    @Test
    void testSendTopicAndHeaders(){

        //给Topic交换机上发送消息
        String sendSMSTopic = "使用send()方法来发送短信---Topic型交换机";

        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        properties.getHeaders().put("登录次数",4);

        Message message = new Message(sendSMSTopic.getBytes(),properties);

        rabbitTemplate.send("交换机spring短信-topic","0086.18734910102",message);


        //给Header交换机上发送消息
        String sendSMSHeader = "使用send()方法来发送短信---Header型交换机";

        MessageProperties propertiesHeader = new MessageProperties();
        propertiesHeader.setContentEncoding("UTF-8");
        propertiesHeader.getHeaders().put("userName","华为");
        propertiesHeader.getHeaders().put("passWord","123456");
        propertiesHeader.getHeaders().put("登录次数",5);


        Message messageHeaders = new Message(sendSMSHeader.getBytes(),propertiesHeader);

        rabbitTemplate.send("交换机spring短信-header","",messageHeaders);
    }

绑定队列和处理方法de的代码:

 //专用于处理消息队列-小米手机的方法
    public void myHandleMessageXiaoMi(byte[] body){
        String strMessage = new String(body);
        System.out.println("自定义名称的方法-小米 我收到了:" + strMessage);
    }


    //专用于处理消息队列-红米手机的方法
    public void myHandleMessageHongMi(byte[] body){
        String strMessage = new String(body);
        System.out.println("自定义名称的方法-红米 我收到了:" + strMessage);
    }

配置类代码

//使用监听适配器,针对不同队列的消息使用不同的方法,进行处理
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO 表示对消息进行自动确认
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //使用MessageListenerAdapter类进行消息接收并处理
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter();
        //new MyMessageDelegate() 这里使用自己的方法
        messageListenerAdapter.setDelegate(new MyMessageDelegate());

        //这个Map记录了哪个队列使用哪个方法 key为队列的名字 value为方法的名字
        Map<String,String> queueMethod = new HashMap<>();
        queueMethod.put("队列spring-监听器-小米","myHandleMessageXiaoMi");
        queueMethod.put("队列spring-监听器-红米","myHandleMessageHongMi");

        //通过队列的名字来和方法的名字进行绑定  (此处使用Map集合)
        messageListenerAdapter.setQueueOrTagToMethodName(queueMethod);


        //进行绑定
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);

        return simpleMessageListenerContainer;
    }

生产者的代码:

@Test
    void testSendToXiaoMiAndHongMi(){

        //给Topic交换机上发送消息
        String sendSMSTopic = "一部小米手机";

        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");


        Message message = new Message(sendSMSTopic.getBytes(),properties);

        rabbitTemplate.send("","队列spring-监听器-小米",message);


        //给Header交换机上发送消息
        String sendSMSHeader = "一部红米手机";

        MessageProperties propertiesHeader = new MessageProperties();
        propertiesHeader.setContentEncoding("UTF-8");


        Message messageHeaders = new Message(sendSMSHeader.getBytes(),propertiesHeader);

        rabbitTemplate.send("","队列spring-监听器-红米",messageHeaders);
    }
15、 MessageConverter自定义接收数据类型

MessageConverter自定义接收数据类型的代码:

package com.study.rabbitmq.p10TestSpringListenerAdaper;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;

/**
 * @author 武帅
 * @date 2020/6/7 16:18
 * @description 自定义文本转换器
 *      MessageConverter自定义接收数据类型
 *
 * 	    类型转换器(实现接口MessageConverter)
 */
public class MyMessageTestConverter implements MessageConverter {


    // java对象转换为Message对象
    @Override
    public Message toMessage(Object o, MessageProperties messageProperties) throws MessageConversionException {
        Message message = new Message(o.toString().getBytes(),messageProperties);
        return message;
    }


    // Message对象转换为java对象
    @Override
    public Object fromMessage(Message message) throws MessageConversionException {

        String contentType = message.getMessageProperties().getContentType();
        if(contentType != null && contentType.contains("text")){
            String str = new String(message.getBody());
            return str;
        }else{
            //对于不是文本的类型,直接返回字节数组
            return message.getBody();
        }
    }
}

配置类代码:

    //使用监听适配器,针对不同队列的消息使用不同的方法,进行处理
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO 表示对消息进行自动确认
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //使用MessageListenerAdapter类进行消息接收并处理
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter();

        //设置消息的转换器
        messageListenerAdapter.setMessageConverter(new MyMessageTestConverter());

        //new MyMessageDelegate() 这里使用自己的方法
        messageListenerAdapter.setDelegate(new MyMessageDelegate());

        //使用自己的类型转换器
        messageListenerAdapter.setDefaultListenerMethod("myHandleMessage");

        //进行绑定
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);

        return simpleMessageListenerContainer;
    }

处理方法的参数为转换过的字符串类型的代码:

    // 处理方法的参数为转换过的字符串类型
    public void myHandleMessage(String str){
        System.out.println( "处理方法的参数为转换过的字符串类型" + str);
    }

生产者的代码:

	@Test
    void testSendToXiaoMiAndHongMi(){

        //给Topic交换机上发送消息
        String sendSMSTopic = "一部小米手机";

        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");


        Message message = new Message(sendSMSTopic.getBytes(),properties);

        rabbitTemplate.send("","队列spring-监听器-小米",message);


        //给Header交换机上发送消息
        String sendSMSHeader = "一部红米手机";

        MessageProperties propertiesHeader = new MessageProperties();
        propertiesHeader.setContentEncoding("UTF-8");


        Message messageHeaders = new Message(sendSMSHeader.getBytes(),propertiesHeader);

        rabbitTemplate.send("","队列spring-监听器-红米",messageHeaders);
    }
16、添加json支持-转换普通对象为JSON字符串并发送到MQ

在pom.xml中需要添加jackson的引用,才能够实现把自定义的对象转换为json字符串

<!--json支持的依赖-->
<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
</dependency>

实体类代码:

package com.study.rabbitmq.p10TestSpringListenerAdaper;

/**
 * @author 武帅
 * @date 2020/6/7 16:56
 * @description
 */
public class MyOrder {

    private Integer id;
    private String name;
    private float price;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "MyOrder{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

配置类代码(暂时先注释一下)

   //使用监听适配器,针对不同队列的消息使用不同的方法,进行处理
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO 表示对消息进行自动确认
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //使用MessageListenerAdapter类进行消息接收并处理
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter();

        //设置消息的转换器
        messageListenerAdapter.setMessageConverter(new MyMessageTestConverter());

        //new MyMessageDelegate() 这里使用自己的方法
        messageListenerAdapter.setDelegate(new MyMessageDelegate());

        //使用自己的类型转换器
        messageListenerAdapter.setDefaultListenerMethod("myHandleMessage");

        //进行绑定
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);

       return simpleMessageListenerContainer;
    }

测试类代码:

    @Test
    void testSendOrderToXiaoMi() throws JsonProcessingException {


        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        //变成json字符串
        properties.setContentType("application/json");

        MyOrder myOrder = new MyOrder();
        myOrder.setId(1);
        myOrder.setName("一部最新的小米手机");
        myOrder.setPrice(1999);

        //把普通对象变成JSON格式的字符串
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(myOrder);

        System.out.println( "====================" + jsonStr);

        Message message = new Message(jsonStr.getBytes(), properties);
        rabbitTemplate.send("","队列spring-监听器-小米",message);

    }
17、Jackson2JsonMessageConverter接收并处理Map类型的消息

配置类代码:

  //使用监听适配器,针对不同队列的消息使用不同的方法,进行处理
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO 表示对消息进行自动确认
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //使用MessageListenerAdapter类进行消息接收并处理
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter();


        //Jackson2JsonMessageConverter接收并处理Map类型的消息
        Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();

        //设置消息的转换器
        messageListenerAdapter.setMessageConverter(jsonMessageConverter);

        //new MyMessageDelegate() 这里使用自己的方法
        messageListenerAdapter.setDelegate(new MyMessageDelegate());

        //使用自己的类型转换器 默认使用反射,寻找方法名
        messageListenerAdapter.setDefaultListenerMethod("myHandleMap");

        //进行绑定
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);

        return simpleMessageListenerContainer;
    }

处理方法的参数为转换过的Map类型

// 处理方法的参数为转换过的Map类型
    public void myHandleMap(Map map){
        System.out.println( "处理方法的参数为转换过的Map类型" + map);
    }

测试类代码:

   @Test
    void testSendOrderToXiaoMi() throws JsonProcessingException {


        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        //变成json字符串
        properties.setContentType("application/json");

        MyOrder myOrder = new MyOrder();
        myOrder.setId(1);
        myOrder.setName("一部最新的小米手机");
        myOrder.setPrice(1999);

        //把普通对象变成JSON格式的字符串
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(myOrder);

        //System.out.println( "====================" + jsonStr);

        Message message = new Message(jsonStr.getBytes(), properties);
        rabbitTemplate.send("","队列spring-监听器-小米",message);

    }
18、使用JavaTypeMapper直接接收并处理Java对象

配置类代码:

//使用监听适配器,直接处理传过来的Java对象
       @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO 表示对消息进行自动确认
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //使用MessageListenerAdapter类进行消息接收并处理
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter();


        //Jackson2JsonMessageConverter接收并处理Map类型的消息
        Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();

        DefaultJackson2JavaTypeMapper defaultJackson2JavaTypeMapper = new DefaultJackson2JavaTypeMapper();

        //信任所有的包 进行反射
        defaultJackson2JavaTypeMapper.setTrustedPackages("*");

        //进行映射
        jsonMessageConverter.setJavaTypeMapper(defaultJackson2JavaTypeMapper);


        //设置消息的转换器
        messageListenerAdapter.setMessageConverter(jsonMessageConverter);

        //new MyMessageDelegate() 这里使用自己的方法
        messageListenerAdapter.setDelegate(new MyMessageDelegate());

        //使用自己的类型转换器 默认使用反射,寻找方法名
        messageListenerAdapter.setDefaultListenerMethod("myHandleJavaObject");

        //进行绑定
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);

        return simpleMessageListenerContainer;
    }

​ 处理方法的参数为转换过的Java类型代码:

public void myHandleJavaObject(MyOrder myOrder){
    System.out.println( "处理方法的参数为转换过的Java类型" + myOrder);
}

测试类代码:

 @Test
    void testSendJavaClassObjectToXiaoMi() throws JsonProcessingException {


        MessageProperties properties = new MessageProperties();
        properties.setContentEncoding("UTF-8");
        //变成json字符串
        properties.setContentType("application/json");
        //把Java的类对象转换为Json在转换为字节数组
        properties.getHeaders().put("__TypeId__", "com.study.rabbitmq.p10TestSpringListenerAdaper.MyOrder");


        MyOrder myOrder = new MyOrder();
        myOrder.setId(1);
        myOrder.setName("一部最新的小米手机-Java对象");
        myOrder.setPrice(1999);

        //把普通对象变成JSON格式的字符串
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(myOrder);

        //System.out.println( "====================" + jsonStr);

        Message message = new Message(jsonStr.getBytes(), properties);
        rabbitTemplate.send("","队列spring-监听器-小米",message);

    }
19、全局转换器-处理多种类型的消息-1

根据内容类型自定义转换器,需要使用全局消息转换器

ContentTypeDelegatingMessageConverter

配置类代码:

//使用全局转换器,对不同类型的数据进行定向转换
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,Queue queueSMS){
        //把工厂传进来
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);

        //设置多个监听队列
        simpleMessageListenerContainer.setQueues(queueSMS,queueXiaoMi(),queueHongMi());

        //1个监听器,可以监听多少个队列 (一般设置为1,不能设置为0)
        simpleMessageListenerContainer.setConcurrentConsumers(1);

        //创建多少个监听器,来监听消息队列
        simpleMessageListenerContainer.setMaxConcurrentConsumers(5);

        //设置收到消息后的确认模式  AcknowledgeMode.AUTO 表示对消息进行自动确认
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);

        //设置标签,然后台更加的认识它们
        simpleMessageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy(){

            @Override
            public String createConsumerTag(String consumerTag) {

                //自己手写改动过后的
                consumerTag = consumerTag + "-" + num++;
                return consumerTag;

                //默认返回的就是,rabbitMq自动给咱们起好的名字
                //return consumerTag;
            }
        });

        //使用MessageListenerAdapter类进行消息接收并处理
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter();


        //Jackson2JsonMessageConverter接收并处理Map类型的消息
        Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();

        //创建全局转换器,对不同类型的数据进行定向转换
        ContentTypeDelegatingMessageConverter converter = new ContentTypeDelegatingMessageConverter();
        //根据不同的内容创建不同的转换器
        converter.addDelegate("my-jpg", new MyMessageJPGConverter());
        converter.addDelegate("my-pdf", new MyMessagePDFConverter());

        //设置消息的转换器
        messageListenerAdapter.setMessageConverter(converter);

        //new MyMessageDelegate() 这里使用自己的方法
        messageListenerAdapter.setDelegate(new MyMessageDelegate());

        //使用自己的类型转换器 默认使用反射,寻找方法名
        messageListenerAdapter.setDefaultListenerMethod("myHandleFile");

        //进行绑定
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);

        return simpleMessageListenerContainer;
    }

处理方法的参数为转换过的File类型的代码

	// 处理方法的参数为转换过的File类型
    public void myHandleFile(File file){
        System.out.println( "处理方法的参数为转换过的File类型" + file.getName());
    }

读取文件的二进制流发送到中间件的代码:

//读取文件的二进制流发送到中间件
    @Test
    void testSendFileByteToXiaoMi() throws Exception {

        //处理图片
        MessageProperties properties = new MessageProperties();
        //设置自己的类型
        properties.setContentType("my-jpg");
        properties.getHeaders().put("extName","jpg");

        //读取文件的二进制
        File file = new File("E:\\其他文件\\SiKi\\资料RabbitMQ\\dog.jpg");

        byte[] bytes = Files.readAllBytes(file.toPath());

        Message message = new Message(bytes, properties);
        rabbitTemplate.send("","队列spring-监听器-小米",message);


        //处理PDF文件
        MessageProperties propertiesPDF = new MessageProperties();
        //设置自己的类型
        propertiesPDF.setContentType("my-pdf");
        propertiesPDF.getHeaders().put("extName","pdf");

        //读取文件的二进制
        File filePDF = new File("E:\\其他文件\\SiKi\\资料RabbitMQ\\snake.pdf");

        byte[] bytesPDF = Files.readAllBytes(filePDF.toPath());

        Message messagePDF = new Message(bytesPDF, propertiesPDF);
        rabbitTemplate.send("","队列spring-监听器-小米",messagePDF);

    }

​ 根据不同的内容创建不同的转换器的代码

	package com.study.rabbitmq.p10TestSpringListenerAdaper;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.UUID;

/**
 * @author 武帅
 * @date 2020/6/7 16:18
 * @description 自定义图片转换器
 *      MessageConverter自定义接收数据类型
 *
 * 	    类型转换器(实现接口MessageConverter)
 */
public class MyMessagePDFConverter implements MessageConverter {


    // java对象转换为Message对象
    @Override
    public Message toMessage(Object o, MessageProperties messageProperties) throws MessageConversionException {
        Message message = new Message(o.toString().getBytes(),messageProperties);
        return message;
    }



    @Override
    public Object fromMessage(Message message) {

        //获取扩展名
        String extName = message.getMessageProperties().getHeaders().get("extName").toString();

        //做文件路径的拼接
        String path = "E:/" + UUID.randomUUID().toString() + "." + extName;

        //进行文件的读写
        File file = new File(path);

        try {
            Files.copy(new ByteArrayInputStream(message.getBody()),file.toPath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }
}

根据不同的内容创建不同的转换器的代码

package com.study.rabbitmq.p10TestSpringListenerAdaper;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.UUID;

/**
 * @author 武帅
 * @date 2020/6/7 16:18
 * @description 自定义PDF转换器
 *      MessageConverter自定义接收数据类型
 *
 * 	    类型转换器(实现接口MessageConverter)
 */
public class MyMessagePDFConverter implements MessageConverter {


    // java对象转换为Message对象
    @Override
    public Message toMessage(Object o, MessageProperties messageProperties) throws MessageConversionException {
        Message message = new Message(o.toString().getBytes(),messageProperties);
        return message;
    }



    @Override
    public Object fromMessage(Message message) {

        //获取扩展名
        String extName = message.getMessageProperties().getHeaders().get("extName").toString();

        //做文件路径的拼接
        String path = "E:/" + UUID.randomUUID().toString() + "." + extName;

        //进行文件的读写
        File file = new File(path);

        try {
            Files.copy(new ByteArrayInputStream(message.getBody()),file.toPath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }
}
20、使用SpringBoot的配置文件和注解进行收发消息 (这里类似于SpringBoot整合RabbitMq)

​ 配置Application.properties

​ 配置后,就可以直接使用RabbitTemplate的实力化bean了,连自己实例化bean都省了

第一步:

​ 创建两个工程(这个就不多说了,很简单啊)

第二步:

​ 使用配置文件连接消息中间件

#SpringBoot连接rabbitmq的信息

#SpringBoot连接rabbitmq的地址 如果是本机则写localhost 如果是别的机器,则写它的IP地址
spring.rabbitmq.addresses=localhost

#SpringBoot连接rabbitmq的用户名 默认是guest
spring.rabbitmq.username=guest

#SpringBoot连接rabbitmq的密码 默认是guest
spring.rabbitmq.password=guest

#SpringBoot连接rabbitmq的虚拟机 /表示根目录
spring.rabbitmq.virtual-host=/

#SpringBoot连接rabbitmq的超时时间 以毫秒为单位 这里先设为10秒(如果10秒内还没有连接到rabbitmq的话,那就退出连接)
spring.rabbitmq.connection-timeout=10000
21、注入模版对象发送消息-携带相关数据ID (以下所有的标题和代码内容都和上一个内容有关)

​ 这里的上一个内容为20标题

​ 创建配置类的代码:

package com.study.rabbitmq;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author 武帅
 * @date 2020/6/9 15:56
 * @description 生产者的配置类
 *      @Configuration  添加了此注解 则表示这个类为配置类(用于实例化需要的Bean)
 *      @ComponentScan({"com.study.rabbitmq.*"})  添加了此注解 则表示要扫描这个包下所有的组件类,并且实例化
 */
@Configuration
@ComponentScan({"com.study.rabbitmq.*"})
public class MyConfigProducer {


}

创建生产者类的代码:

package com.study.rabbitmq;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.UUID;

/**
 * @author 武帅
 * @date 2020/6/9 16:01
 * @description  @Component 添加此注解 则表示自动实例化,变成组件类
 */
@Component
public class MySendComponent {

    //Spring整合的RabbitMq  Spring对它进行了优化,而创造出来的类RabbitTemplate 是个模板
    @Autowired
    RabbitTemplate rabbitTemplate;

    /**
     * @Author: 武帅
     * @Date: 2020-06-09
     * @Description:
     * @param object 表示 需要发送的实际内容
     * @param map    表示 需要携带的特殊信息
     *@return: void
     */
    public void send(Object object, Map<String,Object> map){

        //这里导入的包是org.springframework.messaging.MessageHeaders
        MessageHeaders messageHeaders = new MessageHeaders(map);

        //这里导入的包是org.springframework.messaging.Message
        Message message = MessageBuilder.createMessage(object,messageHeaders);

        //创建唯一的UUID
        String uuId = UUID.randomUUID().toString();

        //需要传入一个字符串 保证全局唯一
        //作用为: 如果消息没有发送成功,可以把这个Id给你返回回来,让你快速的查询到是哪条消息出错了。
        CorrelationData correlationData = new CorrelationData(uuId);

        //发送消息
        //第一个参数为交换机的名字
        //第一个参数为交换机的路由键
        //第三个参数为要发送的数据
        //第四个参数为要携带相关数据的ID 用于:如果消息没有发送成功,可以把这个Id给你返回回来,让你快速的查询到是哪条消息出错了。
        rabbitTemplate.convertAndSend("交换机spring短信","发送短信",message,correlationData);

        //应该还有一步 就是发送完短信,因该把UUID插入到数据库中。
    }


}
22、确认模式

发送消息代码:

package com.study.rabbitmq;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.Map;


@SpringBootTest
class RabbitmqApplicationTests {

    @Autowired
    private MySendComponent mySendComponent;


    @Test
    void test() {
        System.out.println("hello");
    }

    @Test
    void sendStringToMQ(){

        //需要发送的数据
        String str = "hello world";

        //需要携带的特殊信息
        Map<String,Object> map = new HashMap<>();
        map.put("收货人姓名","Jack");
        map.put("收货人地址","北京");
        map.put("收货人电话","110");

        mySendComponent.send(str,map);
    }




}

往application.properties文件中添加了其它的配置文件代码:

#SpringBoot整合rabbitmq的确认模式 默认是none
spring.rabbitmq.publisher-confirm-type=correlated

#SpringBoot整合rabbitmq的返回模式 默认是false
spring.rabbitmq.publisher-returns=true

#默认是false 则表示不通知,直接扔掉, 如果是true的话,则表示投递出错,通知生产者
spring.rabbitmq.template.mandatory=true

往MySendComponent文件中添加了其它的代码:

package com.study.rabbitmq;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.UUID;

/**
 * @author 武帅
 * @date 2020/6/9 16:01
 * @description  @Component 添加此注解 则表示自动实例化,变成组件类
 */
@Component
public class MySendComponent {

    //Spring整合的RabbitMq  Spring对它进行了优化,而创造出来的类RabbitTemplate 是个模板
    @Autowired
    RabbitTemplate rabbitTemplate;

    //回调函数
    RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
        @Override
        public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            if (ack == false){
                System.out.println("出错了,发送了Mq出现了问题,此时因该更新数据库,失败的原因:" + cause
                + "错误的ID为:" + correlationData);
            }else{
                System.out.println("发送成功,原因为:" + cause + "Id为:" + correlationData);
            }
        }
    };

    /**
     * @Author: 武帅
     * @Date: 2020-06-09
     * @Description:
     * @param object 表示 需要发送的实际内容
     * @param map    表示 需要携带的特殊信息
     *@return: void
     */
    public void send(Object object, Map<String,Object> map){

        //这里导入的包是org.springframework.messaging.MessageHeaders
        MessageHeaders messageHeaders = new MessageHeaders(map);

        //这里导入的包是org.springframework.messaging.Message
        Message message = MessageBuilder.createMessage(object,messageHeaders);

        //创建唯一的UUID
        String uuId = UUID.randomUUID().toString();

        //需要传入一个字符串 保证全局唯一
        //作用为: 如果消息没有发送成功,可以把这个Id给你返回回来,让你快速的查询到是哪条消息出错了。
        CorrelationData correlationData = new CorrelationData(uuId);


        //回调函数 如果出错,则调用此函数
        rabbitTemplate.setConfirmCallback(confirmCallback);


        //发送消息
        //第一个参数为交换机的名字
        //第一个参数为交换机的路由键
        //第三个参数为要发送的数据 这里暂时没有数据,数据由外边的类来提供
        //第四个参数为要携带相关数据的ID 用于:如果消息没有发送成功,可以把这个Id给你返回回来,让你快速的查询到是哪条消息出错了。
        rabbitTemplate.convertAndSend("交换机spring短信","发送短信",message,correlationData);

        //应该还有一步 就是发送完短信,因该把UUID插入到数据库中。
    }


}

23、返回模式

​ 发送消息代码: 和上面确认模式的一样

​ application.properties文件: 和上面确认模式的一样

​ 往MySendComponent文件中添加了其它的代码:

package com.study.rabbitmq;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.UUID;

/**
 * @author 武帅
 * @date 2020/6/9 16:01
 * @description  @Component 添加此注解 则表示自动实例化,变成组件类
 */
@Component
public class MySendComponent {

    //Spring整合的RabbitMq  Spring对它进行了优化,而创造出来的类RabbitTemplate 是个模板
    @Autowired
    RabbitTemplate rabbitTemplate;

    //回调函数
    RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
        @Override
        public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            if (ack == true){
                System.out.println("出错了,发送了Mq出现了问题,此时因该更新数据库,失败的原因:" + cause
                        + "错误的ID为:" + correlationData);
            }else{
                System.out.println("发送成功,原因为:" + cause + "Id为:" + correlationData);
            }
        }
    };


    RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
        @Override
        public void returnedMessage(org.springframework.amqp.core.Message message, int replyCode, String replyText, String exchange, String routingKey) {
            System.out.println("replyCode :" + replyCode );
            System.out.println("replyText :" + replyText );
            System.out.println("exchange :" + exchange );
            System.out.println("routingKey :" + routingKey );
            System.out.println("message :" + message );
        }
    };


    /**
     * @Author: 武帅
     * @Date: 2020-06-09
     * @Description:
     * @param object 表示 需要发送的实际内容
     * @param map    表示 需要携带的特殊信息
     *@return: void
     */
    public void send(Object object, Map<String,Object> map){

        //这里导入的包是org.springframework.messaging.MessageHeaders
        MessageHeaders messageHeaders = new MessageHeaders(map);

        //这里导入的包是org.springframework.messaging.Message
        Message message = MessageBuilder.createMessage(object,messageHeaders);

        //创建唯一的UUID
        String uuId = UUID.randomUUID().toString();

        //需要传入一个字符串 保证全局唯一
        //作用为: 如果消息没有发送成功,可以把这个Id给你返回回来,让你快速的查询到是哪条消息出错了。
        CorrelationData correlationData = new CorrelationData(uuId);


        //回调函数 如果出错,则调用此函数
        rabbitTemplate.setConfirmCallback(confirmCallback);

        //返回模式
        rabbitTemplate.setReturnCallback(returnCallback);

        //发送消息
        //第一个参数为交换机的名字
        //第一个参数为交换机的路由键
        //第三个参数为要发送的数据 这里暂时没有数据,数据由外边的类来提供
        //第四个参数为要携带相关数据的ID 用于:如果消息没有发送成功,可以把这个Id给你返回回来,让你快速的查询到是哪条消息出错了。
        rabbitTemplate.convertAndSend("交换机spring短信","发送短信",message,correlationData);

        //应该还有一步 就是发送完短信,因该把UUID插入到数据库中。
    }


}

24、使用RabbitListener注解消费数据并手动确认

@RabbitListener是一个组合注解,可以组合其它注解一起来完成对队列的消息接收和监听,主要包括@QueueBinding、@Queue、@Exchange

此时是在rabbitmqConsumer工程里写代码

application.properties文件的代码

#SpringBoot连接rabbitmq的信息

#SpringBoot连接rabbitmq的地址 如果是本机则写localhost 如果是别的机器,则写它的IP地址
spring.rabbitmq.addresses=localhost

#SpringBoot连接rabbitmq的用户名 默认是guest
spring.rabbitmq.username=guest

#SpringBoot连接rabbitmq的密码 默认是guest
spring.rabbitmq.password=guest

#SpringBoot连接rabbitmq的虚拟机 /表示根目录
spring.rabbitmq.virtual-host=/

#SpringBoot连接rabbitmq的超时时间 以毫秒为单位 这里先设为10秒(如果10秒内还没有连接到rabbitmq的话,那就退出连接)
spring.rabbitmq.connection-timeout=10000

#rabbitmq的手动确认模式
spring.rabbitmq.listener.simple.acknowledge-mode=manual

#rabbitmq的监听对象的数量
spring.rabbitmq.listener.simple.concurrency=1

#SpringBoot为我们创建5个对象进行同时监听
spring.rabbitmq.listener.simple.max-concurrency=5



配置类的代码:

package com.study.rabbitmq;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author 武帅
 * @date 2020/6/11 11:03
 * @description @ComponentScan({"com.study.rabbitmq.*"}) 表示扫描包下所有的类
 */
@Configuration
@ComponentScan({"com.study.rabbitmq.*"})
public class MyConfigConsumer {



}

组件类的代码

package com.study.rabbitmq;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author 武帅
 * @date 2020/6/11 11:05
 * @description     @Component 表示这是一个组件类.会被自动的实例化,进行一个注入
 */
@Component
public class MyRecvComponent {

    //需要引入 import org.springframework.messaging.Message;
    //需要引入 import com.rabbitmq.client.Channel;
    @RabbitListener(
        //queues = {"队列spring短信"} 监听的队列
        queues = {"队列spring短信"}
    )
    @RabbitHandler
    public void onMessage(Message message, Channel channel){
        System.out.println("收到了: " + message.getPayload());

        //获取消息唯一Id
        Long deliveryTag = (Long) message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);

        //因为现在是手动确认模式,所以要设置basicAck
        //第一个参数 包裹的一个标签 是RabbitMq为我们自动添加的唯一Id
        //第二个参数 不自动批量
        try {
            channel.basicAck(deliveryTag,false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
25、使用RabbitListener复合注解 创建队列交换机和绑定

application.properties文件的代码 和上面的一样

配置类的代码: 和上面的一样

组件类的代码:

package com.study.rabbitmq;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author 武帅
 * @date 2020/6/11 11:05
 * @description     @Component 表示这是一个组件类.会被自动的实例化,进行一个注入
 */
@Component
public class MyRecvComponent {

    //需要引入 import org.springframework.messaging.Message;
    //需要引入 import com.rabbitmq.client.Channel;
    @RabbitListener(
        //queues = {"队列spring短信"} 监听的队列
        queues = {"队列spring短信"}
    )
    @RabbitHandler
    public void onMessage(Message message, Channel channel){
        System.out.println("收到了: " + message.getPayload());

        //获取消息唯一Id
        Long deliveryTag = (Long) message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);

        //因为现在是手动确认模式,所以要设置basicAck
        //第一个参数 包裹的一个标签 是RabbitMq为我们自动添加的唯一Id
        //第二个参数 不自动批量
        try {
            channel.basicAck(deliveryTag,false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    // =========================================================================================

    //需要引入 import org.springframework.messaging.Message;
    //需要引入 import com.rabbitmq.client.Channel;
    //使用复合注解创建队列
    @RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "队列-注解创建的",declare = "true",exclusive = "false",autoDelete = "false"),
                exchange = @Exchange(value = "交换机-注解创建的",durable = "true", type = "direct"),
                key = "新路由键"
        )
    )
    @RabbitHandler
    public void onMessageNewQueue(Message message, Channel channel){
        System.out.println("NewQue收到了: " + message.getPayload());

        //获取消息唯一Id
        Long deliveryTag = (Long) message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);

        //因为现在是手动确认模式,所以要设置basicAck
        //第一个参数 包裹的一个标签 是RabbitMq为我们自动添加的唯一Id
        //第二个参数 不自动批量
        try {
            channel.basicAck(deliveryTag,false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

26、使用注解直接发送和接收java自定义对象

​ 要求:实体类必须实现接口 Serializable

​ 实体类最好定义 序列号ID

1、首先在生产端定义一个实体类

package com.study.rabbitmq;

import java.io.Serializable;

/**
 * @author 武帅
 * @date 2020/6/12 15:35
 * @description
 */
public class MyUser implements Serializable {

    //随便给一个UID即可
    private static final long serialVersionUID = 870292457463066666L;

    private String userName;
    private Integer age;
    private long exd;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public long getExd() {
        return exd;
    }

    public void setExd(long exd) {
        this.exd = exd;
    }

    public MyUser() { }

    public MyUser(String userName, Integer age, long exd) {
        this.userName = userName;
        this.age = age;
        this.exd = exd;
    }

}

2、然后再组件类里添加其余的代码:

public void sendMyUser(MyUser user){
        //回调函数 如果出错,则调用此函数
        rabbitTemplate.setConfirmCallback(confirmCallback);

        //返回模式
        rabbitTemplate.setReturnCallback(returnCallback);

        //创建唯一的UUID
        String uuId = UUID.randomUUID().toString();

        //需要传入一个字符串 保证全局唯一
        //作用为: 如果消息没有发送成功,可以把这个Id给你返回回来,让你快速的查询到是哪条消息出错了。
        CorrelationData correlationData = new CorrelationData(uuId);

        rabbitTemplate.convertAndSend("交换机-注解创建的","新路由键",user,correlationData);

    }

3、测试类里添加其余的代码:

 @Test
    void SendUserToMQ(){
        MyUser user = new MyUser("张三",18,2000L);
        mySendComponent.sendMyUser(user);
    }

4、在切换为消费端

5、在消费端直接粘贴生产端的实体类

6、在组件类里添加其余的代码:

//需要引入 import org.springframework.messaging.Message;
    //需要引入 import com.rabbitmq.client.Channel;
    @RabbitListener(
            //queues = {"队列spring短信"} 监听的队列
            queues = {"队列-注解创建的"}
    )
    @RabbitHandler
    public void onMessageUser(@Payload MyUser user, Channel channel, @Headers Map<String,Object> headers){
        System.out.println("收到了: " + user.getUserName());
        System.out.println("收到了: " + user.getAge());
        System.out.println("收到了: " + user.getExd());

        //获取消息唯一Id
        Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);

        //因为现在是手动确认模式,所以要设置basicAck
        //第一个参数 包裹的一个标签 是RabbitMq为我们自动添加的唯一Id
        //第二个参数 不自动批量
        try {
            channel.basicAck(deliveryTag,false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

好了到此RabbitMQ的基础部分就结束了

posted @ 2020-06-12 17:31  9geg  阅读(442)  评论(0)    收藏  举报