策略模式实现多方发送验证码

前言:
java语言实现一个简单的策略模式进行多方短信发送的架子,可以在多个第三方进行切换,防止一方突然不可用等突发情况,以阿里云、互亿、创蓝为例。

1.注册第三方用以发送短信,以阿里云为例


在搜索框搜索找到短信服务控制台,这里会有快速教程,按步骤做即可,我这里是开通完成的样子,大概步骤如下,不清楚的可以百度教程。
1.登录阿里云账号。
2.搜索框搜索短信服务
3.开通短信服务并进入短信服务控制台,点击左边的栏目的国内消息
4.添加签名,等待审核
5.添加模版,等待审核
6.点击套餐包咨询栏目,购买一定的短信套餐
7.获取Access Key,需要将鼠标移动到右上角头像位置,不需要点击,显示Access Key管理并点击
8.进入管理台,点击创建Access Key即可获得

2.application.yml配置

2.1.signName需和这里名称保持一致

在这里插入图片描述

2.2.templateCode需和这里模板code保持一致

在这里插入图片描述

2.3.accessKey和secret从这里获取

没有的话就先创建
在这里插入图片描述
在这里插入图片描述
获取到各方配置文件需要的密钥后,在对应位置进行配置,如果后续某个第三方发送失败,一定检查配置文件是否正确。

lyy:
  sms:
#      默认启用
    enable: huyi 
    aliyun:
#      签名
      signName: 1111
#      模板CODE
      templateCode: 11111
#      个人accessKey
      accessKey: 11111
#      个人secret
      secret: 11111
    huyi:
      signName: 
      templateCode: 
      accessKey: 
      secret: 
    chuanglan:
      signName: 
      templateCode: 
      accessKey: 
      secret: 

3.创建各方实体类

prefix 值注意和配置文件层级保持一致

3.1.互亿

@Data
@Component
@ConfigurationProperties(prefix = "lyy.sms.huyi")
public class AliyunProperties {
    private String signName;
    private String templateCode;
    private String accessKey;
    private String secret;
}

3.2.创蓝

@Data
@Component
@ConfigurationProperties(prefix = "lyy.sms.chuanglan")
public class ChuanglanProperties {
    private String signName;
    private String templateCode;
    private String accessKey;
    private String secret;
}

3.3.阿里云

@Data
@Component
@ConfigurationProperties(prefix = "lyy.sms.aliyun")
public class HuyiProperties {
    private String signName;
    private String templateCode;
    private String accessKey;
    private String secret;
}

4.自定义一个注解

这个注解的是为了给各方实现类起一个别名,后续用这个别名与配置文件中enable属性值对应。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SmsTypeName {
    String value();
}

5.发送短信方法接口和实现类

5.1.接口

发送短信的方法,参数一:接收方的电话号码;参数二:发送的验证码

public interface TemplateService {
    void sendMsg(String mobile, String code);
}

5.2.实现类

具体的发送代码,百度都有现成的,或者阅读官方文档。
这里使用@ConfigurationProperties注解,在启动时,springBoot会自动注入属性值,
然后用@Autowired注解自动装配对应的第三方的实体类。
@SmsTypeName(“aliyun”),别名需与配置文件的一致。不然影响到第6步策略类的加载存储的key与配置文件的enable属性对应不上,就无法获取到对应的实现类。
这里第三方的实现类的代码都是使用的阿里云的,只需要验证是否能通过配置文件改变发送短信具体的实现类即可,大家也可以替换为对应第三方的代码。

5.2.1.阿里云
@Component
@SmsTypeName("aliyun")
public class AliyunTemplate implements TemplateService {

    @Autowired
    private AliyunProperties properties;

