首页 > 技术文章 > SpringCloud集成发送短信--容联云通讯--Redis

gmllxx 2020-07-01 17:03 原文

SpringCloud集成–容联云通讯–Redis

发送短信微服务

项目结构

在这里插入图片描述

配置文件

  1. 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>
    
  2. 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
    

启动类

  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

  1. 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

  1. 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

  1. 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"));
            }
        }
    
    }
    

测试

  1. 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);
        }
    
    }
    

推荐阅读