阿里大于发送短信(用户微服务--消息微服务)

阿里大于官网

  1. 官网流程文档:

    https://help.aliyun.com/document_detail/55284.html?spm=a2c4g.11186623.6.567.77f914d1QWnwjX

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-85JBDKAv-1656147205975)(/Users/xiaoge/Downloads/assests/image-20220625163030313.png)]

    1. 登录阿里大于: https://dayu.aliyun.com/

    2. 去短信服务

      https://dysms.console.aliyun.com/dysms.htm?spm=5176.12818093.0.ddysms.6eac16d0SKkGSC#/domestic/text/template

      在这里插入图片描述

    3. 设置签名模板(需要审核)

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q8SDGszf-1656147205980)(/Users/xiaoge/Downloads/assests/image-20220625163303504.png)]

    4. 拿到 AccessKey

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eozsw9jY-1656147205980)(/Users/xiaoge/Downloads/assests/image-20220625163329165.png)]
      在这里插入图片描述

    5. 申请短信模板 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d9LeHR5N-1656147205983)(/Users/xiaoge/Downloads/assests/image-20220625163405349.png)]

    6. 总结需要的东西
      短信签名,短信模板 id,AccessKey,AccessKey Secret,version(版本信息,有点坑), Action(SendSms)关键的还有一个 jar 包(依赖)

    用户微服务

    1. pom.xml(需要用到消息微服务的api----因为AliSmsModel类在消息api中)

      <dependency>
        <groupId>com.xiaoge</groupId>
        <artifactId>message-api</artifactId>
        <version>1.0-SNAPSHOT</version>
       </dependency>
      
    2. RedisCacheConfig(有这个配置启动类上必须加@EnableCaching注解, 把缓存叫给redis, 用redis客户端查看也不会乱码)

      package com.xiaoge.config;
      
      import org.springframework.boot.autoconfigure.cache.CacheProperties;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.data.redis.cache.RedisCacheConfiguration;
      import org.springframework.data.redis.serializer.RedisSerializationContext;
      import org.springframework.data.redis.serializer.RedisSerializer;
      
      @Configuration
      public class RedisCacheConfig {
      
          //使用了cache的注解,需要手动设置序列化
          private CacheProperties cacheProperties;
      
          /**
           * 该配置类被构造时,它里面的参数,将有Spring 的ioc 容器提供
           *
           * @param cacheProperties
           */
          public RedisCacheConfig(CacheProperties cacheProperties) {
              this.cacheProperties = cacheProperties;
          }
      
      
          /**
           * 定义Redis缓存的序列化的形式
           * 在这个RedisSerializer类里面提交了3 种常用的序列化形式
           * 1 java  jdk的序列化 (默认的形式)
           * 2 json  jackson (我们可以手动切换)
           * 3 String String的序列化(主要用在字符串的存储,不是对象) 对key 一般使用的是String的序列化
           */
          @Bean
          public RedisCacheConfiguration redisCacheConfiguration() {
              CacheProperties.Redis redisProperties = this.cacheProperties.getRedis();
              RedisCacheConfiguration config = RedisCacheConfiguration
                      .defaultCacheConfig();
      
              config = config.serializeValuesWith(
                      RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
              // 缓存的过期时间,一般我们在配置文件里面设置
              if (redisProperties.getTimeToLive() != null) {
                  config = config.entryTtl(redisProperties.getTimeToLive());
              }
              // 是否给缓存添加前缀
              if (redisProperties.getKeyPrefix() != null) {
                  config = config.prefixKeysWith(redisProperties.getKeyPrefix());
              }
              // 空值的缓存
              if (!redisProperties.isCacheNullValues()) {
                  config = config.disableCachingNullValues();
              }
              //禁用key
              if (!redisProperties.isUseKeyPrefix()) {
                  config = config.disableKeyPrefix();
              }
              return config;
          }
      }
      
    3. 启动类

      @SpringBootApplication
      @EnableEurekaClient
      @EnableCaching
      public class MemberServiceApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(MemberServiceApplication.class, args);
          }
      }
      
      
    4. UserController

      package com.xiaoge.controller;
      
      import com.xiaoge.domain.User;
      import com.xiaoge.domain.UserCollection;
      import com.xiaoge.service.UserCollectionService;
      import com.xiaoge.service.UserService;
      import io.swagger.annotations.Api;
      import io.swagger.annotations.ApiImplicitParam;
      import io.swagger.annotations.ApiImplicitParams;
      import io.swagger.annotations.ApiOperation;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.http.ResponseEntity;
      import org.springframework.security.core.context.SecurityContextHolder;
      import org.springframework.web.bind.annotation.*;
      
      import java.util.Map;
      
      /**
       * @Classname UserController
       * @Date 2022/6/6 下午8:23
       * @Created by xiaoge
       * @Description TODO
       */
      @Api(tags = "前台用户管理接口")
      @RestController
      @RequestMapping
      public class UserController {
      
          @Autowired
          private UserService userService;
      
      
          @ApiImplicitParams({
                  @ApiImplicitParam(name = "phoneNum", value = "用户手机号, 验证码")
          })
          @ApiOperation("修改用户信息")
          @PostMapping("p/sms/send")
          public ResponseEntity<Void> bindPhoneNum(@RequestBody Map<String, String> phoneNum) {
              String openId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
              userService.bindPhoneNum(openId, phoneNum);
              return ResponseEntity.ok().build();
          }
      
      
      
      }
      
      
    5. UserService

      package com.xiaoge.service;
      
      import com.baomidou.mybatisplus.extension.service.IService;
      import com.xiaoge.domain.User;
      
      import java.util.Map;
      
      /**
      * @Classname UserService
      * @Date 2022/6/6 下午7:00
      * @Created by xiaoge
      * @Description TODO
      */
      public interface UserService extends IService<User>{
      
      
          /**
           * 用户绑定手机号
           * @param openId
           * @param phoneNum
           */
          Boolean bindPhoneNum(String openId, Map<String, String> phoneNum);
      }
      
      
    6. UserServiceImpl

    7. package com.xiaoge.service.impl;
      
      import com.alibaba.fastjson.JSON;
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.xiaoge.constant.QueueConstant;
      import com.xiaoge.domain.User;
      import com.xiaoge.mapper.UserMapper;
      import com.xiaoge.model.AliSmsModel;
      import com.xiaoge.service.UserService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.amqp.rabbit.core.RabbitTemplate;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      
      import java.time.Duration;
      import java.util.HashMap;
      import java.util.Map;
      
      /**
       * @Classname UserServiceImpl
       * @Date 2022/6/6 下午7:00
       * @Created by xiaoge
       * @Description TODO
       */
      @Slf4j
      @Service
      public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{
      
          @Autowired
          private RabbitTemplate rabbitTemplate;
      
          @Autowired
          private RedisTemplate redisTemplate;
      
          /**
           * 用户绑定手机号
           * 1. 生成一个code
           * 2. 放在redis
           * 3. 设置一个过期时间 5min
           * 4. 组装参数
           * 5. 放入mq
           * 6. 返回
           * @param openId
           * @param phoneNum
           */
          @Override
          public Boolean bindPhoneNum(String openId, Map<String, String> phoneNum) {
              String phonenum = phoneNum.get("phonenum");
      
              // 生成验证码
              String code = createCode();
      
              // 放入redis
              redisTemplate.opsForValue().set(phonenum, code, Duration.ofMinutes(5));
      
              // 组装参数 放mq 短信的签名 短信的模板,短信的code
              AliSmsModel aliSmsModel = new AliSmsModel();
              aliSmsModel.setPhoneNumbers(phonenum);
              aliSmsModel.setSignName("ego商城");
              aliSmsModel.setTemplateCode("SMS_203185255");
              Map<String, String> map = new HashMap<>(2);
              map.put("code", code);
              aliSmsModel.setTemplateParam(JSON.toJSONString(map));
      
              // 发送消息
              rabbitTemplate.convertAndSend(QueueConstant.PHONE_CHANGE_EX, QueueConstant.PHONE_CHANGE_KEY, JSON.toJSONString(aliSmsModel));
      
              return true;
          }
      
      
          /**
           * 生成验证码
           * @return
           */
          private String createCode() {
              // 位数 4  6  8多一点
              // 随机生成验证码
              return "88888888";
          }
      }
      
      

    消息微服务

    1. message-api中模型类 用户微服务用到了该模型类

      package com.whsxt.model;
      
      import io.swagger.annotations.ApiModel;
      import io.swagger.annotations.ApiModelProperty;
      import lombok.AllArgsConstructor;
      import lombok.Builder;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      
      
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      @Builder
      @ApiModel("发送阿里大于短信的实体类")
      public class AliSmsModel {
      
          @ApiModelProperty("手机号")
          private String phoneNumbers;
      
          @ApiModelProperty("签名")
          private String signName;
      
          @ApiModelProperty("模板id")
          private String templateCode;
      
          @ApiModelProperty("参数")
          private String templateParam;
      
          @ApiModelProperty("短信扩展码")
          private String smsUpExtendCode;
      
          @ApiModelProperty("外部流水扩展字段")
          private String outId;
      
      }
      
      
    2. pom.xml

        <dependency>
          <groupId>com.aliyun</groupId>
          <artifactId>aliyun-java-sdk-core</artifactId>
          <version>4.0.6</version> <!-- 注:如提示报错,先升级基础包版,无法解决可联系技术支持 -->
         </dependency>
      
    3. RabbitMQConfig(发送短信mq配置 PHONE_CHANGE_QUEUE都是自己随便定义的常量值)

      package com.xiaoge.config;
      
      import com.xiaoge.constant.QueueConstant;
      import org.springframework.amqp.core.Binding;
      import org.springframework.amqp.core.BindingBuilder;
      import org.springframework.amqp.core.DirectExchange;
      import org.springframework.amqp.core.Queue;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      /**
       * @Classname RabbitMQConfig
       * @Date 2022/6/25 下午2:56
       * @Created by xiaoge
       * @Description TODO
       */
      @Configuration
      public class RabbitMQConfig {
      
      
          /*  短信mq配置  */
          @Bean
          public Queue phoneChangeQueue() {
              return new Queue(QueueConstant.PHONE_CHANGE_QUEUE);
          }
      
      
          @Bean
          public DirectExchange phoneChangeExchange() {
              return new DirectExchange(QueueConstant.PHONE_CHANGE_EX);
          }
      
          @Bean
          public Binding bind() {
              return BindingBuilder
                      .bind(phoneChangeQueue())
                      .to(phoneChangeExchange())
                      .with(QueueConstant.PHONE_CHANGE_KEY);
          }
      
      }
      
      
    4. application.yml

      # 阿里大于短信模版
      sms:
        region-id: cn-hangzhou
        access-key-id: LTAIkRdZIaLMBGKw
        access-secret: ZPuDXJKxZ0ZNndDXlWkO8WAcZK26n7
        sys-domain: dysmsapi.aliyuncs.com
        version: 2017-05-25
      
    5. SmsProperties

      package com.xiaoge.config;
      
      import lombok.Data;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      
      /**
       * @Classname Sms
       * @Date 2022/6/25 下午3:56
       * @Created by xiaoge
       * @Description TODO
       */
      @Data
      @ConfigurationProperties(prefix = "sms")
      public class SmsProperties {
      
          private String regionId;
      
          private String accessKeyId;
      
          private String accessSecret;
      
          private String version;
      
      }
      
    6. SmsAutoConfiguration

      package com.xiaoge.config;
      
      import com.aliyuncs.DefaultAcsClient;
      import com.aliyuncs.IAcsClient;
      import com.aliyuncs.profile.DefaultProfile;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.context.properties.EnableConfigurationProperties;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      /**
       * @Classname SmsAutoConfiguration
       * @Date 2022/6/25 下午4:00
       * @Created by xiaoge
       * @Description TODO
       */
      @Configuration
      @EnableConfigurationProperties(value = SmsProperties.class)
      public class SmsAutoConfiguration {
      
          @Autowired
          private SmsProperties smsProperties;
      
      
          /**
           * 初始化阿里的客户端
           * 阿里的不是直接给一个url 你直接请求就可以
           * 他是需要你自己写一个客户端的配置
           * 你自己调用客户客户端的配置来发请求
           *
           * @return
           */
          @Bean
          public IAcsClient iAcsClient() {
              DefaultProfile profile = DefaultProfile.getProfile(smsProperties.getRegionId(),
                      smsProperties.getAccessKeyId(),
                      smsProperties.getAccessSecret()
              );
              IAcsClient acsClient = new DefaultAcsClient(profile);
              return acsClient;
          }
      
      }
      
      
    7. SmsListener(监听器, 并且发送短信)

      package com.xiaoge.listener;
      
      import com.alibaba.fastjson.JSON;
      import com.aliyuncs.CommonRequest;
      import com.aliyuncs.CommonResponse;
      import com.aliyuncs.IAcsClient;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.http.MethodType;
      import com.rabbitmq.client.Channel;
      import com.xiaoge.config.SmsProperties;
      import com.xiaoge.constant.QueueConstant;
      import com.xiaoge.model.AliSmsModel;
      import com.xiaoge.service.SmsLogService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.amqp.core.Message;
      import org.springframework.amqp.rabbit.annotation.RabbitListener;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Component;
      
      /**
       * @Classname SmsListener
       * @Date 2022/6/25 下午3:52
       * @Created by xiaoge
       * @Description TODO
       */
      @Component
      @Slf4j
      public class SmsListener {
      
          @Autowired
          private SmsProperties smsProperties;
      
          @Autowired
          private IAcsClient iAcsClient;
      
          @Autowired
          private SmsLogService smsLogService;
      
          /**
           * 短信监听  concurrency 线程数量3-5个
           */
          @RabbitListener(queues = QueueConstant.PHONE_CHANGE_QUEUE, concurrency = "3-5")
          public void smsHandler(Message message, Channel channel){
              // 拿到消息
              String msg = new String(message.getBody());
      
              // 需要发送的内容
              AliSmsModel aliSmsModel = JSON.parseObject(msg, AliSmsModel.class);
              // 发短信了
              try {
                  CommonResponse commonResponse = realSendMsg(aliSmsModel);
                  // 成功了
                  log.info("短信发送成功");
                  // 记录数据库
                  smsLogService.saveMsg(aliSmsModel, commonResponse);
      
                  // 签收
                  channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
              } catch (Exception e) {
                  log.error("发送短信失败");
              }
          }
      
      
          /**
           * 发送短信
           * @param aliSmsModel
           * @return
           */
          private CommonResponse realSendMsg(AliSmsModel aliSmsModel) throws ClientException {
              CommonRequest commonRequest = new CommonRequest();
              // 基本参数
              commonRequest.setVersion(smsProperties.getVersion());
              commonRequest.setMethod(MethodType.POST);
              commonRequest.setRegionId(smsProperties.getRegionId());
              commonRequest.setAction("SendSms");
              commonRequest.setDomain("dysmsapi.aliyuncs.com");
              // 给哪个手机号发
              commonRequest.putQueryParameter("PhoneNumbers", aliSmsModel.getPhoneNumbers());
              commonRequest.putQueryParameter("SignName", aliSmsModel.getSignName());
              commonRequest.putQueryParameter("TemplateCode", aliSmsModel.getTemplateCode());
              commonRequest.putQueryParameter("TemplateParam", aliSmsModel.getTemplateParam());
              // 发请求
              CommonResponse commonResponse = iAcsClient.getCommonResponse(commonRequest);
              System.out.println(commonResponse.getData());
              System.out.println(commonResponse.getHttpStatus());
              return commonResponse;
          }
      
      
      }
      
      
    8. SmsLogService

      package com.xiaoge.service;
      
      import com.aliyuncs.CommonResponse;
      import com.baomidou.mybatisplus.extension.service.IService;
      import com.xiaoge.domain.SmsLog;
      import com.xiaoge.model.AliSmsModel;
      
      /**
      * @Classname SmsLogService
      * @Date 2022/6/25 下午3:19
      * @Created by xiaoge
      * @Description TODO
      */
      public interface SmsLogService extends IService<SmsLog>{
      
      
          /**
           * 把短信信息保存进数据库
           * @param aliSmsModel
           * @param commonResponse
           */
          void saveMsg(AliSmsModel aliSmsModel, CommonResponse commonResponse);
      
      }
      
    9. SmsLogServiceImpl(保存发送过的短信到数据库)

      package com.xiaoge.service.impl;
      
      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.JSONObject;
      import com.aliyuncs.CommonResponse;
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.xiaoge.domain.SmsLog;
      import com.xiaoge.mapper.SmsLogMapper;
      import com.xiaoge.model.AliSmsModel;
      import com.xiaoge.service.SmsLogService;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.Date;
      
      /**
       * @Classname SmsLogServiceImpl
       * @Date 2022/6/25 下午3:19
       * @Created by xiaoge
       * @Description TODO
       */
      @Service
      public class SmsLogServiceImpl extends ServiceImpl<SmsLogMapper, SmsLog> implements SmsLogService{
      
          @Autowired
          private SmsLogMapper smsLogMapper;
      
          /**
           * 把短信信息保存进数据库
           *
           * @param aliSmsModel
           * @param commonResponse
           */
          @Override
          public void saveMsg(AliSmsModel aliSmsModel, CommonResponse commonResponse) {
              String phoneNumbers = aliSmsModel.getPhoneNumbers();
              String templateParam = aliSmsModel.getTemplateParam();
              JSONObject jsonObject = JSON.parseObject(templateParam);
              String code = jsonObject.getString("code");
              SmsLog smsLog = new SmsLog();
              smsLog.setUserPhone(phoneNumbers);
              smsLog.setContent("尊敬的用户,您的注册会员动态密码为:" + code + ",请勿泄漏于他人!");
              smsLog.setMobileCode(code);
              smsLog.setRecDate(new Date());
              String data = commonResponse.getData();
              JSONObject jsonObject1 = JSON.parseObject(data);
              String code1 = jsonObject1.getString("Code");
              smsLog.setResponseCode(String.valueOf(commonResponse.getHttpStatus()));
              if (code1.equals("OK")) {
                  smsLog.setStatus(1);
              } else {
                  smsLog.setStatus(0);
              }
              smsLog.setType(2);
              // 插入数据库
              smsLogMapper.insert(smsLog);
          }
      }
      
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只因为你温柔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值