SpringCloud集成–容联云通讯–Redis
发送短信微服务
项目结构
配置文件
-
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>leyou</artifactId> <groupId>com.leyou.parent</groupId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.leyou.service</groupId> <artifactId>ly-sms</artifactId> <dependencies> <!-- 容联云通讯, 发送短信的依赖 自带的是gson2.8.5但是会报错--> <dependency> <groupId>com.cloopen</groupId> <artifactId>java-sms-sdk</artifactId> <version>1.0.1</version> </dependency> <!-- 必须添加2.8.6, 要不然发送短信就会报错 --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency> <!-- spring操作rabbitmq依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <!-- 测试依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- spring操作redis依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> </project>
-
application.yml
server: port: 8086 spring: application: name: sms-service rabbitmq: host: 192.168.79.128 # 安装rabbitmq的ip username: leyou # rabbitmq的账号 password: 123456 # rabbitmq的密码 virtual-host: /leyou # 虚拟主机 redis: host: 192.168.79.128 # 端口默认6379, 所以这里没配置 ly: sms: # 主账号,登陆云通讯网站后,可在控制台首页看到开发者主账号ACCOUNT SID和主账号令牌AUTH TOKEN accountSId: *********************** accountToken: *********************** # 请使用管理控制台中已创建应用的APPID appId: *********************** # 短信模板 templateId: 1
启动类
-
LySmsApplication
package com.leyou.sms; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @program: leyou * @description: * @author: Mr.Xiao * @create: 2020-07-01 11:12 **/ @SpringBootApplication public class LySmsApplication { public static void main(String[] args) { SpringApplication.run(LySmsApplication.class); } }
config
-
SmsProperties
package com.leyou.sms.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; /** * @program: leyou * @description: java配置类 * @author: Mr.Xiao * @create: 2020-07-01 11:24 **/ @ConfigurationProperties(prefix = "ly.sms") @Data public class SmsProperties { private String accountSId; private String accountToken; private String appId; private String templateId; }
mq
-
SmsListener
package com.leyou.sms.mq; import com.leyou.sms.config.SmsProperties; import com.leyou.sms.utils.SmsUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.amqp.core.ExchangeTypes; import org.springframework.amqp.rabbit.annotation.Exchange; import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.QueueBinding; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.Map; /** * @program: leyou * @description: 消息接收处理 * @author: Mr.Xiao * @create: 2020-06-29 18:21 **/ @Component @EnableConfigurationProperties(SmsProperties.class) public class SmsListener { @Autowired private SmsUtils smsUtils; @Autowired private SmsProperties prop; @RabbitListener(bindings = @QueueBinding( /** * name = "sms.verify.code.queue" 队列名称 * durable = "true" 持久化 **/ value = @Queue(name = "sms.verify.code.queue", durable = "true"), /** * name = "ly.sms.exchange" 交换机名称 * type = ExchangeTypes.TOPIC 交换机类型 **/ exchange = @Exchange(name = "ly.sms.exchange", type = ExchangeTypes.TOPIC), /** * key = "sms.verify.code" routing key **/ key = "sms.verify.code" )) public void listenerSendSms(Map<String, String> msg) { if (CollectionUtils.isEmpty(msg)) { return; } String to = msg.get("phone"); if (StringUtils.isBlank(to)) { return; } String[] datas = msg.get("datas").split(","); // 发送短信验证码 smsUtils.sendSms(to, prop.getTemplateId(), datas); } }
utils
-
SmsUtils
package com.leyou.sms.utils; import com.cloopen.rest.sdk.BodyType; import com.cloopen.rest.sdk.CCPRestSmsSDK; import com.leyou.sms.config.SmsProperties; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Set; import java.util.concurrent.TimeUnit; /** * @program: leyou * @description: 发送短息 * @author: Mr.Xiao * @create: 2020-07-01 11:27 **/ @Slf4j @Component @EnableConfigurationProperties(SmsProperties.class) public class SmsUtils { @Autowired private SmsProperties prop; // java配置类, 把发送短信需要的配置, 都配置在配置文件了 @Autowired private StringRedisTemplate redisTemplate; // 注入redisTemplate // 生产环境请求地址:app.cloopen.com private static final String serverIp = "app.cloopen.com"; // 请求端口 private static final String serverPort = "8883"; // 存入redis的前缀 private static final String KEY_PREFIX = "sms:phone:"; // 存活时间 1分钟 private static final long SMS_MIN_INTERVAL_IN_MILLIS = 60000; public void sendSms(String to, String templateId, String[] datas) { String redisKey = KEY_PREFIX + to; // TODO 按照手机号限流 // 先从redis中取出该值 String redisValue = redisTemplate.opsForValue().get(redisKey); if (StringUtils.isNotBlank(redisValue)) { // redis中有值 long lastTime = Long.valueOf(redisValue); if (System.currentTimeMillis() - lastTime < SMS_MIN_INTERVAL_IN_MILLIS) { log.info("[短信服务], 发送频率过高, 被拦截, 请稍后再试, 手机号码: {}", to); return; } } CCPRestSmsSDK sdk = new CCPRestSmsSDK(); sdk.init(serverIp, serverPort); sdk.setAccount(prop.getAccountSId(), prop.getAccountToken()); sdk.setAppId(prop.getAppId()); sdk.setBodyType(BodyType.Type_JSON); /** * to: 发送短信至手机号 * * templateId: 短信模板 * * datas: 这里模拟一下验证码123456,10分钟内到期 {"123456", "10"} */ HashMap<String, Object> result = sdk.sendTemplateSMS(to,templateId,datas); 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); } // 发送短信成功后, 写入redis, 指定生存时间1分钟 redisTemplate.opsForValue().set(redisKey, String.valueOf(System.currentTimeMillis()), 1, TimeUnit.MINUTES); log.info("[短信服务], 发送短信验证码, 手机号: {}", to); }else{ log.error("[短信服务] 发送短信失败 ", result.get("statusMsg")); //异常返回输出错误码和错误信息 System.out.println("错误码=" + result.get("statusCode") +" 错误信息= "+result.get("statusMsg")); } } }
测试
-
test
package com.leyou.test; import com.leyou.sms.LySmsApplication; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.HashMap; /** * @program: leyou * @description: * @author: Mr.Xiao * @create: 2020-07-01 14:03 **/ @RunWith(SpringRunner.class) @SpringBootTest(classes = LySmsApplication.class) public class test { @Autowired private AmqpTemplate amqpTemplate; @Test public void sendSms() { HashMap<String, String> map = new HashMap<>(); map.put("phone", "*********"); map.put("datas", "123456,1"); this.amqpTemplate.convertAndSend("ly.sms.exchange", "sms.verify.code", map); } }