1 引入依赖
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2 配置yml
YAML
spring:
rabbitmq:
host: 192.168.101.65
port: 5672
username: guest
password: guest
virtual-host: /
publisher-confirm-type: correlated #correlated 异步回调,定义ConfirmCallback,MQ返回结果时会回调这个ConfirmCallback
publisher-returns: false #开启publish-return功能,同样是基于callback机制,需要定义ReturnCallback
template:
mandatory: false #定义消息路由失败时的策略。true,则调用ReturnCallback;false:则直接丢弃消息
listener:
simple:
acknowledge-mode: none #出现异常时返回unack,消息回滚到mq;没有异常,返回ack ,manual:手动控制,none:丢弃消息,不回滚到mq
retry:
enabled: true #开启消费者失败重试
initial-interval: 1000ms #初识的失败等待时长为1秒
multiplier: 1 #失败的等待时长倍数,下次等待时长 = multiplier * last-interval
max-attempts: 3 #最大重试次数
stateless: true #true无状态;false有状态。如果业务中包含事务,这里改为false
3 编写MQ配置类,配置交换机
Java
package com.xuecheng.learning.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description 消息队列配置
* @author Mr.M
* @date 2022/10/4 22:25
* @version 1.0
*/
@Configuration
public class PayNotifyConfig {
//交换机
public static final String PAYNOTIFY_EXCHANGE_FANOUT = "paynotify_exchange_fanout";
//支付通知队列
public static final String PAYNOTIFY_QUEUE = "paynotify_queue";
//支付结果回复
public static final String PAYNOTIFY_REPLY_QUEUE = "paynotify_reply_queue";
//支付结果通知消息类型
public static final String MESSAGE_TYPE = "payresult_notify";
//声明交换机
@Bean(PAYNOTIFY_EXCHANGE_FANOUT)
public FanoutExchange paynotify_exchange_fanout(){
// 三个参数:交换机名称、是否持久化、当没有queue与其绑定时是否自动删除
return new FanoutExchange(PAYNOTIFY_EXCHANGE_FANOUT, true, false);
}
//支付通知队列
@Bean(PAYNOTIFY_QUEUE)
public Queue course_publish_queue(){
return QueueBuilder.durable(PAYNOTIFY_QUEUE).build();
}
//交换机和支付通知队列绑定
@Bean
public Binding binding_course_publish_queue(@Qualifier(PAYNOTIFY_QUEUE) Queue queue, @Qualifier(PAYNOTIFY_EXCHANGE_FANOUT) FanoutExchange exchange){
return BindingBuilder.bind(queue).to(exchange);
}
}
4 消息的发送类
@Override
public void notfy(MqMessage message) {
//消息内容
String jsonString = JSON.toJSONString(message);
//持久化消息
Message messages = MessageBuilder.withBody(jsonString.getBytes(StandardCharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
//全局消息id
Long id = message.getId();
CorrelationData correlationData = new CorrelationData(id.toString());
//使用correlationData指定回调方法
correlationData.getFuture().addCallback( result->{
if (result.isAck()) {
//消息成功发送到了交换机
log.debug("消息发送成功",messages);
}else {
//消息发送失败
log.debug("消息发送失败",messages);
// TODO: 2023/5/18将消息写到数据库里(消息表)
}
},eq->{
//消息发生异常
log.debug("消息发生异常",messages);
});
rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"",messages,correlationData);
}
5 消息监听配置类
package com.xuecheng.learning.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description 消息队列配置
* @author Mr.M
* @date 2022/10/4 22:25
* @version 1.0
*/
@Configuration
public class PayNotifyConfig {
//交换机
public static final String PAYNOTIFY_EXCHANGE_FANOUT = "paynotify_exchange_fanout";
//支付结果通知队列
public static final String PAYNOTIFY_QUEUE = "paynotify_queue";
//支付结果通知回复队列
public static final String PAYNOTIFY_REPLY_QUEUE = "paynotify_reply_queue";
//支付结果通知消息类型
public static final String MESSAGE_TYPE = "payresult_notify";
//声明交换机
@Bean(PAYNOTIFY_EXCHANGE_FANOUT)
public FanoutExchange paynotify_exchange_direct(){
// 三个参数:交换机名称、是否持久化、当没有queue与其绑定时是否自动删除
return new FanoutExchange(PAYNOTIFY_EXCHANGE_FANOUT, true, false);
}
//声明队列
@Bean(PAYNOTIFY_QUEUE)
public Queue course_publish_queue(){
return QueueBuilder.durable(PAYNOTIFY_QUEUE).build();
}
//支付结果回复队列
@Bean(PAYNOTIFY_REPLY_QUEUE)
public Queue msgnotify_result_queue(){
return QueueBuilder.durable(PAYNOTIFY_REPLY_QUEUE).build();
}
//交换机和队列绑定
@Bean
public Binding binding_course_publish_queue(@Qualifier(PAYNOTIFY_QUEUE) Queue queue, @Qualifier(PAYNOTIFY_EXCHANGE_FANOUT) FanoutExchange exchange){
return BindingBuilder.bind(queue).to(exchange);
}
}
5 消息监听
package com.xuecheng.learning.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.learning.config.PayNotifyConfig;
import com.xuecheng.learning.mapper.XcChooseCourseMapper;
import com.xuecheng.learning.model.po.XcChooseCourse;
import com.xuecheng.learning.service.MyCourseTablesService;
import com.xuecheng.messagesdk.model.po.MqMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Mr.M
* @version 1.0
* @description TODO
* @date 2022/10/26 11:24
*/
@Slf4j
@Component
public class ReceivePayNotifyService {
@Autowired
XcChooseCourseMapper chooseCourseMapper;
@Autowired
MyCourseTablesService myCourseTablesService;
@Autowired
RabbitTemplate rabbitTemplate;
//监听支付结果通知队列
@RabbitListener(queues = {PayNotifyConfig.PAYNOTIFY_QUEUE})
public void receive(String message) {
//解析消息
MqMessage mqMessage = JSON.parseObject(message, MqMessage.class);
//判断该消息是否自己的消息
String messageType = mqMessage.getMessageType();
//记录了订单类型
String businessKey2 = mqMessage.getBusinessKey2();
//只处理支付结果通知的消息,并且是学生购买课程的订单的消息
if(PayNotifyConfig.MESSAGE_TYPE.equals(messageType) && "60201".equals(businessKey2)){
//根据选课id查询选课表的记录
String businessKey1 = mqMessage.getBusinessKey1();
XcChooseCourse xcChooseCourse = chooseCourseMapper.selectById(businessKey1);
if(xcChooseCourse == null){
log.info("收到支付结果通知,查询不到选课记录,businessKey1:{}",businessKey1);
return ;
}
XcChooseCourse xcChooseCourse_u = new XcChooseCourse();
xcChooseCourse_u.setStatus("701001");//选课成功
chooseCourseMapper.update(xcChooseCourse_u,new LambdaQueryWrapper<XcChooseCourse>().eq(XcChooseCourse::getId,businessKey1));
//查询最新的选课记录
xcChooseCourse = chooseCourseMapper.selectById(businessKey1);
//向我的课程表添加记录
myCourseTablesService.addCourseTabls(xcChooseCourse);
//发送回复
send(mqMessage);
}
}
/**
* @description 回复消息
* @param message 回复消息
* @return void
* @author Mr.M
* @date 2022/9/20 9:43
*/
public void send(MqMessage message){
//转json
String msg = JSON.toJSONString(message);
JSON.parseObject(msg,String.class);
// 发送消息
rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_REPLY_QUEUE, msg);
log.debug("学习中心服务向订单服务回复消息:{}",message);
}
}