【Java】阿里云短信发送功能实现

前言

在移动端,我们除了使用账号密码、第三方社交平台账号(例如:微信、QQ、微博等)这几种登录方式以外,也会通过手机短信验证码的方式来做登录。
博主最近正在做移动端的手机短信验证登录。原本为了简单起见,选用的是某个不知名科技公司的短信服务,但是收费贵,服务也不太稳定等一系列问题的出现,导致博主开始另寻他路。

短信服务选择

博主挑选了几家大公司的短信服务,以下为各服务官网的产品价格:

在参考了各个服务的费用以及公司系统用户量等具体情况以后,博主最终选择了 阿里云短信服务

阿里云短信配置

在我们实现 阿里云短信发送API 之前,其实在阿里云平台上还有一系列的操作需要我们去申请、配置等(例如:开通短信服务、获取AccessKey、创建短信的签名和模板等等)。但是这些并不是本文的重点,所以博主这里不做详细的叙述。
大家可以自行参考阿里云提供的 短信服务文档使用指引,根据步骤操作。

API所需配置提取

假设上述配置操作大家已完成,博主这里用公司已注册好的模板举个例子。我们需要提取记录的配置有以下几种:

  • AccessKeyID和AccessKeySecret: 关于这个内容大家自行参考官方文档 如何获取AccessKeyID和AccessKeySecret,步骤写的也比较详细,博主在这里就不做过多的叙述。
  • 签名名称: 打开阿里短信服务管理控制台,按顺序点开:国内消息->签名管理,我这里选用阿里赠送的签名 阿里云短信测试专用
图1 获取签名名称
  • 模板CODE和内容: 打开阿里短信服务管理控制台,按顺序点开:国内消息->模板管理->点击对应模板操作中的详情,我这里选用阿里赠送的 身份验证验证码 模板。
图2 获取模板CODE和内容

对以上的内容先做记录,因为后续在代码中我们相应会用到。

代码实现

基本的工作已经做完了,下面我们来看下具体代码的实现

1.添加依赖

	<!-- 阿里云短信服务sdk -->
	<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.1.0</version>
	</dependency>

2.阿里云短信构造类

博主这里采用链式的写法,代码中的accessKeyIdaccessKeySecret 需要替换成我们从云平台提取的对应值。

/**
 * 阿里云短信构造类
 * Created by Hilox on 2018/11/22 0022.
 */
public class AliSmsBuilder implements Serializable {

    private static final long serialVersionUID = -8277819898310935813L;

    /**
     * 阿里云短信服务accessKeyId
     */
    private String accessKeyId;

    /**
     * 阿里云短信服务accessKeySecret
     */
    private String accessKeySecret;

    /**
     * 必填:待发送手机号
     */
    private String phoneNum;

    /**
     * 必填:短信签名-可在短信控制台中找到
     */
    private String signName;

    /**
     * 必填:短信模板-可在短信控制台中找到
     */
    private String templateCode;

    /**
     * 可选:验证码
     */
    private String verifyCode;

    /**
     * 可选:上行短信扩展码(无特殊需求用户请忽略此字段)
     */
    private String smsUpExtendCode;

    /**
     * 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
     */
    private String outId;

    private String defaultConnectTimeout;

    private String defaultReadTimeout;

    public AliSmsBuilder() {
        // 默认初始化
        accessKeyId = "***";   // 替换成自己的阿里云短信accessKeyId
        accessKeySecret = "***";   // 替换成自己的阿里云短信accessKeySecret
        this.defaultConnectTimeout = "10000";
        this.defaultReadTimeout = "10000";
    }

    public AliSmsBuilder(String accessKeyId, String accessKeySecret) {
        // 自定义初始化
        this.accessKeyId = accessKeyId;
        this.accessKeySecret = accessKeySecret;
    }

    public AliSmsBuilder setAccessKeyId(String accessKeyId) {
        this.accessKeyId = accessKeyId;
        return this;
    }

    public String getAccessKeyId() {
        return accessKeyId;
    }

    public AliSmsBuilder setAccessKeySecret(String accessKeySecret) {
        this.accessKeySecret = accessKeySecret;
        return this;
    }

    public String getDefaultConnectTimeout() {
        return defaultConnectTimeout;
    }

    public AliSmsBuilder setDefaultConnectTimeout(String defaultConnectTimeout) {
        this.defaultConnectTimeout = defaultConnectTimeout;
        return this;
    }

    public String getDefaultReadTimeout() {
        return defaultReadTimeout;
    }

