RabbitMQ在springboot中實(shí)現(xiàn)短信服務(wù)的異步通信方式
springboot中RabbitMQ基本使用
RabbitMQ是一個(gè)開源的消息中間件
具有以下用途和優(yōu)點(diǎn):
- 異步通信:RabbitMQ可以作為應(yīng)用程序之間進(jìn)行異步通信的媒介,生產(chǎn)者可以將消息發(fā)送到RabbitMQ,而消費(fèi)者可以從中獲取消息并進(jìn)行處理。這種異步通信可以實(shí)現(xiàn)系統(tǒng)各部分的解耦,提高系統(tǒng)的可伸縮性和性能。
- 應(yīng)用解耦:通過使用RabbitMQ,不同的應(yīng)用程序可以通過發(fā)送和接收消息來解耦,并減少應(yīng)用之間的依賴。這樣可以提高系統(tǒng)的靈活性,使系統(tǒng)更易于維護(hù)和擴(kuò)展。
- 可靠消息傳遞:RabbitMQ確保消息傳遞的可靠性。它提供持久化和消息確認(rèn)機(jī)制,即使在消息發(fā)送或消費(fèi)者出現(xiàn)故障的情況下,也能保證消息的不丟失和不重復(fù)。
- 靈活的消息路由和交換:RabbitMQ支持多種消息路由模式和交換機(jī)類型,如直連、扇形、主題和頭部交換機(jī)。這使得可以根據(jù)消息的內(nèi)容和標(biāo)簽將消息路由到不同的隊(duì)列中,滿足各種復(fù)雜的應(yīng)用場景。
- 延遲消息處理:RabbitMQ支持延遲消息的發(fā)送和處理,可以用于處理定時(shí)任務(wù)、延遲通知和調(diào)度等需求。
- 分布式系統(tǒng)中的協(xié)調(diào):RabbitMQ在分布式系統(tǒng)中扮演著關(guān)鍵的角色,可以用于實(shí)現(xiàn)分布式系統(tǒng)的任務(wù)分發(fā)、事件發(fā)布訂閱、分布式鎖等。它提供了一種簡單而強(qiáng)大的方式來處理分布式系統(tǒng)間的通信和協(xié)調(diào)機(jī)制。
RabbitMQ是一個(gè)功能強(qiáng)大、可靠性高且易于使用的消息中間件。它在異步通信、應(yīng)用解耦、可靠消息傳遞、靈活的消息路由和交換、延遲消息處理以及分布式系統(tǒng)中的協(xié)調(diào)等方面具有廣泛應(yīng)用。
在SpringbBoot在使用首先需要在rabbitmq管理界面新建隊(duì)列和交換機(jī)。


