rabbitMQ实现队列超时,死信队列,消息重发,持久化。个人学习了解使用

在linux中使用Docker创建RabbitMQ的容器。

Docker安装过程

下载Docker-CE rpm安装包

Index of linux/centos/7/x86_64/stable/Packages/

注意下载版本要和操作系统版本对应。

docker-ce-18.06.0.ce-3.el7.x86_64.rpm

安装Docker

上传 docker-ce-18.06.0.ce-3.el7.x86_64.rpm 到opt

执行命令: yum install -y docker-ce-18.06.0.ce-3.el7.x86_64.rpm

注意:确保linux服务器处于联网状态。

常见问题:

当用yum安装时报错。。。
Error: Package: glibc-headers-2.17-196.el7_4.2.x86_64 (ultra-centos-7.4-updates)
           Requires: glibc = 2.17-196.el7_4.2
           Installed: glibc-2.17-222.el7.x86_64 (installed)
               glibc = 2.17-222.el7
           Available: glibc-2.17-196.el7.x86_64 (ultra-centos-7.4-base)
               glibc = 2.17-196.el7
           Available: glibc-2.17-196.el7_4.2.x86_64 (ultra-centos-7.4-updates)
               glibc = 2.17-196.el7_4.2
Error: Package: gcc-4.8.5-16.el7_4.2.x86_64 (ultra-centos-7.4-updates)
           Requires: libgomp = 4.8.5-16.el7_4.2
           Installed: libgomp-4.8.5-28.el7_5.1.x86_64 (installed)
               libgomp = 4.8.2-16.el7_5
               libgomp = 4.8.5-28.el7_5.1
           Available: libgomp-4.8.5-16.el7.x86_64 (ultra-centos-7.4-base)
               libgomp = 4.8.5-16.el7
               libgomp = 4.8.2-16.el7
           Available: libgomp-4.8.5-16.el7_4.1.x86_64 (ultra-centos-7.4-updates)
               libgomp = 4.8.5-16.el7_4.1
               libgomp = 4.8.2-16.el7_4
           Available: libgomp-4.8.5-16.el7_4.2.x86_64 (ultra-centos-7.4-updates)
               libgomp = 4.8.5-16.el7_4.2
               libgomp = 4.8.2-16.el7_4
Error: Package: glibc-devel-2.17-196.el7_4.2.x86_64 (ultra-centos-7.4-updates)
           Requires: glibc = 2.17-196.el7_4.2
           Installed: glibc-2.17-222.el7.x86_64 (installed)
               glibc = 2.17-222.el7
           Available: glibc-2.17-196.el7.x86_64 (ultra-centos-7.4-base)
               glibc = 2.17-196.el7
           Available: glibc-2.17-196.el7_4.2.x86_64 (ultra-centos-7.4-updates)
               glibc = 2.17-196.el7_4.2
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest
 

解决办法:

wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

sed -i  's/$releasever/7/g' /etc/yum.repos.d/CentOS-Base.repo
、yum repolist 

启动与停止Docker

启动docker:systemctl start docker

停止docker:systemctl stop docker

重启docker:systemctl restart docker

查看docker状态:systemctl status docker

//设置docker服务开机自启动 systemctl enable docker

验证Docker是否安装成功

执行命令:docker info

查看返回信息,能否查看到Docker相关信息

到此,Docker安装完毕!

RabbitMQ安装

1 docker镜像下载

docker pull rabbitmq:management

注意:如果docker pull rabbitmq 后面不带management,启动rabbitmq后是无法打开管理界面的,所以我们要下载带management插件的rabbitmq.

2.查看docker镜像

docker images

 

3.创建rabbitmq容器

docker run -di -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management

4.访问管理界面

访问管理界面的地址就是 http://主机或虚拟机ip:15672,可以使用默认的账户登录,用户名和密码都guest

 

项目构建

