• 公纵号发送提示信息(用户微服务--消息微服务)


    公纵号发送提示信息(用户微服务–消息微服务)

    1. 微信消息的集成(微信公众号)

      场景:主要用于商城购买提示,金额提醒,活动广告等

    2. 申请微信测试号(和微信小程序有区别)

      https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

    3. 拿到信息
      在这里插入图片描述

    4. 查看具体文档
      在这里插入图片描述

    5. 获取 access_token(这里区别其他的 token)

      本质就是发送一个请求
      在这里插入图片描述

    6. 发送消息模板文档
      在这里插入图片描述
      在这里插入图片描述

    7. 消息模板
      在这里插入图片描述
      在这里插入图片描述

    8. 拿到模板 ID
      在这里插入图片描述

    9. 总结需要的东西

      appID,appsecret,模板 ID
      流程:
      1.根据 appid 和 appsecret 拿到 access_token

      ​ 2.发一个请求(请求中包含模板内容,access_token)

    用户微服务

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

      <dependency>
        <groupId>com.xiaoge</groupId>
        <artifactId>message-api</artifactId>
        <version>1.0-SNAPSHOT</version>
       </dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    2. 启动类

      @SpringBootApplication
      @EnableEurekaClient
      public class MemberServiceApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(MemberServiceApplication.class, args);
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    3. UserController

      package com.xiaoge.controller;
      
      import com.alibaba.fastjson.JSON;
      import com.xiaoge.constant.QueueConstant;
      import com.xiaoge.domain.User;
      import com.xiaoge.domain.UserCollection;
      import com.xiaoge.model.WxMsgModel;
      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.amqp.rabbit.core.RabbitTemplate;
      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.time.LocalDateTime;
      import java.util.HashMap;
      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;
      
          @Autowired
          private RabbitTemplate rabbitTemplate;
      
          @PostMapping("p/sms/wxSend")
          @ApiOperation("测试发送微信公众号消息")
          public ResponseEntity<String> wxSend(String openId, String name) {
              // 构建一个对象
              WxMsgModel wxMsgModel = new WxMsgModel();
              wxMsgModel.setToUser(openId);
              // 公纵号用户点击信息时去往地址
              wxMsgModel.setUrl("https://www.baidu.com");
              // 模版id
              wxMsgModel.setTemplateId("XIL5vtqbdBZbejJ2xfXv-cqXxLni9RzjG32Qjpg_OoY");
              // 头颜色
              wxMsgModel.setTopColor("#FF0000");
              HashMap<String, Map<String, String>> data = new HashMap<>();
              data.put("userName", WxMsgModel.buildMap(name, "#FF0000"));
              data.put("time", WxMsgModel.buildMap(LocalDateTime.now().toString(), "#FF0000"));
              data.put("product", WxMsgModel.buildMap("女朋友", "#FF0000"));
              data.put("money", WxMsgModel.buildMap("0.1", "#FF0000"));
              wxMsgModel.setData(data);
      
              // 用mq发消息
              rabbitTemplate.convertAndSend(QueueConstant.WX_CHANGE_EX, QueueConstant.WX_CHANGE_KEY, JSON.toJSONString(wxMsgModel));
      
              return ResponseEntity.ok("发送成功");
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66

    消息微服务

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

      package com.xiaoge.model;
      
      import com.fasterxml.jackson.annotation.JsonProperty;
      import lombok.AllArgsConstructor;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      
      import java.util.HashMap;
      import java.util.Map;
      
      
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class WxMsgModel {
      
      
          @JsonProperty(value = "touser")
          private String toUser;
      
          @JsonProperty(value = "template_id")
          private String templateId;
      
          @JsonProperty(value = "url")
          private String url;
      
          @JsonProperty(value = "topcolor")
          private String topColor;
      
          @JsonProperty(value = "data")
          private Map<String, Map<String, String>> data;
      
          /**
           * 专门构建参数的
           *
           * @param value
           * @param color
           * @return
           */
          public static Map<String, String> buildMap(String value, String color) {
              HashMap<String, String> map = new HashMap<>();
              map.put("value", value);
              map.put("color", color);
              return map;
          }
      
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
    2. 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 wxChangeQueue() {
              return new Queue(QueueConstant.WX_CHANGE_QUEUE);
          }
      
      
          @Bean
          public DirectExchange wxChangeExchange() {
              return new DirectExchange(QueueConstant.WX_CHANGE_EX);
          }
      
          @Bean
          public Binding wxBind() {
              return BindingBuilder
                      .bind(wxChangeQueue())
                      .to(wxChangeExchange())
                      .with(QueueConstant.WX_CHANGE_KEY);
          }
      
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
    3. application.yml

      # 微信公纵号信息
      wechat:
        app-id: wx010a59592d9c7234
        app-secret: dd6508eb89c7509db542c4b8a0cb062e
        token-url: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s
        message-url: https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    4. WechatProperties

      package com.xiaoge.config;
      
      import io.swagger.annotations.ApiModelProperty;
      import lombok.Data;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      
      /**
       * @Classname WechatProperties
       * @Date 2022/6/25 下午5:31
       * @Created by xiaoge
       * @Description TODO
       */
      @Data
      @ConfigurationProperties(prefix = "wechat")
      public class WechatProperties {
      
          @ApiModelProperty("微信的应用的 id")
          private String appId;
      
          @ApiModelProperty("微信的密钥")
          private String appSecret;
      
          @ApiModelProperty("获取 Tokenurl 的地址")
          private String tokenUrl;
      
          @ApiModelProperty("发送微信模板消息的地址")
          private String messageUrl;
      
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
    5. WechatAutoConfiguration

      package com.xiaoge.config;
      
      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.JSONObject;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.context.properties.EnableConfigurationProperties;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.scheduling.annotation.Scheduled;
      import org.springframework.util.StringUtils;
      import org.springframework.web.client.RestTemplate;
      
      import javax.annotation.PostConstruct;
      
      /**
       * @Classname WechatAutoConfiguration
       * @Date 2022/6/25 下午5:32
       * @Created by xiaoge
       * @Description TODO
       */
      @Slf4j
      @Configuration
      @EnableConfigurationProperties(value = WechatProperties.class)
      public class WechatAutoConfiguration {
      
          @Autowired
          private RestTemplate restTemplate;
      
          @Autowired
          private WechatProperties wechatProperties;
      
          /**
           * volatile(jvm提供的轻量级的同步机制) 三大特性:
           *      1. 保证可见性
           *      2. 不保证原子性
           *      3. 禁止指令重排
           *
           *  1. 验证volatile的可见性
           *      1.1 假如int number = 0; number变量之前根本没有添加volatile关键字修饰, 没有可见性
           *      1.2 添加了volatile, 可以解决可见性问题.
           *
           *  2. 验证volatile不保证原子性
           *      2.1 原子性指的是什么意思?
           *          不可分割, 完整性, 也即某个线程正在做某个具体业务时, 中间不可以被加塞或者被分割, 需要整体完整
           *          要么同时成功, 要么同时失败.
           *
           *      2.2 volatile不保证原子性 案例演示
           *
           *         number ++ 在多线程下是非线程安全的, 如何不加synchronized解决?
           *
           *      2.3 why?
           *          因为在线程自己工作内存写回主内存的时候, 太快了, 通知其他线程还没到, 其他线程也直接写回主内存了, 所以少于20000次, 所以出现写丢的情况.
           *
           *      2.4 如何解决原子性?
           *          * 加synchronized
           *          * 使用我们的juc 下 AtomicInteger
           *
           */
          //因为我们需要定时刷新 token,为了让其他线程可以看到,我们使用 volatile 来修饰
          private volatile String accessToken;
      
      
          /**
           * 这个spring实现了这个注解的规范
           * 所有的bean对象创建完以后执行, 在项目启动完全之前执行
           * 限制 不能有返回值, 也不能有参数
           *
           * 因为消费者直接监听者生产者,
           * 当消费者挂了以后,
           * 在次启动时他会直接消费,
           * 但是这时候token是没有获取到的,
           * 这要会报尖token, 所以要在这里加这个注解
           */
          @PostConstruct
          public void tokenInit() {
              refushToken();
          }
      
          /**
           * 刷新 token 的方法 两个小时以内获取一次
           * initialDelay项目启动完后执行, 所以才会导致token失效, 因为消费者和他是同时执行的
           */
          @Scheduled(initialDelay = 7100 * 1000, fixedRate = 7100 * 1000)
          public void refushToken() {
              String tokenUrl = String.format(wechatProperties.getTokenUrl(),
                      wechatProperties.getAppId(),
                      wechatProperties.getAppSecret());
      
              String jsonStr = restTemplate.getForObject(tokenUrl, String.class);
      
              JSONObject jsonObject = JSON.parseObject(jsonStr);
      
              String accessToken = jsonObject.getString("access_token");
      
              if (!StringUtils.isEmpty(accessToken)) {
                  log.info("token 获取成功");
                  this.accessToken = accessToken;
                  return;
              }
      
              log.error("token 获取失败");
          }
      
      
          public String getAccessToken() {
              return this.accessToken;
          }
      
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
    6. WechatListener(监听器, 并且发送提示信息)

      package com.xiaoge.listener;
      
      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.JSONObject;
      import com.rabbitmq.client.Channel;
      import com.xiaoge.config.WechatAutoConfiguration;
      import com.xiaoge.config.WechatProperties;
      import com.xiaoge.constant.QueueConstant;
      import com.xiaoge.model.WxMsgModel;
      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.amqp.support.AmqpHeaders;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.messaging.handler.annotation.Header;
      import org.springframework.stereotype.Component;
      import org.springframework.web.client.RestTemplate;
      
      import java.io.IOException;
      
      /**
       * @Classname WechatListener
       * @Date 2022/6/25 下午5:46
       * @Created by xiaoge
       * @Description TODO
       */
      @Slf4j
      @Component
      public class WechatListener {
      
          @Autowired
          private WechatProperties wechatProperties;
      
          @Autowired
          private WechatAutoConfiguration wechatAutoConfiguration;
      
          @Autowired
          private SmsLogService smsLogService;
      
          @Autowired
          private RestTemplate restTemplate;
      
          @RabbitListener(queues = QueueConstant.WX_CHANGE_QUEUE, concurrency = "3-5")
          public void handlerWechatMessage(Channel channel, Message message) {
              String wxStr = new String(message.getBody());
      
              // 拿到消息
              WxMsgModel wxMsgModel = JSON.parseObject(wxStr, WxMsgModel.class);
      
              // 发型微信公纵号消息
              realSendWxMsg(wxMsgModel);
      
              smsLogService.saveWxMsg(wxMsgModel);
      
              try {
                  // 签收消息
                  channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
              } catch (IOException e) {
                  log.error("签收失败!");
              }
          }
      
      
          /**
           * 真正发微信消息的方法
           * 发送微信公纵号信息
           * @param wxMsgModel
           */
          private void realSendWxMsg(WxMsgModel wxMsgModel) {
              // 发送公纵号信息的url
              String messageUrl =  String.format(wechatProperties.getMessageUrl(),
                      wechatAutoConfiguration.getAccessToken());
      
              // 发送消息
              String result = restTemplate.postForObject(messageUrl, wxMsgModel, String.class);
      
              System.out.println(result);
          }
      
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
    7. 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;
      import com.xiaoge.model.WxMsgModel;
      
      /**
      * @Classname SmsLogService
      * @Date 2022/6/25 下午3:19
      * @Created by xiaoge
      * @Description TODO
      */
      public interface SmsLogService extends IService<SmsLog>{
          /**
           * 把wx信息保存进数据库
           * @param wxMsgModel
           */
          void saveWxMsg(WxMsgModel wxMsgModel);
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    8. 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.model.WxMsgModel;
      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;
      
          /**
           * 把wx信息保存进数据库
           *
           * @param wxMsgModel
           */
          @Override
          public void saveWxMsg(WxMsgModel wxMsgModel) {
              SmsLog smsLog = new SmsLog();
              smsLog.setContent("发微信消息成功");
              smsLog.setUserId(wxMsgModel.getToUser());
              smsLog.setResponseCode("200");
              smsLog.setRecDate(new Date());
              smsLog.setStatus(0);
              smsLog.setType(2);
              // 插入数据库
              smsLogMapper.insert(smsLog);
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47

    Postman测试

    在这里插入图片描述
    在这里插入图片描述
    打开微信小程序, 随便一个请求都带着token, 拿过来就行了
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    【BOOST C++ 13 并行编程】(3) 线程本地存储
    【Html/Css】Https证书申请、安装和使用(新手IIS安装参考)
    oppo前端开发一面
    GienTech动态|入选软件和信息技术服务名牌企业;荣获城市数字化转型优秀案例;参加第四届深圳国际人工智能展
    MySQL事务
    软件测试|selenium执行js脚本
    ubuntu 定时发送邮件
    vue3验证码倒计时60秒(自用)
    java:application.properties的详细使用以及区分环境
    python小技巧:创建单链表及删除元素
  • 原文地址:https://blog.csdn.net/zsx1314lovezyf/article/details/125463066