RabbitMQ支持多種類型的交換機(jī),用于定義消息的路由規(guī)則。
以下是幾種常見的交換機(jī)類型:
- 直連交換機(jī)(Direct Exchange):根據(jù)消息的路由鍵(Routing Key)精確地將消息路由到匹配的隊(duì)列。例如,通過將消息的路由鍵設(shè)置為特定的關(guān)鍵詞,可以將消息發(fā)送到對應(yīng)的隊(duì)列,以便消費(fèi)者進(jìn)行處理。
- 扇形交換機(jī)(Fanout Exchange):將消息廣播到所有與交換機(jī)綁定的隊(duì)列。無論消息的路由鍵是什么,扇形交換機(jī)都會(huì)將消息發(fā)送到所有綁定的隊(duì)列中。適用于多個(gè)消費(fèi)者需要處理相同消息的場景。
- 主題交換機(jī)(Topic Exchange):根據(jù)路由鍵的模式進(jìn)行匹配和路由??梢允褂猛ㄅ浞?hào)“*”匹配一個(gè)單詞,使用“#”匹配零個(gè)或多個(gè)單詞。主題交換機(jī)可以滿足更復(fù)雜的路由需求,可以將消息路由到多個(gè)隊(duì)列。
- 頭部交換機(jī)(Headers Exchange):根據(jù)消息的頭部屬性進(jìn)行匹配和路由。消息發(fā)布者在發(fā)送消息時(shí)可以在消息的頭部添加自定義的屬性,交換機(jī)將根據(jù)這些屬性進(jìn)行匹配和路由。
不同類型的交換機(jī)適用于不同的應(yīng)用場景,開發(fā)者可以根據(jù)具體需求選擇適合的交換機(jī)類型來進(jìn)行消息路由和分發(fā)。
在項(xiàng)目中引入依賴
<!-- RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>yml文件配置
rabbitmq的用戶名和密碼都為默認(rèn)
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/market?useSSl=true&useUnicode=true$characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: 010409
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest交換機(jī)與隊(duì)列綁定配置
@Configuration
public class RabbitMQConfig {
private static final String MARKET = "market";
private static final String ORDER = "order";
private static final String EXCHANGE = "market.exChanges";
@Bean
public Queue queue01(){
return new Queue(MARKET);
}
@Bean
public Queue queue02(){
return new Queue(ORDER);
}
@Bean
public DirectExchange fanoutExchange(){
return new DirectExchange(EXCHANGE);
}
// 綁定交換機(jī)和隊(duì)列
@Bean
public Binding binding01(){
return BindingBuilder.bind(queue01()).to(fanoutExchange()).with("market");
}
@Bean
public Binding binding02(){
return BindingBuilder.bind(queue02()).to(fanoutExchange()).with("order");
}
}應(yīng)用場景
短信驗(yàn)證碼服務(wù),這里我使用的是阿里云短信服務(wù)SMS,將短信驗(yàn)證碼與前端輸入的手機(jī)號(hào)存入隊(duì)列中,將驗(yàn)證碼存入redis中,方便后續(xù)注冊時(shí)驗(yàn)證碼驗(yàn)證,最后監(jiān)聽隊(duì)列拿到信息后發(fā)送短信。
SMS依賴與配置,需要將配置修改為自己的
<!-- 阿里云短信依賴 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.16</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>2.1.0</version>
</dependency>@Service
public class SmsService {
public boolean send(Map<String, Object> param, String phone) {
if(StringUtils.isEmpty(phone)) return false;
//default 地域節(jié)點(diǎn),默認(rèn)就好 后面是 阿里云的 id和秘鑰(這里記得去阿里云復(fù)制自己的id和秘鑰哦)
DefaultProfile profile = DefaultProfile.getProfile("default", "LTAI5tNtEzgs7etoRVhWQuXz", "X8odaVou1eSwT0boKEgvYxPSUtWafL");
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
request.setProtocol(ProtocolType.HTTPS);
request.setMethod(MethodType.POST);
request.setDomain("dysmsapi.aliyuncs.com");
request.setVersion("2017-05-25");
request.setAction("SendSms");
request.putQueryParameter("PhoneNumbers", phone); //手機(jī)號(hào)
request.putQueryParameter("SignName", "阿里云短信測試"); //申請阿里云 簽名名稱(暫時(shí)用阿里云測試的,自己還不能注冊簽名)
request.putQueryParameter("TemplateCode", "SMS_154950909"); //申請阿里云 模板code(用的也是阿里云測試的)
request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));
try {
CommonResponse response = client.getCommonResponse(request);
// System.out.println(response.getData());
return response.getHttpResponse().isSuccess();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
發(fā)送短信的接口:
@RequestMapping("/sendCode")
public Result sendCode(String phone){
return UserService.sendCode(phone);
}
實(shí)現(xiàn):
@Override
public Result sendCode(String phone) {
// 1.校驗(yàn)手機(jī)號(hào)
String regex = "^1[3456789]\\d{9}$";
if (!phone.matches(regex)) {
// 2.如果不符合,返回錯(cuò)誤信息
return new Result(100,"手機(jī)號(hào)格式錯(cuò)誤!");
}
// 3. 生成驗(yàn)證碼
String code = "";
for (int i = 0; i < 6; i++) {
int var = new Random().nextInt(10);
code = code + var;
}
Map<String,Object> param = new HashMap<>();
param.put("code", code);
// 4.保存驗(yàn)證碼到 redis
redisCache.setCacheObject(phone,code);
Map<String,String> map=new HashMap();
map.put("phone", phone);
map.put("code", code);
// 5.保存驗(yàn)證碼和手機(jī)號(hào)到隊(duì)列
rabbitTemplate.convertAndSend("market.exChanges","market",map);
return new Result(200, "發(fā)送成功");
}
監(jiān)聽隊(duì)列并發(fā)送短信。
@RabbitListener(queues = "market")
@RabbitHandler
public void executeSPC(Map<String, String> map, Channel channel, @Headers Map<String, Object> headers) throws IOException {
try {
Map<String,Object> param = new HashMap<>();
param.put("code", map.get("code"));
smsService.send(param, map.get("phone"));
// 手動(dòng)發(fā)送ACK,確認(rèn)消息已接收
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
// 處理異常情況,根據(jù)業(yè)務(wù)需要選擇是否重新入列或者拒絕消息等操作
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
channel.basicNack(deliveryTag, false, true);
}
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java導(dǎo)出Excel實(shí)現(xiàn)八倍效率優(yōu)化的方法詳解
這篇文章主要為大家詳細(xì)介紹了java導(dǎo)出Excel實(shí)現(xiàn)八倍效率優(yōu)化的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-11-11
如何使用Idea中的 Deployment 實(shí)現(xiàn)打包自動(dòng)部署
這篇文章主要介紹了使用Idea中的 Deployment 實(shí)現(xiàn)打包自動(dòng)部署,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
SpringBoot實(shí)現(xiàn)Thymeleaf驗(yàn)證碼生成
本文使用SpringBoot實(shí)現(xiàn)Thymeleaf驗(yàn)證碼生成,使用后臺(tái)返回驗(yàn)證碼圖片,驗(yàn)證碼存到session中后端實(shí)現(xiàn)校驗(yàn),前端只展示驗(yàn)證碼圖片。感興趣的可以了解下2021-05-05
Java編程實(shí)現(xiàn)獲取當(dāng)前代碼行行號(hào)的方法示例
這篇文章主要介紹了Java編程實(shí)現(xiàn)獲取當(dāng)前代碼行行號(hào)的方法,結(jié)合實(shí)例形式分析了java基于StackTraceElement對象實(shí)現(xiàn)獲取代碼行號(hào)的相關(guān)操作技巧,需要的朋友可以參考下2017-08-08
使用SpringBoot簡單實(shí)現(xiàn)無感知的刷新 Token功能
實(shí)現(xiàn)無感知的刷新 Token 是一種提升用戶體驗(yàn)的常用技術(shù),可以在用戶使用應(yīng)用時(shí)自動(dòng)更新 Token,無需用戶手動(dòng)干預(yù),這種技術(shù)在需要長時(shí)間保持用戶登錄狀態(tài)的應(yīng)用中非常有用,以下是使用Spring Boot實(shí)現(xiàn)無感知刷新Token的一個(gè)場景案例和相應(yīng)的示例代碼2024-09-09
當(dāng)mybatis返回值遇見內(nèi)部類的問題
這篇文章主要介紹了當(dāng)mybatis返回值遇見內(nèi)部類的問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12