本人使用springBoot项目父依赖2.6.2版本,下面为mq和mysql的版本依赖:


   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
            <version>2.6.2</version>
    </dependency>
    <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
     </dependency>
        <!-- 连接池 -->
     <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.14</version>
     </dependency>
     <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
      </dependency>
      <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

配置application.yml

server:
  port: 9090
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/uedu?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
  rabbitmq:
    host: 192.168.157.128 #mq所在主机或虚拟机ip
    port: 5672
    username: guest
    password: guest
    listener:
      simple:
        prefetch: 1 #每次只处理一个信息
        concurrency: 10 #初始化并发数量
        max-concurrency: 20 #设置最大并发数
        default-requeue-rejected: false
        acknowledge-mode: manual # ack确认开启
        retry:
          enabled: true #开启消费者进行重试
          max-attempts: 5 #最大重试次数
          initial-interval: 3000 #重试时间间隔
      type: simple
    publisher-confirm-type: correlated  #确认消息已发送到交换机(Exchange)  # 消息确认(ACK)
    publisher-returns: true #确认消息已发送到队列(Queue)
    template:
      mandatory: true #场景1消息找不到对应的Exchange。场景2找到了Exchange但是找不到对应的Queue。  操作:自动删除(false)或 返回到客户端(true)。

 创建一个MQ的配置类,创建MQ的业务交换机,业务队列,死信交换机,死信队列,交换机队列绑定,配置过期时间,死信交换机,持久化。代码中有解释。

package org.example.config;
 
import lombok.extern.slf4j.Slf4j;
import org.example.common.Constants;
import org.example.service.RabbitMqMessageService;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;
 
/**
 * Feng, Ge 2020/8/15 20:21
 */
@Configuration
@Slf4j
public class RabbitMQConfig {
    @Autowired
    private RetryCache retryCache;

    public static final String BUSINESS_EXCHANGE_NAME = "dead.letter.demo.simple.business.exchange";
    public static final String BUSINESS_QUEUEA_NAME = "dead.letter.demo.simple.business.queuea";
    public static final String BUSINESS_QUEUEB_NAME = "dead.letter.demo.simple.business.queueb";
    public static final String DEAD_LETTER_EXCHANGE = "dead.letter.demo.simple.deadletter.exchange";
    public static final String DEAD_LETTER_QUEUEA_ROUTING_KEY = "dead.letter.demo.simple.deadletter.queuea.routingkey";
    public static final String DEAD_LETTER_QUEUEB_ROUTING_KEY = "dead.letter.demo.simple.deadletter.queueb.routingkey";
    public static final String DEAD_LETTER_QUEUEA_NAME = "dead.letter.demo.simple.deadletter.queuea";
    public static final String DEAD_LETTER_QUEUEB_NAME = "dead.letter.demo.simple.deadletter.queueb";

    // 声明业务Exchange  广播模式FanoutExchange
    @Bean("businessExchange")
    public FanoutExchange businessExchange(){
//      第一个参数 交换机的名字,
//        第二个参数 是否持久化。durable
//        第三个参数 是否自动删除 autoDelete
        return new FanoutExchange(BUSINESS_EXCHANGE_NAME,true,false);
    }

    // 声明死信Exchange  定向模式DirectExchange
    @Bean("deadLetterExchange")
    public DirectExchange deadLetterExchange(){
        return new DirectExchange(DEAD_LETTER_EXCHANGE,true,false);
    }

    // 声明业务队列A
    @Bean("businessQueueA")
    public Queue businessQueueA(){
        Map<String, Object> args = new HashMap<>(3);
//       x-dead-letter-exchange    这里声明当前队列绑定的死信交换机
        args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);
//       x-dead-letter-routing-key  这里声明当前队列的死信路由key
        args.put("x-dead-letter-routing-key", DEAD_LETTER_QUEUEA_ROUTING_KEY);
//        x-message-ttl    这里生命当前队列的消息超时时间,6s
        args.put("x-message-ttl",6000);
//        .durable持久化
        return QueueBuilder.durable(BUSINESS_QUEUEA_NAME).withArguments(args).build();
    }

    // 声明业务队列B
    @Bean("businessQueueB")
    public Queue businessQueueB(){
        Map<String, Object> args = new HashMap<>(3);
//       x-dead-letter-exchange    这里声明当前队列绑定的死信交换机
        args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);
