Spring boot简单的接入阿里短信接口

准备工作如下:

  • 我们需要在阿里云上开通短信服务,这里可以买资源包,也可以自己充值;
  • 创建短信验证签名,签名需要阿里后台审核,一般2小时左右;
  • 创建短信模板;
  • 在用户头像下菜单,(在AccessKey管理里面创建用户,给他短信的权限获取里面的账户和key) 创建阿里云的授权用户;

我们需要的数据:

名称 释义
accessKeyId 创建用户的id
accessKeySecret 创建用户的秘钥
signName 短信签名名称
templateCode 短信模板的id

在工程中导入阿里短信的包,这里注意我是用的升级版的SDK 2017-05-25 参考链接点击进入
按照文档要求导入jar包:

<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>tea-openapi</artifactId>
  <version>0.0.19</version>
</dependency>
<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>dysmsapi20170525</artifactId>
  <version>2.0.6</version>
</dependency>

我们先看看官方文档示例代码: 点击跳转示例

这是官方示例代码:

package com.aliyun.sample;

import com.aliyun.tea.*;
import com.aliyun.dysmsapi20170525.*;
import com.aliyun.dysmsapi20170525.models.*;
import com.aliyun.teaopenapi.*;
import com.aliyun.teaopenapi.models.*;

public class Sample {

    /**
     * 使用AK&SK初始化账号Client
     * @param accessKeyId
     * @param accessKeySecret
     * @return Client
     * @throws Exception
     */
    public static com.aliyun.dysmsapi20170525.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
        Config config = new Config()
                // 您的AccessKey ID
                .setAccessKeyId(accessKeyId)
                // 您的AccessKey Secret
                .setAccessKeySecret(accessKeySecret);
        // 访问的域名
        config.endpoint = "dysmsapi.aliyuncs.com";
        return new com.aliyun.dysmsapi20170525.Client(config);
    }

    public static void main(String[] args_) throws Exception {
        java.util.List<String> args = java.util.Arrays.asList(args_);
        com.aliyun.dysmsapi20170525.Client client = Sample.createClient("accessKeyId", "accessKeySecret");
        SendSmsRequest sendSmsRequest = new SendSmsRequest()
                .setPhoneNumbers("17607146571")
                .setSignName("code")
                .setTemplateCode("sms_12675377891")
                .setTemplateParam("{'code':'123456'}");
        // 复制代码运行请自行打印 API 的返回值
        client.sendSms(sendSmsRequest);
    }
}

我们要做的就是将官方的代码做些更改,更贴合实际的业务开发场景:

  • 我们先在配置文件中定义我们要发短信的固定参数,在yml中进行如下配置;
dysms:
  accessKeyId: LTAIWjSAN0910892
  accessKeySecret: pYtZUs4CCZ57hww19277637OICJSN
  signName: 大威天龙  #短信签名
  templateCode: SMS_168581995 #这个模板可以有多个,可以根据项目需求定义枚举

这里注意项目中可能会有很多的短信模板,这些可以配置多个,另外短信签名是有可能是中文,用properties配置文件时可能会乱码(这个跟spring的默认加载编码有关系),为了方便推荐使用yml文件配置;

  • 我们写个配置文件类,初始化一下这个Client
import com.aliyun.teaopenapi.models.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Auther: MR.rp
 * @Date: 2021/8/3 14:31
 * @Description:
 */

@Configuration
public class DysmsConfig {

    @Value(value = "${dysms.accessKeyId}")
    private  String   accessKeyId;

    @Value(value = "${dysms.accessKeySecret}")
    private  String  accessKeySecret;

    @Bean
    public com.aliyun.dysmsapi20170525.Client careateClient() throws Exception {
        Config config = new Config()
                .setAccessKeyId(accessKeyId)
                .setAccessKeySecret(accessKeySecret);
        // 访问的域名
        config.endpoint = "dysmsapi.aliyuncs.com";
        return new com.aliyun.dysmsapi20170525.Client(config);
    }
}
  • 编写短信调用工具类
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * @Auther: MR.rp
 * @Date: 2021/8/3 14:37
 * @Description:
 */

