Skip to content
🔴🟠🟡🟢🔵🟣🟤⚫⚪

(二十四)集成sms短信服务

基础项目地址:

https://gitee.com/springzb/admin-boot

一、编码实现

短信模块所在路径 cn.mesmile.admin.common.sms

SmsProperties 配置字段属性

java
package cn.mesmile.admin.common.sms.config;

import cn.mesmile.admin.common.sms.domain.SmsPlatformTypeEnum;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author zb
 * @Description
 */
@Data
@Component
@ConfigurationProperties(prefix = "sms")
public class SmsProperties {
    /**
     * 是否开启短信模块
     */
    private Boolean enabled = Boolean.FALSE;
    /**
     * 短信平台类型
     */
    private SmsPlatformTypeEnum platformType  = SmsPlatformTypeEnum.ALI_YUN;
    /**
     * 短信模板id
     */
    private String templateId;
    /**
     * 地域id
     */
    private String regionId = "cn-hangzhou";
    /**
     * accessKey
     */
    private String accessKey;
    /**
     * secretKey
     */
    private String secretKey;
    /**
     * 短信签名
     */
    private String signName;

}

SmsConfiguration 配置类

java
package cn.mesmile.admin.common.sms.config;

import cn.mesmile.admin.common.exceptions.ServiceException;
import cn.mesmile.admin.common.sms.AliSmsTemplate;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.teaopenapi.models.Config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author zb
 * @Description
 */
@EnableConfigurationProperties({SmsProperties.class})
@Configuration
@ConditionalOnProperty(value = {"sms.enabled"}, havingValue = "true")
public class SmsConfiguration {

    @Bean
    @ConditionalOnProperty(value = {"sms.platform-type"}, havingValue = "ali_yun")
    public AliSmsTemplate getAliSmsTemplate(SmsProperties smsProperties) {
        Config config = new Config()
                // 您的 AccessKey ID
                .setAccessKeyId(smsProperties.getAccessKey())
                // 您的 AccessKey Secret
                .setAccessKeySecret(smsProperties.getSecretKey());
        config.endpoint = "dysmsapi.aliyuncs.com";
        com.aliyun.dysmsapi20170525.Client client;
        try {
            client = new Client(config);
        }catch (Exception e){
            throw new ServiceException("创建阿里云短信客户端失败", e);
        }
        return new AliSmsTemplate(smsProperties, client);
    }

//    @Bean
//    @ConditionalOnProperty(value = {"sms.platform-type"}, havingValue = "tencent_yun")
//    public TencentSmsTemplate tencentSmsTemplate(SmsProperties smsProperties) {
//        SmsMultiSender smsSender = new SmsMultiSender(smsProperties.getAccessKey(), smsProperties.getSecretKey());
//        return new TencentSmsTemplate(smsProperties, smsSender);
//    }


}

SmsTemplate 顶层短信接口

java
package cn.mesmile.admin.common.sms;

import cn.mesmile.admin.common.sms.domain.SmsCode;
import cn.mesmile.admin.common.sms.domain.SmsData;
import cn.mesmile.admin.common.sms.domain.SmsResponse;

import java.util.Collection;

/**
 * @author zb
 * @Description
 */
public interface SmsTemplate {

    /**
     * 发送单条消息
     * @param smsData 短信内容匹配
     * @param phones 电话号码
     * @return 发送结果
     */
    SmsResponse sendSingleMessage(SmsData smsData, String phones);
    /**
     * 批量发送消息
     * @param smsData 短信内容匹配
     * @param phones 多个电话号码
     * @return 发送结果
     */
    SmsResponse sendMessage(SmsData smsData, Collection<String> phones);

    /**
     *  发送验证码
     * @param smsData  短信内容匹配
     * @param phone 电话号码
     * @return 发送结果
     */
    SmsCode sendValidate(SmsData smsData, String phone);

    /**
     * 校验消息
     * @param smsCode
     * @return
     */
    boolean validateMessage(SmsCode smsCode);
}

