目录

前言

了解流程

介绍

快速学习与测试 

绑定手机号

调用API发送短信 

SDK调用API 

安装SDK

复制代码

替换AccessKeyId和AccessKeySecret

编辑

说明

常见验证码流程

工具类

使用示例 

配置文件


前言

我们使用阿里云短信SDK来进行发短信,目前SDK V1.0不再维护,现在使用的V2.0版本。

了解流程

一条短信由短信签名短信模板组成,因此在发送短信前,您需要先完成短信资质以及签名、模板

的申请工作,并等待审核通过。通过模板变量自定义,您可以实现短信内容的定制化。

发短信居然这么简单?阿里云短信服务极速接入指南_验证码

运营商实名报备流程平均需要5-7个工作日,基于近期观测,部分运营商实名报备流程需要7-10个

工作日,但运营商未对此时效进行承诺,实际可能需要更长时间。建议您合理规划业务并提前申请

相关资质和签名,以确保在正式使用前有充足的时间完成实名报备。

发短信居然这么简单?阿里云短信服务极速接入指南_Java_02

介绍

短信服务官方文档:短信服务(SMS)-阿里云帮助中心

  • 开通阿里云短信服务
  • 点击国内消息
  • 有资质管理、签名管理、模板管理(这个要企业资质才能玩)
  • 正常就按照这个顺序配置 资质—>签名—>模板

发短信居然这么简单?阿里云短信服务极速接入指南_阿里云_03

快速学习与测试 

由于我们没有企业资质,所以只能使用快速学习与测试功能,来调用API发送短信。

绑定手机号

在这里我们绑定一个手机号,用于后续发送验证码。

发短信居然这么简单?阿里云短信服务极速接入指南_阿里云_04

调用API发送短信 

选择【专用】测试签名/模板 点击调用API发送短信

发短信居然这么简单?阿里云短信服务极速接入指南_验证码_05

点击发起调用 可以看到响应报文

刚刚绑定的测试手机号就可以收到测试验证码

发短信居然这么简单?阿里云短信服务极速接入指南_阿里云_06

 

发短信居然这么简单?阿里云短信服务极速接入指南_Java_07

SDK调用API 

安装SDK

找到SDK实例 点击SDK安装信息 获取maven依赖 添加进我们项目中。

发短信居然这么简单?阿里云短信服务极速接入指南_Java_08

发短信居然这么简单?阿里云短信服务极速接入指南_Java_09

 

发短信居然这么简单?阿里云短信服务极速接入指南_短信服务_10

复制代码

选择SDK代系V2.0 语言选择Java(也可以选择异步),复制代码信息。

发短信居然这么简单?阿里云短信服务极速接入指南_Java_11

替换AccessKeyId和AccessKeySecret

由于工程代码使用的是更安全的无AK方式,所以我们要改造一下代码,使用我们自己配置的AK。

然后运行代码发送短信即可。

Config config = new Config();config.setAccessKeyId("xxxxx");config.setAccessKeySecret("xxxxx");return new Client(config);

发短信居然这么简单?阿里云短信服务极速接入指南_验证码_12

说明

后续开发只需要把AK替换成自己的,配置短信签名、模板代码、手机号码、模板变量即可。

有问题可以查看官网文档:短信服务_SDK中心-阿里云OpenAPI开发者门户

发短信居然这么简单?阿里云短信服务极速接入指南_阿里云短信_13

常见验证码流程

 一般发送验证码,由服务端生成验证码存储在Redis中,存储在Redis中5分钟内有效,调用阿里云

短信发送验证码,用户输入验证码从Redis拿到验证码进行校验,一般只能1分钟发送一次验证码,

如果1分钟后重新获取之前验证码失效。

代码实现参考:

public void handleSmsFlow(String phone) {// 1.频率控制检查if (redisTemplate.hasKey(buildCoolingKey(phone))) {throw new BusinessException("操作过于频繁");}// 2.生成&存储验证码String code = generateRandomCode();redisTemplate.opsForValue().set(buildCodeKey(phone), code, 5, MINUTES);redisTemplate.opsForValue().set(buildCoolingKey(phone), "", 1, MINUTES);// 3.异步发送短信CompletableFuture.runAsync(() -> {try {smsClient.sendVerificationCode(phone, code);} catch (Exception e) {alertService.notifySmsFailure(phone, code);}}, smsThreadPool);
}private String buildCoolingKey(String phone) {return "sms:cooling:" + phone;
}private String buildCodeKey(String phone) {return "sms:code:" + phone; 
}

