Spring Boot 集成阿里云发送短信

625 阅读4分钟

起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第29天,点击查看活动详情

前言

项目中经常会用到短信发送功能,例如用户登录需要发送验证码,通过验证码登录成功。本文将讲解Spring Boot如何发送短信,短信平台采用的阿里云平台为例。

环境准备

登录阿里云开通短信服务

  • 登录阿里云在项目主页面,单击自有品牌App名称,进入自有品牌页面。
  • 单击验证码短信服务对应的开通并授权服务。
  • 在弹出的对话框中,点击授权服务
  • 弹出的页面中点击同意授权即可

创建短信模板

图片.png

按照要求选择模板类型、填写模板名称、模板内容、申请说明即可

集成短信

pom.xml文件中添加阿里云JAR包

   <dependency>
      <groupId>com.aliyun</groupId>
      <artifactId>aliyun-java-sdk-core</artifactId>
      <version>4.0.3</version>
   </dependency>

application.yml添加阿里云配置

config:
  sms:
    # 是否启用短信发送
    enable: true
    # 是否为测试短信
    test: false
    # 短信模板
    template:
      0: SMS_184220772
    # 测试短信接收账号
    test-recv-phone: 13612345678
    accessKeyId: accessKeyId
    regionId: regionId
    secret: secret
    request:
      regionId: regionId
      domain: domain
      action: SendSms
      version: 2017-05-25
      signName: 自定义签名

短信配置类

@Component
@ConfigurationProperties(prefix="config.sms")
public class SmsConfig
{
    private String regionId;
    private String accessKeyId;
    private String secret;
    private Request request;
    private boolean enable;
    private boolean test;
    private String testRecvPhone;
    
    public static class Request
    {
        private String domain;
        private String version;
        private String action;
        private String regionId;
        private String signName;
     }
     
     // 省略get、set方法
 }

短信核心实现类

public SmsResponse sendSms(SmsParameter smsParameter)
    {
        logger.info("sendSms param:",JSON.toJSONString(smsParameter));
        String phones = smsParameter.getPhoneNumbers();
        if(StringUtils.isEmpty(phones))
        {
            logger.warn("sendSms phone is empty");
             throw new RuntimeException("短信发送失败,手机号码为空");
        }
        phones = phones.trim();
        
        //添加阿里云相关的参数
        DefaultProfile profile = DefaultProfile.getProfile(smsConfig.getRegionId(), smsConfig.getAccessKeyId(), smsConfig.getSecret());
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain(smsConfig.getRequest().getDomain());
        request.setVersion(smsConfig.getRequest().getVersion());
        // 
        request.setAction(smsConfig.getRequest().getAction());
        request.putQueryParameter("RegionId", smsConfig.getRequest().getRegionId());
        // 如果是测试模式,那么发送给测试手机号
        String phone = smsConfig.isTest() ? smsConfig.getTestRecvPhone() : smsParameter.getPhoneNumbers();
        
        request.putQueryParameter("PhoneNumbers", phone);
        //签名
        request.putQueryParameter("SignName", smsParameter.getSignName());
        //模板编号
        request.putQueryParameter("TemplateCode", smsParameter.getTemplateCode());
        //模板参数
        request.putQueryParameter("TemplateParam", smsParameter.getTemplateParam());
        logger.info("真实接收短信手机:{};是否发送短信:{}",phone,smsConfig.isEnable());
        logger.trace("发送短信内容:{}",request);
        
        // 启用了短信发送,才进行发送短信
        if(smsConfig.isEnable())
        {
            try
            {
               CommonResponse response = client.getCommonResponse(request);
               String result = response.getData();
               logger.info("发送短信结果:{}",result);
               // 尝试解析结果,根据结果判断是否发送成功
               SmsResponse smsResponse= JSON.parseObject(result,SmsResponse.class);
               return smsResponse;
            }
            catch (Exception e)
            {
                logger.error("send sms error",e);
                throw new RuntimeException("短信发送失败",e);
            }
        }
        else
        {
           logger.error("send sms config not enable"); 
        }
        return null;
    }

说明:根据文档设置阿里云相关的参数即可。

短信测试

@RequestMapping("/sendSms")
    public String sendSms()
    {
        //模板编号
        String templateCode ="SMS_187640334";
        //签名
        String signName = smsConfig.getRequest().getSignName();
        
        //发送电话号码
        String phoneNumbers ="13612345678";
        //随机生成验证码
        int code=(int)(Math.random()*1000000);
        String templateParam="{\"code\":\"" + code + "\"}";
        SmsParameter  smsParameter =new SmsParameter();
        smsParameter.setTemplateCode(templateCode);
        smsParameter.setTemplateParam(templateParam);
        smsParameter.setPhoneNumbers(phoneNumbers);
        smsParameter.setSignName(signName);
        
        SmsResponse response =smsService.sendSms(smsParameter);
        if("code".equals(response.getCode()))
        {
            return "发送短信成功";
        }
        else
        {
            return "发送短信失败";
        }
    }

注意

发送短信需要注意短信模板中的参数与其对应,且短信模板的参数采用的是键值对形式。测试采用的是短信验证码的模板只需要传入code值即可。

测试结果

[http-nio-9090-exec-1] INFO  [] c.s.sms.service.SmsServiceImpl - 发送短信结果:{"RequestId":"4C95CC59-7632-521E-B559-FD3E5F9F7D5C","Message":"OK","BizId":"902804351291637542^0","Code":"OK"}

说明:发送短信成功的Code为OK说明短信发送成功。

其他特性

批量发送短信

发送短信参数的PhoneNumbers可以支持多个短信发送,使用逗号隔开,可以支持批量上线为1000个。

 //批量发送
  String phoneNumbers ="13612345678,1345678901";

短信并发控制,设置短信发送频率

方案1:阿里云配置短信发送发送频率

图片.png

方案2:通过Redis限制发送的频率

关于Redis限制发送的频率的实现后续Redis的文章将详细讲解。

总结

本文讲解了Spring Boot发送短信,实际的项目中我们需要将短信和邮件进行统一封装成功独立服务,提供对应的API接口给其他服务调用即可。