前言
本系列博客基于B站的云e办管理系统,前端和后端我都自己敲了一遍,这里做一个学习记录。云e办的原始视频链接如下:https://www.bilibili.com/video/BV1Ai4y1P7Tk?p=1
生产端可靠性投递的两种方案
消息落库方案
刚开始发送消息,消息状态是发送中,为0。
发送失败就重新发送,若是这次发送成功,消息状态改成1。
如果尝试了好几次(次数自己定义)都没有成功,设置状态为2。然后不再重试发送。
消息延迟投递方案
首先是消息生产端,它首先发送一次消息给rabbitMQ队列,过一会它会发送第二次消息,也就是一个延迟投递消息。然后MQ队列会把第一次消息传给消费端。消费端若是接收到这个消息,就会给MQ队列发送一个确认收到消息的信息,由MQ转发给回调服务,然后回调服务把这个确认信息缓存到消息数据库中。但要是它收到的是生产端延迟投递的消息,它和自己的消息数据库比对后发现没有这个确认信息,然后它就要求生产端重新开始第一步。
总的一个流程为
server模块新建消息投递状态实体类
再去修改员工服务实现类的添加员工的逻辑
记录消息,发送消息
然后写rabbitMQ的配置类
package com.xxxx.server.config.security;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xxxx.server.pojo.MailConstants.MailConstants;
import com.xxxx.server.pojo.MailLog;
import com.xxxx.server.service.IMailLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* rabbitmq配置类
*
* @author LinLinD
* @Create 2022-04-24-23:23
*/
@Configuration
public class RabbitMQConfig {
public static final Logger Logger = LoggerFactory.getLogger(RabbitMQConfig.class);
@Autowired
private CachingConnectionFactory cachingConnectionFactory;
@Autowired
private IMailLogService mailLogService;
@Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
/**
* 消息确认回调,确认消息是否到达broker
* data:消息唯一标识
* ack:确认结果
* cause:失败原因
*/
rabbitTemplate.setConfirmCallback((data,ack,cause) -> {
String msgId = data.getId();
if (ack) {
//消息确认成功
Logger.info("{}=====>消息发送成功", msgId);
//更新数据库中记录
mailLogService.update(new UpdateWrapper<MailLog>()
.set("status", 1)
.eq("msgId", msgId));
} else {
Logger.info("{}=====>消息发送失败", msgId);
}
});
/**
* 消息失败回调,比如router不到queue时回调
* msg:消息主题
* repCode:响应码
* repText:响应描述
* exchange:交换机
* routingKey:路由键
*/
rabbitTemplate.setReturnCallback((msg,repCode,repText,exchange,routingKey) -> {
Logger.info("{}=====>消息发送到queue时失败", msg.getBody());
});
return rabbitTemplate;
}
@Bean
public Queue queue() {
return new Queue(MailConstants.MAIL_QUEUE_NAME);
}
@Bean
public DirectExchange directExchange() {
return new DirectExchange(MailConstants.MAIL_EXCHANGE_NAME);
}
@Bean
public Binding binding() {
return BindingBuilder
.bind(queue())
.to(directExchange())
.with(MailConstants.MAIL_ROUTING_KEY_NAME);
}
}