    @Override
    public void sendMsg(String mobile, String code) {
        try {
            Config config = new Config()
                    // 必填,您的 AccessKey ID
                    .setAccessKeyId(properties.getAccessKey())
                    // 必填,您的 AccessKey Secret
                    .setAccessKeySecret(properties.getSecret());
            // 访问的域名
            config.endpoint = "dysmsapi.aliyuncs.com";
            Client client = new Client(config);
            SendSmsRequest sendSmsRequest = new SendSmsRequest()
                    .setPhoneNumbers(mobile)
                    .setSignName(properties.getSignName())
                    .setTemplateCode(properties.getTemplateCode())
                    .setTemplateParam("{\"code\":\"" + code + "\"}");
            // 复制代码运行请自行打印 API 的返回值
            SendSmsResponse response = client.sendSms(sendSmsRequest);
            if ("OK".equals(response.getBody().getCode())) {
                System.out.println("aliyun验证码发送成功");
            }
            System.out.println(response.getBody().getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
5.2.2.创蓝
@Component
@SmsTypeName("chuanglan")
public class ChuanglanTemplate implements TemplateService {

    @Autowired
    private ChuanglanProperties properties;
    @Override
    public void sendMsg(String mobile, String code) {
        try {
            Config config = new Config()
                    // 必填,您的 AccessKey ID
                    .setAccessKeyId(properties.getAccessKey())
                    // 必填,您的 AccessKey Secret
                    .setAccessKeySecret(properties.getSecret());
            // 访问的域名
            config.endpoint = "dysmsapi.aliyuncs.com";
            Client client = new Client(config);
            SendSmsRequest sendSmsRequest = new SendSmsRequest()
                    .setPhoneNumbers(mobile)
                    .setSignName(properties.getSignName())
                    .setTemplateCode(properties.getTemplateCode())
                    .setTemplateParam("{\"code\":\"" + code + "\"}");
            // 复制代码运行请自行打印 API 的返回值
            SendSmsResponse response = client.sendSms(sendSmsRequest);
            if ("OK".equals(response.getBody().getCode())) {
                System.out.println("chuanglan验证码发送成功");
            }
            System.out.println(response.getBody().getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
5.2.3.互亿
@Component
@SmsTypeName("huyi")
public class HuyiTemplate implements TemplateService {
    @Autowired
    private HuyiProperties properties;

    @Override
    public void sendMsg(String mobile, String code) {
        try {
            Config config = new Config()
                    // 必填,您的 AccessKey ID
                    .setAccessKeyId(properties.getAccessKey())
                    // 必填,您的 AccessKey Secret
                    .setAccessKeySecret(properties.getSecret());
            // 访问的域名
            config.endpoint = "dysmsapi.aliyuncs.com";
            Client client = new Client(config);
            SendSmsRequest sendSmsRequest = new SendSmsRequest()
                    .setPhoneNumbers(mobile)
                    .setSignName(properties.getSignName())
                    .setTemplateCode(properties.getTemplateCode())
                    .setTemplateParam("{\"code\":\"" + code + "\"}");
            // 复制代码运行请自行打印 API 的返回值
            SendSmsResponse response = client.sendSms(sendSmsRequest);
            if ("OK".equals(response.getBody().getCode())) {
                System.out.println("huyi验证码发送成功");
            }
            System.out.println(response.getBody().getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6.策略类

启动时加载,存储带有SmsTypeName注解的类,以SmsTypeName的值为key,以对应的实现类为value存入一个map并提供一个get方法根据key获取value。

@Component
public class SmsTypeHandler implements ApplicationContextAware {
    private static HashMap<String, TemplateService> TEMPLATE_MAP = new HashMap<>();

    /**
     * 启动时加载发送短信策略类
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        applicationContext.getBeansOfType(TemplateService.class).values().forEach(temp -> {
            String type = temp.getClass().getAnnotation(SmsTypeName.class).value();
            TEMPLATE_MAP.put(type, temp);
        });
    }

    public static TemplateService getTemplateByType(String type) {
        TemplateService templateService = TEMPLATE_MAP.get(type);
        return templateService;
    }
}

7.测试类

获取配置文件enable的属性值,然后调用SmsTypeHandler类的getTemplateByType方法即可。110换成自己的手机号码,检查有没有收到自己设置的验证码即可。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class TemplateTest {
    @Autowired
    private SmsTypeHandler smsTypeHandler;
    @Value("${tanhua.sms.enable}")
    private String smsType;

    //阿里云发短信测试
    @Test
    public void testSendSms() {
        smsTypeHandler.getTemplateByType(smsType).sendMsg("110", "123456");
    }
}

这是一个简单的架子,大家可以尽情扩展。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值