阿里大于发送短信
阿里大于短信服務(wù)
demo
注冊(cè)頁(yè)面上有短信發(fā)送的按鈕,當(dāng)用戶點(diǎn)擊發(fā)送短信,我們需要生成驗(yàn)證碼,發(fā)送給用戶。我們將使用阿里提供的阿里大于來(lái)實(shí)現(xiàn)短信發(fā)送。
?
創(chuàng)建短信微服務(wù)
因?yàn)橄到y(tǒng)中不止注冊(cè)一個(gè)地方需要短信發(fā)送,因此我們將短信發(fā)送抽取為微服務(wù):learn-sms-service,凡是需要的地方都可以使用。
另外,因?yàn)槎绦虐l(fā)送API調(diào)用時(shí)長(zhǎng)的不確定性,為了提高程序的響應(yīng)速度,短信發(fā)送我們都將采用異步發(fā)送方式,即:
-
短信服務(wù)監(jiān)聽(tīng)MQ消息,收到消息后發(fā)送短信。
-
其它服務(wù)要發(fā)送短信時(shí),通過(guò)MQ通知短信微服務(wù)。
創(chuàng)建module
pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>learn</artifactId><groupId>com.learn.parent</groupId><version>1.0.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.learn.sms</groupId><artifactId>learn-sms-service</artifactId><version>1.0.0-SNAPSHOT</version><dependencies><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.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>3.3.1</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-dysmsapi</artifactId><version>1.0.0</version></dependency></dependencies> </project>編寫啟動(dòng)類
@SpringBootApplication public class SmsApplication {public static void main(String[] args) {SpringApplication.run(SmsApplication.class, args);} }編寫application.yml
server:port: 8086 spring:application:name: sms-servicerabbitmq:host: 192.168.56.101username: learnpassword: learnvirtual-host: /learn編寫短信工具類
項(xiàng)目結(jié)構(gòu):
屬性抽取
我們首先把一些常量抽取到application.yml中:
learn:sms:accessKeyId: JWffwFJIwada # 你自己的accessKeyIdaccessKeySecret: aySRliswq8fe7rF9gQyy1Izz4MQ # 你自己的AccessKeySecretsignName: 碧溪商城 # 簽名名稱verifyCodeTemplate: SMS_133976814 # 模板名稱然后注入到屬性類中:
@ConfigurationProperties(prefix = "learn.sms") public class SmsProperties {String accessKeyId;String accessKeySecret;String signName;String verifyCodeTemplate;public String getAccessKeyId() {return accessKeyId;}public void setAccessKeyId(String accessKeyId) {this.accessKeyId = accessKeyId;}public String getAccessKeySecret() {return accessKeySecret;}public void setAccessKeySecret(String accessKeySecret) {this.accessKeySecret = accessKeySecret;}public String getSignName() {return signName;}public void setSignName(String signName) {this.signName = signName;}public String getVerifyCodeTemplate() {return verifyCodeTemplate;}public void setVerifyCodeTemplate(String verifyCodeTemplate) {this.verifyCodeTemplate = verifyCodeTemplate;} }工具類
我們把阿里提供的demo進(jìn)行簡(jiǎn)化和抽取,封裝一個(gè)工具類:
@Component @EnableConfigurationProperties(SmsProperties.class) public class SmsUtils {@Autowiredprivate SmsProperties prop;//產(chǎn)品名稱:云通信短信API產(chǎn)品,開(kāi)發(fā)者無(wú)需替換static final String product = "Dysmsapi";//產(chǎn)品域名,開(kāi)發(fā)者無(wú)需替換static final String domain = "dysmsapi.aliyuncs.com";static final Logger logger = LoggerFactory.getLogger(SmsUtils.class);public SendSmsResponse sendSms(String phone, String code, String signName, String template) throws ClientException {//可自助調(diào)整超時(shí)時(shí)間System.setProperty("sun.net.client.defaultConnectTimeout", "10000");System.setProperty("sun.net.client.defaultReadTimeout", "10000");//初始化acsClient,暫不支持region化IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou",prop.getAccessKeyId(), prop.getAccessKeySecret());DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);IAcsClient acsClient = new DefaultAcsClient(profile);//組裝請(qǐng)求對(duì)象-具體描述見(jiàn)控制臺(tái)-文檔部分內(nèi)容SendSmsRequest request = new SendSmsRequest();request.setMethod(MethodType.POST);//必填:待發(fā)送手機(jī)號(hào)request.setPhoneNumbers(phone);//必填:短信簽名-可在短信控制臺(tái)中找到request.setSignName(signName);//必填:短信模板-可在短信控制臺(tái)中找到request.setTemplateCode(template);//可選:模板中的變量替換JSON串,如模板內(nèi)容為"親愛(ài)的${name},您的驗(yàn)證碼為${code}"時(shí),此處的值為request.setTemplateParam("{\"code\":\"" + code + "\"}");//選填-上行短信擴(kuò)展碼(無(wú)特殊需求用戶請(qǐng)忽略此字段)//request.setSmsUpExtendCode("90997");//可選:outId為提供給業(yè)務(wù)方擴(kuò)展字段,最終在短信回執(zhí)消息中將此值帶回給調(diào)用者request.setOutId("123456");//hint 此處可能會(huì)拋出異常,注意catchSendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);logger.info("發(fā)送短信狀態(tài):{}", sendSmsResponse.getCode());logger.info("發(fā)送短信消息:{}", sendSmsResponse.getMessage());return sendSmsResponse;} }編寫消息監(jiān)聽(tīng)器
接下來(lái),編寫消息監(jiān)聽(tīng)器,當(dāng)接收到消息后,我們發(fā)送短信。
@Component @EnableConfigurationProperties(SmsProperties.class) public class SmsListener {@Autowiredprivate SmsUtils smsUtils;@Autowiredprivate SmsProperties prop;@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "learn.sms.queue", durable = "true"),exchange = @Exchange(value = "learn.sms.exchange", ignoreDeclarationExceptions = "true"),key = {"sms.verify.code"}))public void listenSms(Map<String, String> msg) throws Exception {if (msg == null || msg.size() <= 0) {// 放棄處理return;}String phone = msg.get("phone");String code = msg.get("code");if (StringUtils.isBlank(phone) || StringUtils.isBlank(code)) {// 放棄處理return;}// 發(fā)送消息SendSmsResponse resp = this.smsUtils.sendSms(phone, code, prop.getSignName(),prop.getVerifyCodeTemplate());} }我們注意到,消息體是一個(gè)Map,里面有兩個(gè)屬性:
-
phone:電話號(hào)碼
-
code:短信驗(yàn)證碼
?
?
總結(jié)