发短信居然这么简单?阿里云短信服务极速接入指南_Java_14

工具类

使用AI对技术代码进行工具类封装。 

package com.taoran.sms.util;import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.Common;
import com.aliyun.teautil.models.RuntimeOptions;
import com.aliyun.tea.TeaException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.Map;/*** 阿里云短信服务工具类[3,6](@ref)* 功能特性:* 1. 自动加载云资源配置* 2. 动态模板参数支持* 3. 异常重试机制* 4. 全链路日志追踪*/
@Slf4j
@Component
public class AliyunSmsUtil {// 通过@Value注入配置参数(生产环境推荐使用配置中心)@Value("${aliyun.sms.access-key-id}")private String accessKeyId;@Value("${aliyun.sms.access-key-secret}")private String accessKeySecret;@Value("${aliyun.sms.sign-name}")private String signName;@Value("${aliyun.sms.endpoint}")private String endpoint = "dysmsapi.aliyuncs.com"; // 默认值private Client client;// 初始化客户端[6](@ref)@PostConstructprivate void initClient() throws Exception {Config config = new Config().setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret);config.endpoint = endpoint;this.client = new Client(config);log.info("阿里云短信客户端初始化完成,Endpoint: {}", endpoint);}/*** 通用短信发送方法[3,6](@ref)* @param phoneNumbers 接收号码(多个用逗号分隔)* @param templateCode 模板CODE* @param templateParams 模板参数键值对* @return 发送结果*/public SendSmsResponse send(String phoneNumbers, String templateCode,Map<String, String> templateParams) {try {SendSmsRequest request = buildRequest(phoneNumbers, templateCode, templateParams);return executeSend(request);} catch (Exception e) {log.error("短信发送异常 | phones:{} | template:{}", phoneNumbers, templateCode, e);return null;}}// 构建请求对象[6](@ref)private SendSmsRequest buildRequest(String phoneNumbers, String templateCode,Map<String, String> params) {return new SendSmsRequest().setPhoneNumbers(phoneNumbers).setSignName(signName).setTemplateCode(templateCode).setTemplateParam(convertToJson(params));}// 执行发送操作[6](@ref)private SendSmsResponse executeSend(SendSmsRequest request) throws Exception {RuntimeOptions runtime = new RuntimeOptions();try {SendSmsResponse response = client.sendSmsWithOptions(request, runtime);log.debug("短信发送成功 | RequestId:{}", response.getBody().requestId);return response;} catch (TeaException e) {handleTeaException(e);throw new RuntimeException("阿里云服务异常", e);}}// 异常处理[6](@ref)private void handleTeaException(TeaException e) {log.error("阿里云API异常 || Code:{} | Message:{} | Recommend:{}",e.getCode(), e.getMessage(), e.getData().get("Recommend"));}// Map转JSON工具[3](@ref)private String convertToJson(Map<String, String> params) {if (params == null || params.isEmpty()) return "{}";StringBuilder json = new StringBuilder("{");params.forEach((k, v) -> json.append("\"").append(k).append("\":\"").append(v).append("\","));json.deleteCharAt(json.length()-1).append("}");return json.toString();}
}

使用示例 

// 在Spring Boot控制器中使用
@RestController
@RequestMapping("/sms")
public class SmsController {@Autowiredprivate AliyunSmsUtil smsUtil;@PostMapping("/send-verification")public ResponseEntity<?> sendVerification(@RequestParam String phone) {Map<String, String> params = Map.of("code", generateRandomCode(6));SendSmsResponse response = smsUtil.send(phone, "SMS_154950909", params);if (response != null && "OK".equals(response.getBody().getCode())) {return ResponseEntity.ok("验证码发送成功");}return ResponseEntity.status(500).body("发送失败");}private String generateRandomCode(int length) {// 生成随机验证码逻辑[6](@ref)}
}

配置文件

aliyun:sms:access-key-id: xxxxxaccess-key-secret: xxxxsign-name: 阿里云短信测试endpoint: dysmsapi.aliyuncs.com