    public AliSmsBuilder setDefaultReadTimeout(String defaultReadTimeout) {
        this.defaultReadTimeout = defaultReadTimeout;
        return this;
    }

    public String getAccessKeySecret() {
        return accessKeySecret;
    }

    public AliSmsBuilder setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
        return this;
    }

    public String getPhoneNum() {
        return phoneNum;
    }

    public AliSmsBuilder setSignName(String signName) {
        this.signName = signName;
        return this;
    }

    public String getSignName() {
        return signName;
    }

    public AliSmsBuilder setTemplateCode(String templateCode) {
        this.templateCode = templateCode;
        return this;
    }

    public String getTemplateCode() {
        return templateCode;
    }

    public AliSmsBuilder setVerifyCode(String verifyCode) {
        this.verifyCode = verifyCode;
        return this;
    }

    public String getVerifyCode() {
        return verifyCode;
    }

    public AliSmsBuilder setSmsUpExtendCode(String smsUpExtendCode) {
        this.smsUpExtendCode = smsUpExtendCode;
        return this;
    }

    public String getSmsUpExtendCode() {
        return smsUpExtendCode;
    }

    public AliSmsBuilder setOutId(String outId) {
        this.outId = outId;
        return this;
    }

    public String getOutId() {
        return outId;
    }

    @Override
    public String toString() {
        return "AliSmsBuilder{" +
                "accessKeyId='" + accessKeyId + '\'' +
                ", accessKeySecret='" + accessKeySecret + '\'' +
                ", phoneNum='" + phoneNum + '\'' +
                ", signName='" + signName + '\'' +
                ", templateCode='" + templateCode + '\'' +
                ", verifyCode='" + verifyCode + '\'' +
                ", smsUpExtendCode='" + smsUpExtendCode + '\'' +
                ", outId='" + outId + '\'' +
                ", defaultConnectTimeout='" + defaultConnectTimeout + '\'' +
                ", defaultReadTimeout='" + defaultReadTimeout + '\'' +
                '}';
    }

    /**
     * 发送短信消息
     * @return
     * @throws ClientException
     */
    public String send() throws ClientException {
        return AliSmsSDK.getInstance().sendSmsAli(this);
    }
}

3.阿里云短信SDK

在这里有一点要强调下,我们从平台提取的短信模板内容为 验证码${code},您正在进行身份验证,打死不要告诉别人哦!,所以在以下代码当中我们设置模板参数的JSON串的代码为 request.setTemplateParam("{\"code\":\"" + 变量替换值 + "\"}"); 同理,如果你的模板内容是 亲爱的${name},您的验证码为${code} 那么在代码当中我们设置模板参数的JSON串的代码应该是 request.setTemplateParam("{\"name\":\"" + 变量替换值 + "\", \"code\":\"" + 变量替换值 + "\"}"); 。阿里云对于变量替换值也是有要求的:变量替换值<=6位数字或字母
换句话说以上JSON串该如何写,主要还是看你的模板内容如何配置。当然 request.setTemplateParam("{\"code\":\"" + 变量替换值 + "\"}"); 这段代码也可以忽略(只要对应的模板内容不配置占位符),因为这并不是必须的。

/**
 * 阿里云短信SDK
 * Created by Hilox on 2018/11/22 0022.
 */
@Slf4j
public class AliSmsSDK {

    // 产品名称:云通信短信API产品,开发者无需替换
    private static final String product = "Dysmsapi";
    // 产品域名,开发者无需替换
    private static final String domain = "dysmsapi.aliyuncs.com";

    /**
     * 私有化构造
     */
    private AliSmsSDK() {}

    /**
     * 静态内部类
     */
    private static class AliSmsSDKHolder {
        private static final AliSmsSDK INSTANCE = new AliSmsSDK();
    }

    /**
     * 选用静态内部类实现单例:
     *     1.防止懒汉式单例多线程额外开销
     *     2.防止饿汉式单例内存资源浪费
     * @return
     */
    public static final AliSmsSDK getInstance() {
        return AliSmsSDKHolder.INSTANCE;
    }

