SpringBoot整合RabbitMQ,简易的队列发送短信实例

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

SpringBoot整合RabbitMQ,简易的队列发送短信实例
在这个界⾯⾥⾯我们可以做些什么?
可以⼿动创建虚拟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("${}")
private String fanoutExchangeName;
// 备份换机名称
@Value("${}")
private String alternateExchangeName;
// TOPIC换机名称
@Value("${}")
private String topicExchangeName;
// 消息死信交换机名称
@Value("${}")
private String deadExchangeName;
// 备份队列名称
@Value("${}")
private String alternateQueueName;
// 短信消息队列名称
@Value("${}")
private String smsQueueName;
// 短信消息死信队列名称
@Value("${}")
private String smsDeadQueueName;
// 邮件消息队列名称
@Value("${}")
private String emailQueueName;
// 邮件消息死信队列名称
@Value("${}")
private String emailDeadQueueName;
// 上⾏消息队列名称
@Value("${}")
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("${}")
private String wxQueueName;
// 微信消息路由键
@Value("${rabbit.msg.route.wx}")
private String wxRouteKey;
// 微信消息死信队列名称
@Value("${}")
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)) {
("收到[{}]消息[{}]", 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 { ("收到[sms]死信消息:[{}]", msgContent);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
详情介绍可参考他⼈链接:。

相关文档
最新文档