spring boot>>RabbitMQ中間件發送驗證碼

起因:

短信發送的應用場景非常多,在較大的系統中,短信一般作爲單獨的服務獨立運行,
而短信發送任務的觸發基本有兩種方式。1、定時獲取Redis中短信發送任務,2、消息中間件訂閱短息任務隊列。

RabbitMQ訂閱短信:

短信服務:

短信服務爲獨立工程。將阿里雲 SmsServer抽取爲工具類。

1、pom依賴:

		<!-- RabbitMQ -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
		
		<!-- 阿里sms短信服務 -->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>${aliyun-java-sdk-core.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>${aliyun-java-sdk-dysmsapi.version}</version>
        </dependency>
		<!-- 阿里sms短信服務 -->
        
        <!-- 極光推送 -->
        <dependency>
            <groupId>cn.jpush.api</groupId>
            <artifactId>jpush-client</artifactId>
            <version>3.2.17</version>
        </dependency>
        <dependency>
            <groupId>cn.jpush.api</groupId>
            <artifactId>jiguang-common</artifactId>
            <version>1.0.3</version>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.6.Final</version>
            <scope>compile</scope>
        </dependency>
        <!-- 極光推送 -->

2、啓動類:

@SpringBootApplication
@EnableAsync
public class SmsServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(SmsServerApplication.class, args);
	}
}

3、SmsQueueConfig類

@Configuration
public class SmsQueueConfig {

	/**
	 * 消息隊列
	 * @return
	 */
	@Bean
	public Queue smsQueue(){
        return new Queue("sms");
    }
}

4、JGuangConfig類

@Configuration
public class JGuangConfig {

	@Value("${jpush.master.jpushAppKey}")
	private String jpushAppKey; 
	@Value("${jpush.master.secret}")
	private String jpushMasterSecret;
	
	@Bean
	public JPushClient getJPushClient() {
		return new JPushClient(jpushMasterSecret, jpushAppKey);
	}
}

 5、極光推送服務

@Log4j
@Service
public class JpushService {
	
	@Autowired
	private JPushClient jPushClient;

	/**
	 * 給手機推送異常提醒
	 */
	@Async
	public void sendPush() {
		sendRemind("registrationId", "驗證碼");
	}
	
	/**
	 * 通過極光的註冊編號推送
	 * @param registrationId
	 * @param title
	 */
	private void sendRemind(String registrationId, String title) {
		 
		Builder builder = PushPayload.newBuilder();
		
		builder.setPlatform(Platform.all());
		
		builder.setAudience(Audience.registrationId(registrationId));
		
		builder.setNotification(Notification.newBuilder().setAlert(title).build());
		
		builder.setOptions(Options.newBuilder().setApnsProduction(true).build());
		try {
			PushResult pushResult = jPushClient.sendPush(builder.build());
			log.info("推送成功,misId:("+ pushResult.msg_id +")");
		} catch (APIConnectionException | APIRequestException e) {
			e.printStackTrace();
			log.info("推送失敗~~~,錯誤原因:"+ e);
		}
	}
}

6、ALiYunSmsUtil類

public class ALiYunSmsUtil {

	public static BaseVo<Void> sendPhoneCode(String phone, String code) {
		
		IAcsClient acsClient = getIAcsClient();
		// 組裝請求對象
		SendSmsRequest smsRequest = new SendSmsRequest();
		
		//使用post提交
		smsRequest.setMethod(MethodType.POST);
		//必填:待發送手機號。支持以逗號分隔的形式進行批量調用,批量上限爲1000個手機號碼,批量調用相對於單條調用及時性稍有延遲,驗證碼類型的短信推薦使用單條調用的方式;發送國際/港澳臺消息時,接收號碼格式爲國際區號+號碼,如“85200000000”
		smsRequest.setPhoneNumbers(phone);
		//必填:短信簽名-可在短信控制檯中找到
		smsRequest.setSignName("阿里雲");
		//必填:短信模板-可在短信控制檯中找到,發送國際/港澳臺消息時,請使用國際/港澳臺短信模版
		smsRequest.setTemplateCode("SMS_1500000000");
		//可選:模板中的變量替換JSON串,如模板內容爲"親愛的${name},您的驗證碼爲${code}"時,此處的值爲
		//友情提示:如果JSON中需要帶換行符,請參照標準的JSON協議對換行符的要求,比如短信內容中包含\r\n的情況在JSON中需要表示成\\r\\n,否則會導致JSON在服務端解析失敗
		smsRequest.setTemplateParam("{\"code\":\""+ code +"\"}");
		//可選-上行短信擴展碼(擴展碼字段控制在7位或以下,無特殊需求用戶請忽略此字段)
		//request.setSmsUpExtendCode("90997");
		//可選:outId爲提供給業務方擴展字段,最終在短信回執消息中將此值帶回給調用者
		//smsRequest.setOutId("");
		
		BaseVo<Void> baseVo = new BaseVo<>();
		try {
			SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(smsRequest);
			if (sendSmsResponse == null) {
				baseVo.setCode(2);
				baseVo.setMessage("sendSmsResponse爲空,驗證碼發送失敗");
			} else if (!StringUtils.isEmpty(sendSmsResponse.getCode()) && sendSmsResponse.getCode().equals("OK")) {
				baseVo.setCode(1);
				baseVo.setMessage("驗證碼發送成功!");
			} else {
				baseVo.setCode(2);
				baseVo.setMessage(StringUtils.isEmpty(sendSmsResponse.getMessage()) ? "請稍後重試" : sendSmsResponse.getMessage());
			}
			
		} catch (ClientException e) {
			e.printStackTrace();
			baseVo.setCode(2);
			baseVo.setMessage("調用阿里雲sms發生錯誤");
		}
		return baseVo;
	}
	