    /**
     * 发送短信验证码(阿里云短信平台)
     * @param aliSmsBuilder
     * @return
     */
    public String sendSmsAli(AliSmsBuilder aliSmsBuilder) throws ClientException {

        log.info("==== 开始发送短信验证码消息体: {} =====", aliSmsBuilder.toString());

        // 设置超时时间-可自行调整
        System.setProperty("sun.net.client.defaultConnectTimeout", aliSmsBuilder.getDefaultConnectTimeout());
        System.setProperty("sun.net.client.defaultReadTimeout", aliSmsBuilder.getDefaultReadTimeout());

        // 初始化acsClient, 暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", aliSmsBuilder.getAccessKeyId(), aliSmsBuilder.getAccessKeySecret());
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);
        // 组装请求对象-具体描述见控制台-文档部分内容
        SendSmsRequest request = new SendSmsRequest();
        // 必填:待发送手机号
        request.setPhoneNumbers(aliSmsBuilder.getPhoneNum());
        // 必填:短信签名-可在短信控制台中找到
        request.setSignName(aliSmsBuilder.getSignName());
        // 必填:短信模板-可在短信控制台中找到
        request.setTemplateCode(aliSmsBuilder.getTemplateCode());

        String verifyCode = aliSmsBuilder.getVerifyCode();
        // 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 request.setTemplateParam("{\"name\":\"Tom\", \"code\":\"123\"}");
        if (!StringUtils.isEmpty(verifyCode)) {
            request.setTemplateParam("{\"code\":\"" + verifyCode + "\"}");
        }

        String smsUpExtendCode = aliSmsBuilder.getSmsUpExtendCode();
        // 选填-上行短信扩展码(无特殊需求用户请忽略此字段)
        if (!StringUtils.isEmpty(smsUpExtendCode)) {
            request.setSmsUpExtendCode(smsUpExtendCode);
        }

        String outId = aliSmsBuilder.getOutId();
        // 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
        if (!StringUtils.isEmpty(outId)) {
            request.setOutId(outId);
        }

        //hint 此处可能会抛出异常,注意catch
        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
        String code = sendSmsResponse.getCode();

        log.info("==== 发送短信验证码成功, 返回code: {} =====", code);
        return code;
    }
}

4.阿里短信验证码返回code枚举

/**
 * 阿里短信验证码返回code列表
 * Created by Hilox on 2018/11/13 0013.
 */
public enum AliSmsCodeEnum {

    OK("OK", "请求成功"),
    RAM_PERMISSION_DENY("isp.RAM_PERMISSION_DENY", "RAM权限DENY"),
    OUT_OF_SERVICE("isv.OUT_OF_SERVICE", "业务停机"),
    PRODUCT_UN_SUBSCRIPT("isv.PRODUCT_UN_SUBSCRIPT", "未开通云通信产品的阿里云客户"),
    PRODUCT_UNSUBSCRIBE("isv.PRODUCT_UNSUBSCRIBE", "产品未开通"),
    ACCOUNT_NOT_EXISTS("isv.ACCOUNT_NOT_EXISTS", "账户不存在"),
    ACCOUNT_ABNORMAL("isv.ACCOUNT_ABNORMAL", "账户异常"),
    SMS_TEMPLATE_ILLEGAL("isv.SMS_TEMPLATE_ILLEGAL", "短信模板不合法"),
    SMS_SIGNATURE_ILLEGAL("isv.SMS_SIGNATURE_ILLEGAL", "短信签名不合法"),
    INVALID_PARAMETERS("isv.INVALID_PARAMETERS", "参数异常"),
    SYSTEM_ERROR("isp.SYSTEM_ERROR", "系统错误"),
    MOBILE_NUMBER_ILLEGAL("isv.MOBILE_NUMBER_ILLEGAL", "非法手机号"),
    MOBILE_COUNT_OVER_LIMIT("isv.MOBILE_COUNT_OVER_LIMIT", "手机号码数量超过限制"),
    TEMPLATE_MISSING_PARAMETERS("isv.TEMPLATE_MISSING_PARAMETERS", "模板缺少变量"),
    BUSINESS_LIMIT_CONTROL("isv.BUSINESS_LIMIT_CONTROL", "业务限流"),
    INVALID_JSON_PARAM("isv.INVALID_JSON_PARAM", "JSON参数不合法,只接受字符串值"),
    BLACK_KEY_CONTROL_LIMIT("isv.BLACK_KEY_CONTROL_LIMIT", "黑名单管控"),
    PARAM_LENGTH_LIMIT("isv.PARAM_LENGTH_LIMIT", "参数超出长度限制"),
    PARAM_NOT_SUPPORT_URL("isv.PARAM_NOT_SUPPORT_URL", "不支持URL"),
    AMOUNT_NOT_ENOUGH("isv.AMOUNT_NOT_ENOUGH", "账户余额不足"),
    ;

