(三)RabbitMQ整合SpringBoot

初步了解了RabbitMQ的流程、工作模式后,进行RabbitMQ与SpringBoot整合

一、相关依赖

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

二、生产者

1、生产者 application.properties

spring:
	rabbitmq:
	    host: 192.168.93.138
	    port: 5672
	    username: guest
	    password: guest
	    publisher-confirms: true #交换机确认消息机制
	    publisher-returns: true #队列确认消息机制
	    virtualHost: / #指定连接MQ的虚拟机名,MQ的虚拟机名以"/"开头

2、声明交换机(生产者仅需创建交换机,队列由消费者创建)

@Configuration
public class RabbitMQConfig {
    //交换机的名称
    public static final String EX_ROUTING_CMS_POSTPAGE="ex_routing_cms_postpage";

    /**
     * 声明交换机,交换机配置使用direct类型
     * @return the exchange
     */
    @Bean(EX_ROUTING_CMS_POSTPAGE)
    public Exchange EXCHANGE_TOPICS_INFORM() {
        return ExchangeBuilder.directExchange(EX_ROUTING_CMS_POSTPAGE).durable(true).build();
    }
}

3、消息发送确认配置

1)、application.properties添加配置

spring:
	rabbitmq:
		publisher-confirms: true #交换机确认消息机制
	    publisher-returns: true #队列确认消息机制

2)、确认生产者发送的消息是否到达交换机,成功时打印语句

@Component
public class RabbitMQ_ExConfirm_Config implements RabbitTemplate.ConfirmCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct //jdk的注解 在@Autowired之后执行,只会执行一次
    public void init(){
        rabbitTemplate.setConfirmCallback(this);
    }

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String msg) {
        System.out.println("------交换机确认机制confirm------");
        System.out.println("消息唯一标识:" + correlationData);
        System.out.println("确认结果:" + ack);
        System.out.println("失败原因:" + msg);
    }
}

3)、确认生产者发送的消息是否到达队列,失败时会打印语句

@Component
public class RabbitMQ_Queue_Config implements RabbitTemplate.ReturnCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct
    public void init(){
        rabbitTemplate.setReturnCallback(this);
    }

    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        System.out.println("------队列确认机制returnedMessage------");
        System.out.println("消息主体 message:" + message);
        System.out.println("返回代码 replyCode:" + replyCode);
        System.out.println("描述 replyCode:" + replyText);
        System.out.println("交换机 exchange:" + exchange);
        System.out.println("路由key routingKey:" + routingKey);
    }
}

4、使用rabbitTemplate发送消息

/**
  * 1、交换机名称:RabbitMQConfig.EX_ROUTING_CMS_POSTPAGE
   * 2、路由key: 站点ID
   * 3、消息对象:页面ID
   */
rabbitTemplate.convertAndSend(RabbitMQConfig.EX_ROUTING_CMS_POSTPAGE, getById(pageId).getSiteId(), jsonString);

三、消费者

1、消费者 application.properties

spring:
	rabbitmq:
	    host: 192.168.93.138
	    port: 5672
	    username: guest
	    password: guest
	    listener:
	      simple:
	        acknowledge-mode: MANUAL #手动返回ACK
	    virtualHost: /

2、队列、交换机的声明与绑定

@Configuration
public class RabbitMQConfig {
    //队列bean的名称
    public static final String QUEUE_CMS_POSTPAGE = "queue_cms_postpage";
    //交换机的名称
    public static final String EX_ROUTING_CMS_POSTPAGE="ex_routing_cms_postpage";
    //队列的名称
    @Value("${xuecheng.mq.queue}")
    public String queue_cms_postpage_name;
    //routingKey 即站点Id
    @Value("${xuecheng.mq.routingKey}")
    public String routingKey;

    /**
     *声明交换机,交换机配置使用direct类型
     * @return the exchange
     */
    @Bean(EX_ROUTING_CMS_POSTPAGE)
    public Exchange EXCHANGE_TOPICS_INFORM() {
        return ExchangeBuilder.directExchange(EX_ROUTING_CMS_POSTPAGE).durable(true).build();
    }

    //声明队列
    @Bean(QUEUE_CMS_POSTPAGE)
    public Queue QUEUE_CMS_POSTPAGE() {
        Queue queue = new Queue(queue_cms_postpage_name);
        return queue;
    }

    /**
     * 绑定队列到交换机
     *
     * @param queue the queue
     * @param exchange the exchange
     *
     * @return the binding
     */
    @Bean
    public Binding BINDING_QUEUE_INFORM_SMS(@Qualifier(QUEUE_CMS_POSTPAGE) Queue queue,
                                            @Qualifier(EX_ROUTING_CMS_POSTPAGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(routingKey).noargs();
    }
}

3、监听并接收队列消息

@Component
public class ConsumerPostPage {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerPostPage.class);
    @Autowired
    PageService pageService;

    //监听队列
    @RabbitListener(queues = {"${xuecheng.mq.queue}"})
    public void postPage(String msg, Message message, Channel channel) throws IOException, InterruptedException {
        //消息投递序号,每次消费或者重新投递requeue后,delivery_tag都会增加(每个channel通道都有)
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        /**解析消息,因为队列中的消息格式是json格式
         * 消息格式:
         * {
         * "pageId":""
         * }
         */
        try{
            System.out.println("接收到消息:" + message);
            Map map = JSON.parseObject(msg, Map.class);//将json字符串转换成Map格式
            //获取页面ID
            String pageId = map.get("pageId").toString();
            //校验页面ID是否合法
            CmsPage cmsPage = pageService.findCmsById(pageId);
            if(null==cmsPage){
                LOGGER.error("页面ID对应页面不存在");
                return;
            }
            //调用savePageToServerPath方法使程序下载html文件到服务器的指定物理路径
            pageService.savePageToServerPath(pageId);

            /**
             * 处理消息过程没有出现异常,手动发送消息接收成功
             * deliveryTag:该消息的index
             * multiple:是否批量. true:将一次性ack所有小于deliveryTag的消息。
             */
            Thread.sleep(1000);
            System.out.println("成功确认消息");
            channel.basicAck(deliveryTag, false);
        }
        catch (Exception e){
            /**
             * 处理消息过程出现异常,手动发送消息接收失败
             * 1、deliveryTag:该消息的index。
             * 2、multiple:是否批量. true:将一次性拒绝所有小于deliveryTag的消息。
             * 3、requeue:被拒绝的是否重新入队列。
             */
            Thread.sleep(1000);
            System.out.println("处理队列消息发生异常,重新将该消息抛进队列");
            System.out.println("deliveryTag:" + deliveryTag);
            channel.basicNack(deliveryTag, false, true);
        }
    }
}

总结

使用RabbitMQ的基本流程:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值