//       x-dead-letter-routing-key  这里声明当前队列的死信路由key
        args.put("x-dead-letter-routing-key", DEAD_LETTER_QUEUEB_ROUTING_KEY);
        args.put("x-message-ttl",6000);
        return QueueBuilder.durable(BUSINESS_QUEUEB_NAME).withArguments(args).build();
    }

    // 声明死信队列A
    @Bean("deadLetterQueueA")
    public Queue deadLetterQueueA(){
        Map<String, Object> args = new HashMap<>();
//      设置死信队列长度 100M
        args.put("x-max-length-bytes", 100*1024*1024);
        args.put("x-message-ttl",6000);
        return QueueBuilder.durable(DEAD_LETTER_QUEUEA_NAME).withArguments(args).build();
//        另一种队列创建方法
//        return new Queue(DEAD_LETTER_QUEUEA_NAME,true,false,false);
    }

    // 声明死信队列B
    @Bean("deadLetterQueueB")
    public Queue deadLetterQueueB(){
        return new Queue(DEAD_LETTER_QUEUEB_NAME,true,false,false);
    }

    // 声明业务队列A绑定关系
    @Bean
    public Binding businessBindingA(@Qualifier("businessQueueA") Queue queue,
                                    @Qualifier("businessExchange") FanoutExchange exchange){
        return BindingBuilder.bind(queue).to(exchange);
    }

    // 声明业务队列B绑定关系
    @Bean
    public Binding businessBindingB(@Qualifier("businessQueueB") Queue queue,
                                    @Qualifier("businessExchange") FanoutExchange exchange){
        return BindingBuilder.bind(queue).to(exchange);
    }

    // 声明死信队列A绑定关系
    @Bean
    public Binding deadLetterBindingA(@Qualifier("deadLetterQueueA") Queue queue,
                                      @Qualifier("deadLetterExchange") DirectExchange exchange){
//        因为死信队列是定向模式  .with() 指定routing key
        return BindingBuilder.bind(queue).to(exchange).with(DEAD_LETTER_QUEUEA_ROUTING_KEY);
    }

    // 声明死信队列B绑定关系
    @Bean
    public Binding deadLetterBindingB(@Qualifier("deadLetterQueueB") Queue queue,
                                      @Qualifier("deadLetterExchange") DirectExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(DEAD_LETTER_QUEUEB_ROUTING_KEY);
    }

//    rabbitMq的回调函数,返回消息到达交换机,到达队列的回调
    @Bean
    public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory)
    {
        RabbitTemplate rabbitTemplate = new RabbitTemplate();
        rabbitTemplate.setConnectionFactory(connectionFactory);
        //设置开启Mandatory,才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数
        rabbitTemplate.setMandatory(true);

        //确认消息送到交换机(Exchange)回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback()
        {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause)
            {
                System.out.println("\n确认消息送到交换机(Exchange)结果:");
                System.out.println("相关数据:" + correlationData);
                System.out.println("是否成功:" + ack);
                System.out.println("错误原因:" + cause);

                // 使用ack确认机制,到达ack为true, 
                if (!ack){
                    // 发送失败,会调用消息重发,这里显示信息。
                    log.info("send message failed: " + cause + correlationData.toString());
                }else {
                    //成功调用自己写的retryCache类,删除保存的消息id。
                    System.out.println("删除correlationData.getId()"+correlationData.getId());
                    retryCache.del(Long.valueOf(correlationData.getId()));
                }

            }
        });
        //确认消息送到队列(Queue)回调
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback()
        {

            @Override
            public void returnedMessage(ReturnedMessage returnedMessage)
            {
                System.out.println("\n确认消息送到队列(Queue)结果:");
                System.out.println("发生消息:" + returnedMessage.getMessage());
                System.out.println("回应码:" + returnedMessage.getReplyCode());
                System.out.println("回应信息:" + returnedMessage.getReplyText());
                System.out.println("交换机:" + returnedMessage.getExchange());
                System.out.println("路由键:" + returnedMessage.getRoutingKey());


                try {
                    Thread.sleep(Constants.ONE_SECOND);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                log.info("send message failed: " + returnedMessage.getReplyCode() + " " + returnedMessage.getReplyText());
                rabbitTemplate.send(returnedMessage.getMessage());
            }


        });
        return rabbitTemplate;
    }
}