    private String code;

    private String msg;

    AliSmsCodeEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    /**
     * 根据code获取msg
     * @param code
     * @return
     */
    public static String getMsgByCode(String code) {
        if (StringUtils.isEmpty(code)) {
            return null;
        }
        AliSmsCodeEnum[] values = AliSmsCodeEnum.values();
        for (AliSmsCodeEnum aliSmsCodeEnum : values) {
            if (aliSmsCodeEnum.getCode().equals(code)) {
                return aliSmsCodeEnum.getMsg();
            }
        }
        return null;
    }
}

5.测试用例

博主在这里简单的写了个测试用例,后续调用方式大家可以从这里做参考。
对应的值需要替换成从云平台提取出来的相应值。

/**
 * 测试用例模板
 * Created by Hilox on 2018/11/22 0022.
 */
public class AliSmsSDKTest {

    @Test
    public void sendSmsAli() {
        AliSmsBuilder aliSmsBuilder = new AliSmsBuilder();
        String code;
        try {
            code = aliSmsBuilder.setPhoneNum("150****8879")    // 替换成自己的手机号
                    .setSignName("阿里云短信测试专用")  // 替换成自己的阿里云短信服务签名
                    .setTemplateCode("SMS_108565014") // 替换成自己的阿里云短信模板编号
                    .setVerifyCode("Hilox") // 替换成自己随机生成的验证码
                    .send();
        } catch (ClientException e) {
            e.printStackTrace();
            // 短信发送异常提示
            return;
        }

        // 短信异常码处理
        if (code == null || !"OK".equals(code)) {
            String errorMsg = AliSmsCodeEnum.getMsgByCode(code);
            if (!StringUtils.isEmpty(errorMsg)) {
                // 对应短信异常错误提示
                return;
            }
            // 短信发送异常提示
        }
    }
}

源码传送门

【源码地址】sms-ali

测试效果展示

