1.创建生产者工程
application.yml配置rabbitmq
spring:
redis:
host: 192.168.71.100
rabbitmq:
host: 192.168.71.100:虚拟机ip
virtual-host: /ysvh
username: admin
password: 123456
publisher-confirm-type: CORRELATED # 确认消息是否到达交换机:SIMPLE-同步确认(阻塞) CORRELATED-异步确认
publisher-returns: true # 确认消息是否到达队列
2.引入相关依赖
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
3.配置生产者config
package com.atguigu.gmall.ums.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
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;
import javax.annotation.PostConstruct;
@Configuration
@Slf4j
public class RabbitConfig {
@Autowired
private RabbitTemplate rabbitTemplate;
//构造器初始化后就会执行
@PostConstruct
public void init(){
//确认消息是否到达交换机的回调
this.rabbitTemplate.setConfirmCallback((correlationData,ack,cause)->{
if(ack){
System.out.println("消息已经到达交换机");
}else {
System.out.println("消息未到达交换机");
}
});
//确认消息是否到达队列的回调(只有消息无法到达队列才回调)
this.rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey)->{
log.error("消息未到达队列,交换机:{},路由键:{},消息内容:{}",exchange,routingKey,new String(message.getBody()));
});
}
//业务交换机
@Bean
public TopicExchange exchange(){
return ExchangeBuilder.topicExchange("UMS-MESSAGE-EXCHANGE").durable(true).build();
}
//业务队列
@Bean
public Queue queue(){
return QueueBuilder.durable("UMS-SENDMESSAGE-QUEUE")
.withArgument("x-dead-letter-exchange","UMS-DEAD-EXCHANGE")
.withArgument("x-message-ttl", 60000)
.withArgument("x-dead-letter-routing-key","msg.dead").build();
}
//业务交换机绑定业务队列
@Bean
public Binding binding(TopicExchange exchange, Queue queue){
return BindingBuilder.bind(queue).to(exchange).with("message.send");
}
//死信交换机
@Bean
public TopicExchange deadExchange(){
//return new TopicExchange("UMS-DEAD-EXCHANGE",true,false);
return ExchangeBuilder.topicExchange("UMS-DEAD-EXCHANGE").durable(true).build();
}
//死信队列
@Bean
public Queue deadQueue(){
//return new Queue("UMS-DEAD-EXCHANGE",true,false,false);
return QueueBuilder.durable("UMS-DEAD-QUEUE").build();
}
//绑定
@Bean
public Binding deadBinding(TopicExchange deadExchange,Queue deadQueue){
//return new Binding("SPRING-DEAD-QUEUE",Binding.DestinationType.QUEUE,"SPRING-DEAD-EXCHANGE","msg.dead",null);
return BindingBuilder.bind(deadQueue).to(deadExchange).with("msg.dead");
}
}
4.controller
@Api(tags = "用户表 管理")
@RestController
@RequestMapping("ums/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("send")
public ResponseVo<Object> sendMessage(UserEntity userEntity) {
this.userService.sendMessage(userEntity.getPhone());
return ResponseVo.ok(null);
}
}
5.service
public interface UserService extends IService<UserEntity> {
void sendMessage(String phone);
}
6.service.impl
通过rabbitTemplate的convertAndSend方法发送消息phone给交换机UMS-MESSAGE-EXCHANGE
@Override
public void sendMessage(String phone){
this.rabbitTemplate.convertAndSend("UMS-MESSAGE-EXCHANGE","message.send",phone);
}
7.创建消费者工程
application.yml配置rabbitmq
spring:
redis:
host: 192.168.71.100
rabbitmq:
host: 192.168.71.100
virtual-host: /ysvh
username: admin
password: 123456
listener:
simple:
acknowledge-mode: manual #手动确认
#none-不确认模式(原生api的自动确认) auto-自动确认模式(正常执行即确认;执行异常会无限重试) manual手动确认
prefetch: 1 #开启能者多劳
#如何避免消息堆积? 搭建消费者集群(能者多劳);开启消费者的多线程
#开启多个线程
concurrency: 3
##阿里云短信
aliyun:
sms:
regionId: cn-hangzhou
keyId: 阿里云keyid
keySecret: XXXX
templateCode: XXXX
signName: 你的签名
8.引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>gmall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--阿里云短信-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
9.创建消费者监听器config
package com.atguigu.gmall.message.listener;
import com.atguigu.gmall.common.utils.FormUtils;
import com.atguigu.gmall.common.utils.RandomUtils;
import com.atguigu.gmall.message.service.SmsService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class MessageListener {
@Autowired
private SmsService smsService;
@Autowired
private StringRedisTemplate redisTemplate;
private static final String KEY_PREFIX="message:";
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "UMS-SENDMESSAGE-QUEUE",durable = "true"),//durable:是否持久化
//忽略声明异常:当一个交换机已经存在时,再次声明,若属性不一致,会出现声明异常
exchange = @Exchange(value = "UMS-MESSAGE-EXCHANGE",ignoreDeclarationExceptions = "true",type = ExchangeTypes.TOPIC),
key = {"message.send"}
))
public void listener(String phone, Channel channel, Message message) throws IOException {
try {
//校验手机号是否合法
if(StringUtils.isEmpty(phone) || !FormUtils.isMobile(phone)) {
log.error("请输入正确的手机号码 ");
//throw new GuliException(ResultCodeEnum.LOGIN_PHONE_ERROR);
}
//生成验证码
String checkCode = RandomUtils.getFourBitRandom();
//发送验证码
smsService.send(phone, checkCode);
//将验证码存入redis缓存
redisTemplate.opsForValue().set(KEY_PREFIX+phone, checkCode, 5, TimeUnit.MINUTES);
//手动确认 multiple:true:确认多条
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
} catch (Exception e) {
e.printStackTrace();
//是否重复投递
if(message.getMessageProperties().getRedelivered()){
//记录下来,放入数据库
//如果一条消息被拒绝,并且该队列绑定了死信队列的情况下,该消息会进入死信队列
channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
}else {
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
}
}
}
}