AliSmsTemplate 具体实现模板

java
package cn.mesmile.admin.common.sms;

import cn.mesmile.admin.common.exceptions.ServiceException;
import cn.mesmile.admin.common.result.ResultCode;
import cn.mesmile.admin.common.sms.config.SmsProperties;
import cn.mesmile.admin.common.sms.domain.SmsCode;
import cn.mesmile.admin.common.sms.domain.SmsData;
import cn.mesmile.admin.common.sms.domain.SmsResponse;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teautil.Common;
import com.aliyun.teautil.models.RuntimeOptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;

import java.util.Collection;

/**
 * @author zb
 * @Description
 */
@Slf4j
public class AliSmsTemplate implements SmsTemplate {

    private final SmsProperties smsProperties;
    private final com.aliyun.dysmsapi20170525.Client aliSmsClient;

    @Override
    public SmsResponse sendSingleMessage(SmsData smsData, String phones) {
        SendSmsRequest sendSmsRequest = new SendSmsRequest();
        sendSmsRequest.setSignName(smsProperties.getSignName());
        sendSmsRequest.setTemplateCode(smsProperties.getTemplateId());
        sendSmsRequest.setPhoneNumbers(phones);
        sendSmsRequest.setTemplateParam(JSONObject.toJSONString(smsData.getParams()));
        RuntimeOptions runtime = new RuntimeOptions();
        try {

            SendSmsResponse sendSmsResponse = aliSmsClient.sendSmsWithOptions(sendSmsRequest, runtime);
            return new SmsResponse(sendSmsResponse.getStatusCode() == HttpStatus.OK.value(),
                    HttpStatus.OK.value(), JSONObject.toJSONString(sendSmsResponse.getBody()));
        } catch (TeaException error) {
            String msg = Common.assertAsString(error.message);
            throw new ServiceException(ResultCode.FAILURE, msg, error);
        } catch (Exception e) {
            TeaException error = new TeaException(e.getMessage(), e);
            String msg = Common.assertAsString(error.message);
            throw new ServiceException(ResultCode.FAILURE, msg, error);
        }
    }

    @Override
    public SmsResponse sendMessage(SmsData smsData, Collection<String> phones) {
      return this.sendSingleMessage(smsData, String.join(",", phones));
    }

    @Override
    public SmsCode sendValidate(SmsData smsData, String phone) {
        return null;
//        SmsCode smsCode = new SmsCode();
//        boolean temp = this.sendSingle(smsData, phone);
//        if (temp && StringUtil.isNotBlank(smsData.getKey())) {
//            String id = StringUtil.randomUUID();
//            String value = (String)smsData.getParams().get(smsData.getKey());
//            this.redis.setEx("admin:sms::captcha:" + phone + ":" + id, value, Duration.ofMinutes(30L));
//            smsCode.setId(id).setValue(value);
//        } else {
//            smsCode.setSuccess(Boolean.FALSE);
//        }
//        return smsCode;
    }

    @Override
    public boolean validateMessage(SmsCode smsCode) {
        return true;
//        String id = smsCode.getId();
//        String value = smsCode.getValue();
//        String cache = (String)this.redis.get("admin:sms::captcha:" + smsCode.getPhone() + ":" + id);
//        if (StringUtil.isNotBlank(value) && StringUtil.equalsIgnoreCase(cache, value)) {
//            this.redis.del("admin:sms::captcha:" + id);
//            return true;
//        } else {
//            return false;
//        }
    }

    public AliSmsTemplate(final SmsProperties smsProperties, final com.aliyun.dysmsapi20170525.Client aliSmsClient) {
        this.smsProperties = smsProperties;
        this.aliSmsClient = aliSmsClient;
    }

}

引入maven依赖

xml
<!--AliSms 具体的短信平台,引入的依赖不同-->
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>dysmsapi20170525</artifactId>
    <version>2.0.16</version>
</dependency>