@Component
@Slf4j
public  class DysmsUtil {
    
    private static Client client;
    private static  String  signName; //签名
    public static  String  templateCode;// 短信验证码模板id
    
    @Value("${dysms.templateCode}")
    public void setMsgCode(String templateCode) {
        DysmsUtil.templateCode= templateCode;
    }
    
    @Autowired
    public DysmsUtil(Client client){
        this.client = client;
    }


    @Value("${dysms.signName}")
    public void setSIGN(String signName) {
        DysmsUtil.signName= signName;
    }

    
    /**
     * 单条手机发送信息
     * @param phoneNums
     * @param smsModelId
     * @param template
     */
    public static void  sendMsg(String phoneNums, String templateCode, String  template){
       //这里为了测试只写单条手机号码的校验是否合法,在开发中如果是多个手机号可以先自己校验再传参
       if(!phoneNums.matches("^1(3\\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$"))
            log.warn("============ 手机号:"+phoneNums+"不合法,发送失败 ======");
            return;
        }
        SendSmsRequest sendSmsRequest = new SendSmsRequest()
                .setPhoneNumbers(phoneNums)
                .setSignName(signName)  //短信签名名称
                .setTemplateCode(templateCode) //短信模板ID
                .setTemplateParam(template); //变量值
        try {
            SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
            SendSmsResponseBody  sendBody = sendSmsResponse.getBody();

            if(sendBody.getMessage().equals("OK")){
                log.info("========== 给:"+phoneNums+"发送短信["+template+"]成功!!! ==========");
            }
            
            //下面是查询信息的结果集,因为短信本身会有一定的延迟,所有在查询的时候可能会查不到或者让线程睡眠几秒再查询,这里只是贴出查询代码供大家参考
            String datetime = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String bizId = sendBody.bizId;
            QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest()
                    .setPhoneNumber(phoneNums)
                    .setSendDate(datetime)
                    .setBizId(bizId)
                    .setPageSize(10L)  //分页
                    .setCurrentPage(1L);
            QuerySendDetailsResponseBody body = client.querySendDetails(querySendDetailsRequest).getBody();
            ObjectMapper objectMapper = new ObjectMapper();
            String msg = objectMapper.writeValueAsString(body);
            log.info("返回的body信息:"+msg);
            String message = objectMapper.writeValueAsString(sendBody);
            log.info("发送返回信息详情:"+message);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage(),e);
        }
    }

    /**
     * 获取短信验证码
     * @return 验证码
     */
    public static String getCode() {
        String code = null;
        code = (int) ((Math.random() * 9 + 1) * 100000) + "";
        log.info("验证码为["+code+"]");
        return code;
    }
}

我们在业务中调用测试一下:

    @GetMapping("/getCode")
    @ApiOperation(value = "获取验证码",notes = "获取验证码")
    @Transactional
    public ServerResponseVO  getCode(@RequestParam("userTel")@ApiParam("手机号") String userTel,HttpSession session){
        boolean matches = userTel.matches("^1(3\\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$");
        if(!matches){
            return  ServerResponseVO.error("手机号码有误");
        }
        String code = DysmsUtil.getCode();
//        session.setAttribute(userTel,code);
//        session.setMaxInactiveInterval(300);
        redisTemplate.opsForValue().set(userTel,code,300, TimeUnit.SECONDS);// redis存储
        String  jsonCode  = "{'code':'"+code+"'}";
        DysmsUtil.sendMsg(userTel,DysmsUtil.msgCode,jsonCode);
        log.info("手机号:"+userTel +"获取验证码成功:["+code+"]" );
        return  ServerResponseVO.success("获取验证码成功");
    }

看下日志:
在这里插入图片描述
怎么样,很简单吧?

  • 在多种短信签名的情况下我们可以多配置几个短信的配置名称,在工具类中注入就可以了,你也可以定义为枚举,当调用时传入当前的枚举或注入的属性,就可以实现发送对应的短信了,这里也要注意传入占位参数时,官方支持的是json格式的哦,笔者之前在这里踩到了,一直发送不成功;

有兴趣小伙伴可以自己测试一下哦


版权声明:本文为qq_44035485原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。