步骤比较清晰:
- 前端调发送验证码的接口
- 后端service层写对应的send方法,给用户发验证码短信
- 用户再输入验证码,再让后端从redis中读验证码做比对
在用之前得先去容联云官网注册账号,注册完了就可以免费测试(免费测试是不能编辑短信模板的),后续可以开通付费
https://doc.yuntongxun.com/p/5a531a353b8496dd00dcdfe2
一、Maven依赖
<!--容联云短信sdk-->
<dependency>
<groupId>com.cloopen</groupId>
<artifactId>java-sms-sdk</artifactId>
<version>1.0.3</version>
</dependency>
<!-- 还要加谷歌gson包,版本号就用最新的,否则要报错 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
application.yml
# 容联云(这里是自定义的配置项,到时候可以用@ConfigurationProperties注解读取)
rckj:
accountSID: 8aaf0708809721d00999999999999
accountToken: f930071f78ae42ceeeeeeeeeeeeee
appId: 8aaf0708809721d00180000000000000
serverIp: app.cloopen.com
serverPort: 8883
工具类(读取yml文件里的相关配置值)
// 这个类不写也可以,那就在发送短信的方法里直接填容联云的配置值
@ConfigurationProperties(prefix = "rckj") //会从yml中找到对应的配置项,直接赋值给当前类的属性
@Component
@Data
public class SmsProperties implements InitializingBean {
private String accountSID;
private String accountToken;
private String appId;
private String serverIp;
private String serverPort;
public static String ACCOUNT_SID;
public static String ACCOUNT_Token;
public static String APP_ID;
public static String SERVER_IP;
public static String SERVER_PORT;
//继承的InitializingBean类,重写这个方法就是当私有属性被赋值之后(from app.yml),才执行的
@Override
public void afterPropertiesSet() throws Exception {
ACCOUNT_SID=accountSID;
ACCOUNT_Token=accountToken;
APP_ID=appId;
SERVER_IP=serverIp;
SERVER_PORT=serverPort;
}
}
二、controller层
@RestController
@RequestMapping("/api/sms")
@CrossOrigin
public class ApiSmsController {
@Autowired
private SmsService smsService;
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/send/{mobile}")
public Result send(@PathVariable String mobile){
// 实际上还要校验一下手机号是否合法,当然这步前端也可以校验
Map<String,Object> map=new HashMap<>();
String fourBitRandom = RandomUtils.getFourBitRandom();// 工具类生成4位随机数
map.put("code", fourBitRandom);
smsService.send(mobile,map);
//将验证码存入redis
redisTemplate.opsForValue().set("test:sms:code"+mobile, fourBitRandom, 5, TimeUnit.MINUTES);
return Result.ok().customMsg("短信发送成功");
}
}
三、service层(官网有各种语言的demo)
@Service
public class SmsServiceImpl implements SmsService {
//短信发送
@Override
public void send(String mobile, Map<String, Object> param) {
CCPRestSmsSDK sdk = new CCPRestSmsSDK();
// 配置账号信息
sdk.init(SmsProperties.SERVER_IP, SmsProperties.SERVER_PORT);
sdk.setAccount(SmsProperties.ACCOUNT_SID, SmsProperties.ACCOUNT_Token);
sdk.setAppId(SmsProperties.APP_ID);
sdk.setBodyType(BodyType.Type_JSON);
//String templateId= "xxxx"; 免费测试直接写"1",付费开通后可以自定义短信模板
String[] datas = {(String) param.get("code"), "5"}; //短信里的变量,验证码、几分钟内有效
HashMap<String, Object> result = sdk.sendTemplateSMS(mobile,"1",datas);
System.out.println("SMS--Result: "+result);
if("000000".equals(result.get("statusCode"))){
//正常返回输出data包体信息(map)
HashMap<String,Object> data = (HashMap<String, Object>) result.get("data");
Set<String> keySet = data.keySet();
for(String key:keySet){
Object object = data.get(key);
System.out.println(key +" = "+object);
}
}else {
//异常返回输出错误码和错误信息(或log.error 打印到日志)
System.out.println("错误码=" + result.get("statusCode") + " 错误信息= " + result.get("statusMsg"));
// 自定义的统一异常处理,如果出错了会发给前端
throw new BusinessException(ResponseEnum.ALIYUN_SMS_ERROR);
}
}
}