一、使用RAM子用户
1、进入子用户管理页面
2、添加用户
3、获取子用户key
AccessKeyId, AccessKeySecret
4、设置用户权限
授权:AliyunDysmsFullAccess
二、开通短信服务
1、开通
2、添加签名
3、添加模板
4、套餐
5、快速学习
三、测试短信发送
1、查找使用示例
2、测试短信发送
3、查看发送结果
短信服务->业务统计->发送记录查询
四、创建项目
需求
1、创建service-sms模块
2、配置 pom.xml
<dependencies>
<dependency>
<groupId>com.indi</groupId>
<artifactId>service-base</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok用来简化实体类:需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--阿里云短信-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</dependency>
</dependencies>
3、application.yml
resources目录下创建文件
server:
port: 8120 # 服务端口
spring:
profiles:
active: dev # 环境设置
application:
name: service-sms # 服务名
#spring:
redis:
host: 192.168.2.190
port: 6379
database: 0
password: 123456 #没有密码,则去掉此选项
timeout: 3000ms #最大等待时间,超时则抛出异常,否则请求一直等待
lettuce:
pool:
max-active: 20 #最大连接数,负值表示没有限制,默认8
max-wait: -1 #最大阻塞等待时间,负值表示没限制,默认-1
max-idle: 8 #最大空闲连接,默认8
min-idle: 0 #最小空闲连接,默认0
#阿里云短信
aliyun:
sms:
region-id: cn-hangzhou
key-id: 你的keyid
key-secret: 你的keysecret
template-code: 你的短信模板code
sign-name: 你的短信模板签名
4、logback-spring.xml
复制之前sms-core模块的,只需要修改日志输出目录即可
5、创建SpringBoot启动类
ServiceSmsApplication.java
package com.indi.srb.sms;
@SpringBootApplication
@ComponentScan({"com.indi.srb","com.indi.common"})
public class ServiceSmsApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceSmsApplication.class, args);
}
}
五、自定义配置
1、从配置文件读取常量
com.indi.srb.sms.util
包下
创建常量读取工具类:SmsProperties.java
package com.indi.srb.sms.util;
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.sms")
public class SmsProperties implements InitializingBean {
private String regionId;
private String keyId;
private String keySecret;
private String templateCode;
private String signName;
public static String REGION_Id;
public static String KEY_ID;
public static String KEY_SECRET;
public static String TEMPLATE_CODE;
public static String SIGN_NAME;
//当私有成员被赋值后,此方法自动被调用,从而初始化常量
@Override
public void afterPropertiesSet() throws Exception {
REGION_Id = regionId;
KEY_ID = keyId;
KEY_SECRET = keySecret;
TEMPLATE_CODE = templateCode;
SIGN_NAME = signName;
}
}
Idea报告如下错误信息(不影响程序的编译和运行):
解决步骤:
-
pom添加依赖
<!-- 配置文件处理器 --> <!--让自定义的配置在application.yaml进行自动提示--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
-
启用processor
-
重新编译模块
-
这样在yml文件中写阿里云的配置时,就有提示了
2、测试工具类
test
模块下创建UtilsTests.java
package com.indi.srb.sms;
@SpringBootTest
@RunWith(SpringRunner.class)
public class UtilsTests {
@Test
public void testProperties(){
System.out.println(SmsProperties.KEY_ID);
System.out.println(SmsProperties.KEY_SECRET);
System.out.println(SmsProperties.REGION_Id);
}
}
六、发送短信
1、短信发送业务
SmsService.java
package com.indi.srb.sms.service;
public interface SmsService {
void send(String mobile, String templateCode, Map<String,Object> param);
}
SmsServiceImpl.java
@Service
@Slf4j
public class SmsServiceImpl implements SmsService {
@Override
public void send(String mobile, String templateCode, Map<String,Object> param) {
//创建远程连接客户端对象
DefaultProfile profile = DefaultProfile.getProfile(
SmsProperties.REGION_Id,
SmsProperties.KEY_ID,
SmsProperties.KEY_SECRET);
IAcsClient client = new DefaultAcsClient(profile);
//创建远程连接的请求参数
CommonRequest request = new CommonRequest();
request.setSysMethod(MethodType.POST);
request.setSysDomain("dysmsapi.aliyuncs.com");
request.setSysVersion("2017-05-25");
request.setSysAction("SendSms");
request.putQueryParameter("RegionId", SmsProperties.REGION_Id);
request.putQueryParameter("PhoneNumbers", mobile);
request.putQueryParameter("SignName", SmsProperties.SIGN_NAME);
request.putQueryParameter("TemplateCode", templateCode);
Gson gson = new Gson();
String json = gson.toJson(param);
request.putQueryParameter("TemplateParam", json);
try {
// 使用客户端对象携带请求参数向远程阿里云服务器发起远程调用,并得到响应结果
CommonResponse response = client.getCommonResponse(request);
// 通信失败的处理
boolean success = response.getHttpResponse().isSuccess();
// ALIYUN_RESPONSE_FAIL(-501, "阿里云响应失败"),
Assert.isTrue(success, ResponseEnum.ALIYUN_RESPONSE_FAIL);
// 获取响应结果
String data = response.getData();
HashMap<String, String> resultMap = gson.fromJson(data, HashMap.class);
String code = resultMap.get("Code");
String message = resultMap.get("Message");
log.info("阿里云短信发送响应结果:");
log.info("code:" + code);
log.info("message:" + message);
// 业务失败的处理
Assert.notEquals("isv.BUSINESS_LIMIT_CONTROL", code, ResponseEnum.ALIYUN_SMS_LIMIT_CONTROL_ERROR);
Assert.equals("OK", code, ResponseEnum.ALIYUN_SMS_ERROR);
} catch (ServerException e) {
log.error("阿里云短信发送SDK调用失败:");
log.error("ErrorCode=" + e.getErrCode());
log.error("ErrorMessage=" + e.getErrMsg());
throw new BusinessException(ResponseEnum.ALIYUN_SMS_ERROR , e);
} catch (ClientException e) {
log.error("阿里云短信发送SDK调用失败:");
log.error("ErrorCode=" + e.getErrCode());
log.error("ErrorMessage=" + e.getErrMsg());
throw new BusinessException(ResponseEnum.ALIYUN_SMS_ERROR , e);
}
}
}
2、引入工具类
indi-common模块中创建util
包,存放工具类
RandomUtils.java
:生成四位或六位的验证码
package com.indi.common.util;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
/**
* 生成四位和六位的随机数字
*/
public class RandomUtils {
private static final Random random = new Random();
private static final DecimalFormat fourdf = new DecimalFormat("0000");
private static final DecimalFormat sixdf = new DecimalFormat("000000");
public static String getFourBitRandom() {
return fourdf.format(random.nextInt(10000));
}
public static String getSixBitRandom() {
return sixdf.format(random.nextInt(1000000));
}
/**
* 给定数组,抽取n个数据
* @param list
* @param n
* @return
*/
public static ArrayList getRandom(List list, int n) {
Random random = new Random();
HashMap<Object, Object> hashMap = new HashMap<Object, Object>();
// 生成随机数字并存入HashMap
for (int i = 0; i < list.size(); i++) {
int number = random.nextInt(100) + 1;
hashMap.put(number, i);
}
// 从HashMap导入数组
Object[] robjs = hashMap.values().toArray();
ArrayList r = new ArrayList();
// 遍历数组并打印数据
for (int i = 0; i < n; i++) {
r.add(list.get((int) robjs[i]));
System.out.print(list.get((int) robjs[i]) + "\t");
}
System.out.print("\n");
return r;
}
}
RegexValidateUtils.java
:常用正则表达式验证,这里提供了手机号码验证
package com.indi.common.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 使用正则表达式进行表单验证
*/
public class RegexValidateUtils {
static boolean flag = false;
static String regex = "";
public static boolean check(String str, String regex) {
try {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
flag = matcher.matches();
} catch (Exception e) {
flag = false;
}
return flag;
}
/**
* 验证邮箱
*
* @param email
* @return
*/
public static boolean checkEmail(String email) {
String regex = "^\\w+[-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$ ";
return check(email, regex);
}
/**
* 验证手机号码
*
* 移动号码段:139、138、137、136、135、134、150、151、152、157、158、159、182、183、187、188、147
* 联通号码段:130、131、132、136、185、186、145
* 电信号码段:133、153、180、189
*
* @param cellphone
* @return
*/
public static boolean checkCellphone(String cellphone) {
String regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$";
return check(cellphone, regex);
}
/**
* 验证固话号码
*
* @param telephone
* @return
*/
public static boolean checkTelephone(String telephone) {
String regex = "^(0\\d{2}-\\d{8}(-\\d{1,4})?)|(0\\d{3}-\\d{7,8}(-\\d{1,4})?)$";
return check(telephone, regex);
}
/**
* 验证传真号码
*
* @param fax
* @return
*/
public static boolean checkFax(String fax) {
String regex = "^(0\\d{2}-\\d{8}(-\\d{1,4})?)|(0\\d{3}-\\d{7,8}(-\\d{1,4})?)$";
return check(fax, regex);
}
/**
* 验证QQ号码
*
* @param QQ
* @return
*/
public static boolean checkQQ(String QQ) {
String regex = "^[1-9][0-9]{4,} $";
return check(QQ, regex);
}
}
3、创建controller
创建controller.api
包,创建类ApiSmsController.java
package com.indi.srb.sms.controller.api;
@RestController
@Slf4j
@Api(tags = "短信管理")
@CrossOrigin
@RequestMapping("/api/sms")
public class ApiSmsController {
@Resource
private SmsService smsService;
@Resource
private RedisTemplate redisTemplate;
@ApiOperation("获取验证码")
@GetMapping("/send/{mobile}")
public R send(
@ApiParam(value = "手机号", required = true)
@PathVariable String mobile) {
// 校验手机号不能为空
Assert.notEmpty(mobile, ResponseEnum.MOBILE_NULL_ERROR);
// 校验手机号是否合法
Assert.isTrue(RegexValidateUtils.checkCellphone(mobile), ResponseEnum.MOBILE_ERROR);
String code = RandomUtils.getFourBitRandom();
HashMap<String, Object> map = new HashMap<>();
map.put("code", code);
smsService.send(mobile, SmsProperties.TEMPLATE_CODE, map);
// 将验证码存入redis
redisTemplate.opsForValue().set("srb:sms:code:" + mobile, code, 5, TimeUnit.MINUTES);
return R.ok().setMessage("短信发送成功");
}
}
七、测试
http://localhost:8120/swagger-ui.html
测试正确发送
测试手机号码不正确
测试业务限流:连续发送两次短信