	private static IAcsClient getIAcsClient() {
		System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
		System.setProperty("sun.net.client.defaultReadTimeout", "10000");
		//初始化ascClient需要的幾個參數
		final String product = "Dysmsapi";//短信API產品名稱(短信產品名固定,無需修改)
		final String domain = "dysmsapi.aliyuncs.com";//短信API產品域名(接口地址固定,無需修改)
		//替換成你的AK
		final String accessKeyId = "accessKeyId";//你的accessKeyId,參考本文檔步驟2
		final String accessKeySecret = "accessKeySecret";//你的accessKeySecret,參考本文檔步驟2
		//初始化ascClient,暫時不支持多region(請勿修改)
		IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId,
		accessKeySecret);
		DefaultProfile.addEndpoint("cn-hangzhou", product, domain);
		return new DefaultAcsClient(profile);
	}
}

 7、mq監聽sms隊列:

@Log4j
@Component
@RabbitListener(queues="sms")
public class SmsListener {
	
	@Autowired
	private JpushService jpushService;

	@RabbitHandler
	public void sendSms(Map<String,String> map) {
		log.info("發送手機號:" + map.get("phone"));
		log.info("發送手機號:" + map.get("code"));
		BaseVo<Void> baseVo = ALiYunSmsUtil.sendPhoneCode(map.get("phone"), map.get("code"));
		if (baseVo.getCode() != 1) {
			log.info("發送短信驗證碼失敗,失敗原因:" + baseVo.getMessage());
			// 進行推送處理
			jpushService.sendPush();
		}
	}
}

8、配置文件:

server.port=8013

#log日誌信息
logging.level.root=info
logging.path=../logs/info/SmsServer

#rabbit配置
spring.rabbitmq.host=192.168.41.26
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin

#極光推送配置
jpush.master.secret=yourAccessKeySecret
jpush.master.jpushAppKey=yourAccessKeyId

用戶發送短信服務:

1、添加pom依賴

  
<!-- 集成redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- RabbitMQ -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

 2、添加RabbitMQ配置:

# Redis數據庫索引(默認爲0)
spring.redis.database=0
# Redis服務器地址
spring.redis.host=192.168.41.26
# Redis服務器連接端口
spring.redis.port=6379
# Redis服務器連接密碼(默認爲空)
spring.redis.password=shuo456
# 連接超時時間(毫秒)
spring.redis.timeout=20000

#日誌信息
logging.level.root=info
logging.path=../logs/info/serverMonitor

#rabbit配置
spring.rabbitmq.host=192.168.41.26
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin

3、ALiYunSmsService類

@Slf4j
@Service
public class ALiYunSmsService extends BaseServer{

	@Autowired
	private RabbitTemplate rabbitTemplate;
	@Autowired
	private RedisService redisService;
	// 緩存時間
	private long cathTime = 60 * 3;
	
	public void senSms(String phone){
		
		if (StringUtils.isBlank(phone)) {
			return;
		}
		// 1、生成4位短信驗證碼,阿帕奇提供的工具類
		String code = RandomStringUtils.randomNumeric(4);
		log.info(phone+ "收到的驗證碼是:" + code);
		// 2、存入reids數據庫,當用戶輸入驗證碼後,後臺可進行校驗,有效時間爲 3分鐘
		String redisKey = getKey(phone+ "_" +code);
		redisService.setex(redisKey, code, cathTime);
		// 3、將驗證碼和手機號發送到 rebbitMQ中
		Map<String,String> map = new HashMap<>();
		map.put("phone", phone);
		map.put("code", code);
		rabbitTemplate.convertAndSend("sms", map);
	}
}

4、testController,測試接口

@RestController
public class TestController {
	
	@Autowired
	private ALiYunSmsService aLiYunSmsService;

	@RequestMapping("/getUser")
	public String getUser(int i){
		int j = 1/i;
		System.out.println(j);
		aLiYunSmsService.senSms("1300000000");
		return "success";
	}
}

測試:

1、啓動RabbitMQ、短信服務、用戶服務。

2、測試接口

優點

1、mq爲實時監聽訂閱,有任務就立即觸發發送短息。

2、緩解服務器壓力

3、系統解耦合

4、異步調用

5、流量削峯

參考資料:cp026la寫的不錯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章