图3 测试效果展示
相关推荐
<p> <b><span style="font-size:14px;"></span><span style="font-size:14px;background-color:#FFE500;">【Java面试宝典】</span></b><br /> <span style="font-size:14px;">1、68讲视频课,500道大厂Java常见面试题+100个Java面试技巧与答题公式+10万字核心知识解析+授课老师1对1面试指导+无限次回放</span><br /> <span style="font-size:14px;">2、这门课程基于胡书敏老师8年Java面试经验,调研近百家互联网公司及面试官的问题打造而成,从筛选简历和面试官角度,给出能帮助候选人能面试成功的面试技巧。</span><br /> <span style="font-size:14px;">3、通过学习这门课程,你能系统掌握Java核心、数据库、Java框架、分布式组件、Java简历准备、面试实战技巧等面试必考知识点。</span><br /> <span style="font-size:14px;">4、知识点+项目经验案例,每一个都能做为面试的作品展现。</span><br /> <span style="font-size:14px;">5、本课程已经在线下的培训课程中经过实际检验,老师每次培训结束后,都能帮助同学们运用面试技巧,成功找到更好的工作。</span><br /> <br /> <span style="font-size:14px;background-color:#FFE500;"><b>【超人气讲师】</b></span><br /> <span style="font-size:14px;">胡书敏 | 10年大厂工作经验,8年Java面试官经验,5年线下Java职业培训经验,5年架构师经验</span><br /> <br /> <span style="font-size:14px;background-color:#FFE500;"><b>【报名须知】</b></span><br /> <span style="font-size:14px;">上课模式是什么?</span><br /> <span style="font-size:14px;">课程采取录播模式,课程永久有效,可无限次观看</span><br /> <span style="font-size:14px;">课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化</span><br /> <br /> <br /> <span style="font-size:14px;background-color:#FFE500;"><strong>如何开始学习?</strong></span><br /> <span style="font-size:14px;">PC端:报名成功后可以直接进入课程学习</span><br /> <span style="font-size:14px;">移动端:<span style="font-family:Helvetica;font-size:14px;background-color:#FFFFFF;">CSDN 学院APP(注意不是CSDN APP哦)</span></span> </p>
<p> <span style="color:#337FE5;"><strong>【为什么还需要学习C++?】</strong></span> </p> <p style="margin-left:0cm;"> 你是否接触很多语言,但从来没有了解过编程语言的本质? </p> <p style="margin-left:0cm;text-align:start;"> 你是否想成为一名资深开发人员,想开发别人做不了的高性能程序? </p> <p style="margin-left:0cm;text-align:start;"> 你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹? </p> <p style="margin-left:0cm;text-align:start;">   </p> <p style="margin-left:0cm;text-align:start;"> 那么C++就是你个人能力提升,职业之路进阶的不二之选。 </p> <p style="margin-left:0cm;text-align:start;"> <br /> </p> <p style="margin-left:0cm;text-align:start;"> <br /> </p> <p style="margin-left:0cm;"> <strong><span style="color:#337FE5;">【课程特色】</span></strong> </p> <p style="margin-left:0cm;text-align:start;"> 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。 </p> <p style="margin-left:0cm;text-align:start;"> 2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。 </p> <p style="margin-left:0cm;text-align:start;"> 3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。 </p> <p style="margin-left:0cm;text-align:start;"> <br /> </p> <p class="ql-long-24357476"> <span style="color:#337FE5;"><strong>【学完后我将达到什么水平?】</strong></span> </p> <p class="ql-long-24357476"> 1.对C++的各个知识能够熟练配置、开发、部署; </p> <p class="ql-long-24357476"> 2.吊打一切关于C++的笔试面试题; </p> <p class="ql-long-24357476"> 3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。 </p> <p class="MsoNoSpacing" style="margin-left:18pt;"> <br /> </p> <div> <br /> </div> <p> <br /> </p> <p style="margin-left:0cm;text-align:start;"> <span style="color:#337FE5;"><strong>【面向人群】</strong></span> </p> <p style="margin-left:0cm;text-align:start;"> <span style="color:#222226;font-family:PingFangSC-Regular, "font-size:14px;background-color:#FFFFFF;">1.希望一站式快速入门的C++初学者;</span> </p> <p style="margin-left:0cm;text-align:start;"> <span style="color:#222226;font-family:PingFangSC-Regular, "font-size:14px;background-color:#FFFFFF;">2.希望快速学习 C++、掌握编程要义、修炼内功的开发者;</span> </p> <p style="margin-left:0cm;text-align:start;"> <span style="color:#222226;font-family:PingFangSC-Regular, "font-size:14px;background-color:#FFFFFF;">3.有志于挑战更高级的开发项目,成为资深开发的工程师。</span> </p> <p style="margin-left:0cm;text-align:start;"> <br /> </p> <p> <br /> </p> <p> <span style="color:#337FE5;"><strong>【课程设计】</strong></span> </p> <p> 本课程包含3大模块 </p> <p> <strong>基础篇</strong><br /> 本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。 </p> <p> <br /> <strong>进阶篇</strong><br /> 本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。 </p> <p> <br /> <strong>提升篇:</strong><br /> 本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。 </p> <p> <img src="https://img-bss.csdnimg.cn/202007091130239667.png" alt="" /> </p>
android开发期末大作业(项目源码,任务书,实验大报告,apk文件) 大作业的要求和内容:(包括题目选择范围、技术要求、递交时间、考核方法等) 一、实验项目名称 Android手机应用开发课程大作业 二、实验目的 1.通过本课程设计的实践及其前后的准备与总结,复习、领会、巩固和运用课堂上所学的Android手机应用开发知识。 2.为学生综合应用本专业所学习的多门课程知识(例如,软件工程、数据库、Java语言、Java Web开发等)创造实践机会。为学生提供主动学习、积极探索与大胆创新的机会。 3.掌握Android手机应用设计的方法与技巧。 三、实验内容及要求 1、设计内容 题目、设计内容自拟,工作量适中,要求学生应用课程所学知识,采用JAVA语言和Android手机应用开发技术实现一个完整的系统。 ①完成大作业报告。 ②实现各系统功能,并完成调试运行。 2、主要技术 采用Java语言并不仅限于Java语言实现系统。 开发环境与工具:Android Studio 3.2以上版本; 操作系统:Win7/Win10或其他; 4、设计成果: 材料上交:电子文档(大作业任务书+大作业报告+源代码,电子稿请刻在光盘上)、打印稿(大作业任务书+大作业报告)。 四、成绩评定: 考核标准包括: 1、选题的工作量,难度和新颖程度 2、系统架构设计是否良好,运行过程是否报错 3、界面设计的合理性和美观程度 4、基本功能实现 分值60 (包括布局、组件、Activity、Intent等使用) 数据存储的使用 分值10 网络功能 分值10 Service、ContentProvider或BroadCastReceiver等的使用 分值10 附加分: 图形图像处理、多媒体处理等 分值10 5、考核方式为面对面答辩,在课程的后两周内集中进行。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页