rabbitMq 客户端查看 : 在安装完rabbitMq后,输入http://ip:15672/ ,是可以看到一个简单后台管理界面的
在这个界面里面我们可以做些什么?
可以手动创建虚拟host,创建用户,分配权限,创建交换机,创建队列等等,还有查看队列消息,消费效率,推送效率等等。
首先先介绍一个简单的一个消息推送到接收的流程,提供一个简单的图:
黄色的圈圈就是我们的消息推送服务,将消息推送到 中间方框里面也就是 rabbitMq的服务器,然后经过服务器里面的交换机、队列等各种关系(后面会详细讲)将数据处理入列后,最终右边的蓝色圈圈消费者获取对应监听的消息。
rabbitMq简单编码 (实例:发送短信)
首先创建 rabbitmq-provider,
pom.xml里用到的jar依赖:
<!--rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.mq-amqp</groupId>
<artifactId>mq-amqp-client</artifactId>
<version>1.0.5</version>
</dependency>
application.yml 配置
## 配置rabbitMQ 信息
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
# 开启发送确认
publisher-confirms: true
# 开启发送失败退回
publisher-returns: true
# 消息 rabbitmq 的自定义相关配置
rabbit:
msg:
exchange:
fanout:
name: msg_fanout_exchange
topic:
name: msg_topic_exchange
alternate:
name: msg_alternate_exchange
dead:
name: msg_dead_exchange
queue:
sms:
name: msg.sms.send
dead:
name: msg.sms.dead.send
upstream:
name: msg.sms.upstream
alternate:
name: msg.alternate
route:
sms: msg.sms.send
upstream: msg.sms.upstream
消息 rabbitMq 属性配置 配置交换机,并绑定
/**
* @desc:消息 rabbitMq 属性配置
* @author:
* @date: 2020/6/24 15:40
* @version: 3.0.0
* @since: 3.0.0
*/
@RefreshScope
@Component
public class RabbitMqMsgProperties {
// 扇形交换机名称
@Value("${rabbit.msg.exchange.fanout.name}")
private String fanoutExchangeName;
// 备份换机名称
@Value("${rabbit.msg.exchange.alternate.name}")
private String alternateExchangeName;
// TOPIC换机名称
@Value("${rabbit.msg.exchange.topic.name}")
private String topicExchangeName;
// 消息死信交换机名称
@Value("${rabbit.msg.exchange.dead.name}")
private String deadExchangeName;
// 备份队列名称
@Value("${rabbit.msg.queue.alternate.name}")
private String alternateQueueName;
// 短信消息队列名称
@Value("${rabbit.msg.queue.sms.name}")
private String smsQueueName;
// 短信消息死信队列名称
@Value("${rabbit.msg.queue.sms.dead.name}")
private String smsDeadQueueName;
// 邮件消息队列名称
@Value("${rabbit.msg.queue.email.name}")
private String emailQueueName;
// 邮件消息死信队列名称
@Value("${rabbit.msg.queue.email.dead.name}")
private String emailDeadQueueName;
// 上行消息队列名称
@Value("${rabbit.msg.queue.upstream.name}")
private String upstreamQueueName;
// 短信消息路由键
@Value("${rabbit.msg.route.sms}")
private String smsRouteKey;
// 邮件消息路由键
@Value("${rabbit.msg.route.email}")
private String emailRouteKey;
// 上行消息路由键
@Value("${rabbit.msg.route.upstream}")
private String upstreamRouteKey;
// 微信消息队列名称
@Value("${rabbit.msg.queue.wx.name}")
private String wxQueueName;
// 微信消息路由键
@Value("${rabbit.msg.route.wx}")
private String wxRouteKey;
// 微信消息死信队列名称
@Value("${rabbit.msg.queue.wx.dead.name}")
private String wxDeadQueueName;
public String getFanoutExchangeName() {
return fanoutExchangeName;
}
public void setFanoutExchangeName(String fanoutExchangeName) {
this.fanoutExchangeName = fanoutExchangeName;
}
public String getSmsQueueName() {
return smsQueueName;
}
public void setSmsQueueName(String smsQueueName) {
this.smsQueueName = smsQueueName;
}
public String getEmailQueueName() {
return emailQueueName;
}
public void setEmailQueueName(String emailQueueName) {
this.emailQueueName = emailQueueName;
}
public String getUpstreamQueueName() {
return upstreamQueueName;
}
public void setUpstreamQueueName(String upstreamQueueName) {
this.upstreamQueueName = upstreamQueueName;
}
public String getTopicExchangeName() {
return topicExchangeName;
}
public void setTopicExchangeName(String topicExchangeName) {
this.topicExchangeName = topicExchangeName;
}
public String getSmsRouteKey() {
return smsRouteKey;
}
public void setSmsRouteKey(String smsRouteKey) {
this.smsRouteKey = smsRouteKey;
}
public String getEmailRouteKey() {
return emailRouteKey;
}
public void setEmailRouteKey(String emailRouteKey) {
this.emailRouteKey = emailRouteKey;
}
public String getUpstreamRouteKey() {
return upstreamRouteKey;
}
public void setUpstreamRouteKey(String upstreamRouteKey) {
this.upstreamRouteKey = upstreamRouteKey;
}
public String getAlternateExchangeName() {
return alternateExchangeName;
}
public void setAlternateExchangeName(String alternateExchangeName) {
this.alternateExchangeName = alternateExchangeName;
}
public String getAlternateQueueName() {
return alternateQueueName;
}
public void setAlternateQueueName(String alternateQueueName) {
this.alternateQueueName = alternateQueueName;
}
public String getSmsDeadQueueName() {
return smsDeadQueueName;
}
public void setSmsDeadQueueName(String smsDeadQueueName) {
this.smsDeadQueueName = smsDeadQueueName;
}
public String getEmailDeadQueueName() {
return emailDeadQueueName;
}
public void setEmailDeadQueueName(String emailDeadQueueName) {
this.emailDeadQueueName = emailDeadQueueName;
}
public String getDeadExchangeName() {
return deadExchangeName;
}
public void setDeadExchangeName(String deadExchangeName) {
this.deadExchangeName = deadExchangeName;
}
public String getWxQueueName() {
return wxQueueName;
}
public void setWxQueueName(String wxQueueName) {
this.wxQueueName = wxQueueName;
}
public String getWxRouteKey() {
return wxRouteKey;
}
public void setWxRouteKey(String wxRouteKey) {
this.wxRouteKey = wxRouteKey;
}
public String getWxDeadQueueName() {
return wxDeadQueueName;
}
public void setWxDeadQueueName(String wxDeadQueueName) {
this.wxDeadQueueName = wxDeadQueueName;
}
}
package cn.ygyg.bps.msg.api.conf;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* @desc:消息 rabbitmq 配置类
* @author: guanliang.xue
* @date: 2020/6/24 15:07
* @version: 3.0.0
* @since: 3.0.0
*/
@Configuration
@ConditionalOnBean(value = RabbitMqMsgProperties.class)
public class RabbitMqMsgConfig {
@Resource
private RabbitMqMsgProperties rabbitMqMsgProperties;
/**
* 定义备份交换机
* @return 备份交换机
*/
@Bean
public FanoutExchange alternateExchange(){
return new FanoutExchange(rabbitMqMsgProperties.getAlternateExchangeName());
}
/**
* 定义扇形交换机
* @return
*/
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange(rabbitMqMsgProperties.getFanoutExchangeName());
}
/**
* 定义TOPIC交换机
* @return
*/
@Bean
public TopicExchange topicExchange(){
Map<String, Object> arguments = new HashMap<>();
return new TopicExchange(rabbitMqMsgProperties.getTopicExchangeName(),true,false,arguments);
}
/**
* 死信交换机
* @return
*/
@Bean
public DirectExchange deadExchange(){
return new DirectExchange(rabbitMqMsgProperties.getDeadExchangeName(),true,false);
}
/**
* 备份队列
* @return 队列
*/
@Bean
public Queue alternateQueue(){
return new Queue(rabbitMqMsgProperties.getAlternateQueueName());
}
/**
* 短信队列
* @return
*/
@Bean
public Queue smsQueue(){
Map<String, Object> args = new HashMap<>(2);
// x-dead-letter-exchange 这里声明当前队列绑定的死信交换机
// x-dead-letter-routing-key 死信路由key,默认使用原有路由key
args.put("x-dead-letter-exchange", rabbitMqMsgProperties.getDeadExchangeName());
return QueueBuilder.durable(rabbitMqMsgProperties.getSmsQueueName())
.withArguments(args)
.build();
}
/**
* 微信队列
* @return
*/
@Bean
public Queue wxQueue(){
Map<String, Object> args = new HashMap<>(2);
// x-dead-letter-exchange 这里声明当前队列绑定的死信交换机
// x-dead-letter-routing-key 死信路由key,默认使用原有路由key
args.put("x-dead-letter-exchange", rabbitMqMsgProperties.getDeadExchangeName());
return QueueBuilder.durable(rabbitMqMsgProperties.getWxQueueName())
.withArguments(args)
.build();
}
/**
* 邮件队列
* @return
*/
@Bean
public Queue emailQueue(){
Map<String, Object> args = new HashMap<>(2);
// x-dead-letter-exchange 这里声明当前队列绑定的死信交换机
// x-dead-letter-routing-key 死信路由key,默认使用原有路由key
args.put("x-dead-letter-exchange", rabbitMqMsgProperties.getDeadExchangeName());
return QueueBuilder.durable(rabbitMqMsgProperties.getEmailQueueName())
.withArguments(args)
.build();
}
/**
* sms 死信队列
* @return
*/
@Bean
public Queue smsDeadQueue(){
return new Queue(rabbitMqMsgProperties.getSmsDeadQueueName());
}
/**
* email 死信队列
* @return
*/
@Bean
public Queue emailDeadQueue(){
return new Queue(rabbitMqMsgProperties.getEmailDeadQueueName());
}
/**
* wx 死信队列
* @return
*/
@Bean
public Queue wxDeadQueue(){
return new Queue(rabbitMqMsgProperties.getWxDeadQueueName());
}
/**
* 服务商上行队列
* @return
*/
@Bean
public Queue upstreamQueue(){
return new Queue(rabbitMqMsgProperties.getUpstreamQueueName());
}
/**
* 绑定sms死信列到死信交换机
* @param queue 死信队列
* @return
*/
@Bean
public Binding bindSmsDead(@Qualifier("smsDeadQueue") Queue queue,
@Qualifier("deadExchange") DirectExchange directExchange){
return BindingBuilder.bind(queue).to(directExchange).with(rabbitMqMsgProperties.getSmsRouteKey());
}
/**
* 绑定email死信列到死信交换机
* @param queue 死信队列
* @return
*/
@Bean
public Binding bindEmailDead(@Qualifier("emailDeadQueue") Queue queue,
@Qualifier("deadExchange") DirectExchange directExchange){
return BindingBuilder.bind(queue).to(directExchange).with(rabbitMqMsgProperties.getEmailRouteKey());
}
/**
* 绑定wx死信列到死信交换机
* @param queue 死信队列
* @return
*/
@Bean
public Binding bindWxDead(@Qualifier("wxDeadQueue") Queue queue,
@Qualifier("deadExchange") DirectExchange directExchange){
return BindingBuilder.bind(queue).to(directExchange).with(rabbitMqMsgProperties.getWxRouteKey());
}
/**
* 绑定备份列到备份交换机
* @param queue 备份队列
* @return
*/
@Bean
public Binding bindAlternate(@Qualifier("alternateQueue") Queue queue,
@Qualifier("alternateExchange") FanoutExchange fanoutExchange){
return BindingBuilder.bind(queue).to(fanoutExchange);
}
/**
* 绑定短信队列到TOPIC交换机
* @param queue
* @param topicExchange
* @return
*/
@Bean
public Binding bindSms(@Qualifier("smsQueue") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange){
return BindingBuilder.bind(queue).to(topicExchange).with(rabbitMqMsgProperties.getSmsRouteKey());
}
/**
* 绑定邮件队列
* @param queue
* @param topicExchange
* @return
*/
@Bean
public Binding bindEmail(@Qualifier("emailQueue") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange){
return BindingBuilder.bind(queue).to(topicExchange).with(rabbitMqMsgProperties.getEmailRouteKey());
}
/**
* 绑定微信队列
* @param queue
* @param topicExchange
* @return
*/
@Bean
public Binding bindWx(@Qualifier("wxQueue") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange){
return BindingBuilder.bind(queue).to(topicExchange).with(rabbitMqMsgProperties.getWxRouteKey());
}
/**
* 绑定上行消息队列
* @param queue
* @param topicExchange
* @return
*/
@Bean
public Binding bindUpstream(@Qualifier("upstreamQueue") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange){
return BindingBuilder.bind(queue).to(topicExchange).with(rabbitMqMsgProperties.getUpstreamRouteKey());
}
@Bean
@ConditionalOnMissingBean(AliyunAmqpConfig.class)
@ConditionalOnBean(RabbitAutoConfiguration.class)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RabbitTemplate rabbitTemplate(@Qualifier("rabbitConnectionFactory") CachingConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMandatory(true);
template.setConfirmCallback(new RabbitMqMsgConfirmCallback());
template.setReturnCallback(new RabbitMqMsgReturnCallback());
return template;
}
@Bean
@ConditionalOnBean(AliyunAmqpConfig.class)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RabbitTemplate aliRabbitTemplate(@Qualifier("aliRabbitConnectionFactory") ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMandatory(true);
template.setConfirmCallback(new RabbitMqMsgConfirmCallback());
template.setReturnCallback(new RabbitMqMsgReturnCallback());
return template;
}
}
controller 类 简易代码
/**
* @desc:短信控制类
* @author:
* @date: 2020/7/20 14:33
* @version: 3.0.0
* @since: 3.0.0
*/
@Api(tags = "消息controller")
@RestController
@RefreshScope
@RequestMapping("/msg/api/sms")
public class SmsController {
@Resource
private RabbitTemplate rabbitTemplate;
@Resource
private RabbitMqMsgProperties rabbitMqMsgProperties;
@ApiOperation(value = "短信发送接口")
@PostMapping(value = "/send")
public Boolean send(@RequestBody @Validated({ValidGroupMsgSend.class}) MsgSendDTO msgSendDTO) throws JsonProcessingException {
// msgSendDTO 对象中是要发送给mq中的信息 此处省略处理
Message message = MessageBuilder
.withBody(JsonUtils.toText(msgSendDTO).getBytes())
.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
.build();
// 全局唯一
CorrelationData correlationData = new CorrelationData(new SnowFlakeIdGenerator().newId() +"");
rabbitTemplate.convertAndSend(rabbitMqMsgProperties.getTopicExchangeName(),
rabbitMqMsgProperties.getSmsRouteKey(),message,correlationData);
return true;
}
}
Consumer接收mq对应队列信息
pom包文件
<!--rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.mq-amqp</groupId>
<artifactId>mq-amqp-client</artifactId>
<version>1.0.5</version>
</dependency>
配置文件信息
# rabbitMq 的相关配置
rabbitmq:
host: 192.168.118.160
port: 5672
username: admin
password: admin
listener:
simple:
acknowledge-mode: manual
concurrency: 1 # 并发线程
default-requeue-rejected: false
工具类JsonUtils
/**
* JSON处理辅助功能
*/
public final class JsonUtils {
/**
* MAP对象类型
*/
private static final MapType MAP_TYPE;
/**
* MAP对象类型
*/
private static final CollectionType LIST_TYPE;
/**
* 默认JSON对象映射器
*/
private static ObjectMapper defaultMapper;
// 静态变量初始化
static {
MAP_TYPE = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Object.class);
LIST_TYPE = TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, MAP_TYPE);
defaultMapper = new ObjectMapper();
defaultMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
defaultMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
defaultMapper.enable(JsonParser.Feature.ALLOW_MISSING_VALUES);
defaultMapper.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
defaultMapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
defaultMapper.registerModule(javaTimeModule);
}
/**
* 构造方法(静态类禁止创建)
*/
private JsonUtils() {
}
/**
* 对象输出JSON文本
*
* @param out 输出
* @param object 对象
*/
public static void toOutput(OutputStream out, Object object) {
if (object == null) {
return;
}
try {
defaultMapper.writeValue(out, object);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 对象转换为JSON文本
*
* @param object 对象
* @return String JSON文本
*/
public static String toText(Object object) {
if (object == null) {
return null;
}
try {
return defaultMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* JSON文本转换为对象
*
* @param <T> 类型
* @param jsonText JSON文本
* @param cls 类型
* @return T 数据对象
*/
public static <T> T toObject(String jsonText, Class<T> cls) {
if (jsonText == null || jsonText.isEmpty()) {
return null;
}
try {
return defaultMapper.readValue(jsonText, cls);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* JSON文本转换为对象
*
* @param jsonText JSON文本
* @return Map
*/
public static Map<String, Object> toMap(String jsonText) {
if (jsonText == null || jsonText.isEmpty()) {
return null;
}
try {
return defaultMapper.readValue(jsonText, MAP_TYPE);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* JSON文本转换为对象
*
* @param <T> 类型
* @param jsonText JSON文本
* @param cls 类型
* @return Map
*/
public static <T> Map<String, T> toMap(String jsonText, Class<T> cls) {
if (jsonText == null || jsonText.isEmpty()) {
return null;
}
try {
return defaultMapper.readValue(jsonText,
TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, cls));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* JSON文本转换为列表
*
* @param jsonText JSON文本
* @return List<Map>
*/
public static List<Map<String, Object>> toList(String jsonText) {
if (jsonText == null || jsonText.isEmpty()) {
return null;
}
try {
return defaultMapper.readValue(jsonText, LIST_TYPE);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* JSON文本转换为列表
*
* @param <T> 类型
* @param jsonText JSON文本
* @param cls 类型
* @return List<T> 数据列表
*/
public static <T> List<T> toList(String jsonText, Class<T> cls) {
if (jsonText == null || jsonText.isEmpty()) {
return null;
}
try {
return defaultMapper.readValue(jsonText,
TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, cls));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Consumer接收类
@Slf4j
@Component
public class MsgSmsConsumer {
@Resource
private SmsProcessServiceImpl smsProcessServiceImpl;
/**
* 短信消息处理
*
* @param msgContent 消息内容
* @param message 消息
*/
@RabbitListener(queues = "msg.sms.send")
@RabbitHandler
public void smsProcess(String msgContent, Message message, Channel channel) throws IOException {
// 转换消息
MsgSendDTO msgSendDTO = JsonUtils.toObject(msgContent, MsgSendDTO.class);
boolean ack = true;
BusinessException bizException = null;
try {
if (!ObjectUtils.isEmpty(msgSendDTO)) {
log.info("收到[{}]消息[{}]", msgCategory, JsonUtils.toText(msgSendDTO));
boolean sendRet = smsProcessServiceImpl.msgSend(msgSendDTO); //处理之后业务
if (!sendRet) {
throw new BusinessException(MsgExceptionRetCode.MSG_SEND_FAILED,
MsgExceptionRetCode.MSG_SEND_FAILED.getMsg());
}
}
}
} catch (BusinessException e) {
log.error(e.getMessage());
ack = false;
bizException = e;
}
if (!ack) {
log.error("[{}]消息消费发生异常,错误信息:[{}]", msgCategory, bizException.getMessage(), bizException);
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
} else {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
/**
* sms死信消息处理
*
* @param msgContent 消息内容
* @param message 消息
*/
@RabbitListener(queues = "msg.sms.dead.send")
@RabbitHandler
public void smsDeadProcess(String msgContent, Message message, Channel channel) throws IOException {
log.info("收到[sms]死信消息:[{}]", msgContent);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}