MQ的重发类与静态常量类

public class Constants {
    //线程数
    public final static int THREAD_COUNT = 5;

    //处理间隔时间
    //mils
    public final static int INTERVAL_MILS = 0;

    //consumer失败后等待时间(mils)
    public static final int ONE_SECOND = 1 * 1000;

    //异常sleep时间(mils)
    public static final int ONE_MINUTE = 1 * 6 * 1000;
    //MQ消息retry时间
    public static final int RETRY_TIME_INTERVAL = ONE_MINUTE;
    //MQ消息有效时间
    public static final int VALID_TIME = ONE_MINUTE;
}
package org.example.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Created by littlersmall on 2018/5/16.
 */
@NoArgsConstructor
@AllArgsConstructor
@Data
public class MessageWithTime {
    private long id;
    private long time;
    private Object message;
}

 

package org.example.config;


import lombok.extern.slf4j.Slf4j;
import org.example.common.Constants;
import org.example.common.DetailRes;
import org.example.common.MessageWithTime;
import org.example.pojo.RabbitMqFailMessage;
import org.example.pojo.RabbitMqMessage;
import org.example.quartz.MqFailScheduler;
import org.example.service.BusinessMessageSender;
import org.example.service.RabbitMqFailService;
import org.example.service.RabbitMqMessageService;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicLong;


@Slf4j
@Component
public class RetryCache {
    @Autowired
    // 把MQ发送的消息保存在数据库的服务类   需要自己简单写下,
    private RabbitMqMessageService messageService;
    @Autowired
    // 把MQ发送失败的消息保存在数据库的服务类  需要自己简单写下,
    private RabbitMqFailService rabbitMqFailService;

//    这是Mq消息发送服务类
    private BusinessMessageSender sender;
    private boolean stop = false;
    private Map<Long, MessageWithTime> map = new ConcurrentSkipListMap<>();
    private AtomicLong id = new AtomicLong();
    public static boolean state = false;

    // 接口消息发送时接受BusinessMessageSender服务,启动startRetry()方法。
    public void setSender(BusinessMessageSender sender) {
        this.sender = sender;
        System.out.println("startRetry();开启");
        startRetry();
    }

    public long generateId() {
        return id.incrementAndGet();
    }
//  发送MQ时把MQ的id与信息保存在map中。
    public void add(MessageWithTime messageWithTime) {
        map.putIfAbsent(messageWithTime.getId(), messageWithTime);
        System.out.println("map:++++"+map);
    }

    // 发送成功删除map中那个id的MQ消息
    public void del(long id) {
        map.remove(id);
    }

    private void startRetry() {
        new Thread(() ->{
            while (!stop) {
                try {
                    Thread.sleep(Constants.RETRY_TIME_INTERVAL);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("map:++++"+map);

                long now = System.currentTimeMillis();

                for (Map.Entry<Long, MessageWithTime> entry : map.entrySet()) {
                    System.out.println("entry:++++"+entry);
                    MessageWithTime messageWithTime = entry.getValue();

                    if (null != messageWithTime) {
                        System.out.println("messageWithTime:++++"+messageWithTime);
                        // 初次发送时间加3次重新发送间隔时间,如果大于当前时间,不发送,删除。  只发送三次
                        if (messageWithTime.getTime() + 6 * Constants.VALID_TIME < now) {
                            log.info("send message {} failed after 3 min ", messageWithTime);
                            //删除数据库数据  这是我的服务类,这段代码,你可以不要,或自己简单写下只是简单的数据库增删改
                            RabbitMqMessage rabbitMqMessage = new RabbitMqMessage();
                            rabbitMqMessage.setId(messageWithTime.getId());
                            rabbitMqMessage.setMessage(messageWithTime.getMessage().toString());
                            rabbitMqMessage.setIsConsume(0);
                            rabbitMqMessage.setIsDelete(1); // 设置可用为1  不可用表示删除
                            Long aLong = messageService.saveMessage(rabbitMqMessage);

                            // 3次重发后将还没有发出去的保存到发送失败数据库表,用quartz定时再发送一次     这是我的服务类,这段代码,你可以不要,或自己简单写下
                            RabbitMqFailMessage rabbitMqFailMessage = new RabbitMqFailMessage();
                            rabbitMqFailMessage.setId(messageWithTime.getId());
                            rabbitMqFailMessage.setMessage(messageWithTime.getMessage().toString());
                            rabbitMqFailMessage.setIsSend(0);  // 设置可用为0  表示可定时发送
                            rabbitMqFailMessage.setCreateTime(new Date());
                            rabbitMqFailMessage.setIsSuccess(0);
                            Long aLong1 = rabbitMqFailService.saveFailMessage(rabbitMqFailMessage);
                            if (aLong != null && aLong1 != null){
                                del(entry.getKey());
                            }

                            // 初次发送时间+重新发送间隔时间,如果大于当前时间。重新发送
                        } else if (messageWithTime.getTime() + Constants.VALID_TIME < now) {
                            Boolean aBoolean = sender.retryMsg(messageWithTime);
                        }
                        }
                    }
                }
        }).start();
    }
}

 mq所涉及到的两个数据库表:

消息发送表

 消息发送失败表

 好,现在咱们的消息队列的重发也创建完成了。接下来实现下简单的监听。

创建监听类

package org.example.listener;

import lombok.extern.slf4j.Slf4j;
import org.example.pojo.RabbitMqMessage;
import org.example.service.RabbitMqMessageService;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.amqp.core.Message;
import com.rabbitmq.client.Channel;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;

@Component
@Slf4j
public class BusinessMessageReceiver {
    @Autowired
    // Mq发送的消息保存到数据库服务类
    private RabbitMqMessageService messageService;


    public static final String BUSINESS_QUEUEA_NAME = "dead.letter.demo.simple.business.queuea";
    public static final String BUSINESS_QUEUEB_NAME = "dead.letter.demo.simple.business.queueb";

//  监听的队列名
    @RabbitListener(queues = BUSINESS_QUEUEA_NAME)
    public void receiveA(Message message, Channel channel) throws IOException {
        String msg = new String(message.getBody());
        log.info("收到业务消息A:{}", msg);
        boolean ack = true;
        Exception exception = null;
        try {
            // 模拟死信队列,发送deadletter信息,模拟消息出错。
            if (msg.contains("deadletter")){
                throw new RuntimeException("dead letter exception");
            }
            if (msg != null && msg.length()>0){
//             msg = msg + "@"+消息id; 简单定义发送消息时。消息id与消息用@分割
                String[] split = msg.split("@");
                String id = split[1];
                // 查询数据库看这个消息是否存在可用
                RabbitMqMessage byId = messageService.findById(Long.parseLong(id));
                System.out.println("消息A:{}"+byId);
                if (byId != null && byId.getIsConsume() == 0 && byId.getIsDelete() == 0){
                    byId.setIsConsume(1);
                    messageService.saveMessage(byId);
                    log.info("处理完成业务消息A:{}", msg);
                }else {
                    log.error("消息已消费,或数据库查不到。");
                    // basic.nack方法为不确认deliveryTag对应的消息,第二个参数是否应用于多消息,第三个参数是否requeue,true则重新入队列,否则丢弃或者进入死信队列。
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
                }
            }

        } catch (Exception e){
            ack = false;
            exception = e;
        }
        if (!ack){
            log.error("消息消费发生异常,error msg:{}", exception.getMessage(), exception);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
        } else {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    @RabbitListener(queues = BUSINESS_QUEUEB_NAME)
    public void receiveB(Message message, Channel channel) throws IOException {
        String msg = new String(message.getBody());
        log.info("收到业务消息B:{}", msg);
        if (msg != null && msg.length()>0){

            String[] split = msg.split("@");
            String id = split[1];
            RabbitMqMessage byId = messageService.findById(Long.parseLong(id));
            System.out.println("消息B :{}"+byId);
            if (byId != null && byId.getIsConsume() == 0 && byId.getIsDelete() == 0){
                byId.setIsConsume(1);
                messageService.saveMessage(byId);
                log.info("处理完成业务消息B:{}", msg);
            }else {
                log.error("消息已消费,或数据库查不到。");
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
            }
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}

 发送消息服务类:

package org.example.service;

import lombok.extern.slf4j.Slf4j;
import org.example.common.DetailRes;
import org.example.common.MessageWithTime;
import org.example.config.RetryCache;
import org.example.pojo.RabbitMqMessage;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Component
@Slf4j
public class BusinessMessageSender {
 
    public static final String BUSINESS_EXCHANGE_NAME = "dead.letter.demo.simple.business.exchange";
 
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RabbitMqMessageService messageService;
    @Autowired
    private RetryCache retryCache;
 
    public DetailRes sendMsg(String msg){
        try {
            log.info("message conent:"+msg);
            //保存数据库
            RabbitMqMessage messageEntity = new RabbitMqMessage(msg.toString(),0);
            messageEntity.setIsDelete(0);
            // 将消息保存到数据库,并把数据库中这条消息的id设置成MQ发送这条消息的id
            Long aLong = messageService.saveMessage(messageEntity);
            msg = msg + "@"+aLong;
            long time = System.currentTimeMillis();
            MessageWithTime messageWithTime = new MessageWithTime(aLong, time, msg);
            retryCache.add(messageWithTime);
            //发送消息  第一个参数交换机名,第二个routingKey,第三个 消息 第四个 消息id
             rabbitTemplate.convertSendAndReceive(BUSINESS_EXCHANGE_NAME, "", msg,
                    new CorrelationData(String.valueOf(messageWithTime.getId())));
        } catch (AmqpException e) {
            return new DetailRes(false,"");
        }
        return new DetailRes(true,"");
    }

}

 Controller层

package org.example.controller;

import org.example.common.DetailRes;
import org.example.config.RetryCache;
import org.example.service.BusinessMessageSender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RequestMapping("rabbitmqTest")
@RestController
@CrossOrigin
public class RabbitMQMsgController {
    @Autowired
    private BusinessMessageSender sender;
    @Autowired
    RetryCache retryCache;
 
    @GetMapping("sendMsg")
    public Boolean sendMsg(@RequestParam(value = "msg") String msg){
        DetailRes detailRes = sender.sendMsg(msg);
        System.out.println("detailRes::::"+detailRes);
        if (RetryCache.state == false){
            RetryCache.state = true;
            retryCache.setSender(sender);
        }
        return detailRes.isSuccess();

    }
}

接下来就可以启动springBoot项目的启动项了。

正常启动后,打开网页:http://localhost:9090/rabbitmqTest/sendMsg/?msg=fsd回车

开发控制台会收到如下:发送MQ

 接受MQ

 

http://MQip地址:15672/#/exchanges 

打开MQ的网页,点击Exchanges。 Features标签下的D就是持久化标志。其他信息也可见

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值