微信公众号发送模版消息

1.业务分析

该功能点类似于小助手,在每位同学上课的前一天发送需要上课的信息。

设置为每天18点向各位同学发送。

💡参考:Java 微信公众号消息推送(从零开始)_java微信公众号消息推送-CSDN博客

2.具体实现

首先,每位同学在使用考勤小程序时,登录会有一个请求wx授权,通过这个wx授权,可以拿到微信用户的唯一id(oppenid)。该项目,授权并将该oppenid写入对应的学生数据库已经实现,此处不做赘述。如需要获取参考上述链接。

每位同学授权后,那么就实现了学号与微信id的绑定。在后续中我们可以直接拿取每位学生的oppenid就发送给了对应的学生。

模版消息

在微信公众平台可以选好合适的消息模版:

其中详细内容中的{{time1.DATA}}就是后端需要填入的数据。

准备工作

整个过程操作需要几个必须参数appid(公众号id),secret(密钥)这两个在微信公众平台获取。这是发送消息所需的两个必要的外部条件,再加一个access_token

access_token是微信api最重要的一个部分,因为调用其他api很多都需要用到access_token。比如自定义菜单接口、客服接口、获取用户信息接口、用户分组接口、群发接口等在请求的时候都需要用到access_token。而这个access_token则需要我们自己发送请求获取。更多详情参考:java实现微信公众号的模板消息推送_java多线程发送微信模版消息-CSDN博客

获取access_Token代码:

/**
     * 获取accessToken 用于构建模板消息发送的url入参  此token有效期只有2小时 要存redis?
     * @throws Exception
     *
     */
    public String getAccessToken(String appId,String appSecret) throws Exception{
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ appId +"&secret=" + appSecret;
        String res = HttpUtil.get(url);
        JSONObject jsonObject = JSONObject.parseObject(res);
        String accessToken = jsonObject.getString("access_token");  // key : expires_in 为过期时间  为7200s 后续如果需要缓存 可能要用到
        System.out.println("accessToken:"+accessToken);
        return accessToken;
    }

该token有2小时有效期,每天上限2000个。当一个公众号提供多个服务时,各个服务调用都需要使用该token,所以必须将这个token进一步缓存等处理。此处暂时尚未开发其余api功能,暂时没有缓存。

控制层代码:

    @Scheduled(cron = "0 0 18 * * ?")
    @GetMapping("/sendMessage")
    public  void sendMessage() throws Exception {
        // 公众号的模板id(也有相应的接口可以查询到)
        String templateId = "dbxxxxx7W_ZgyxxxxxxxZtE-SoxxxxxxxxxxxSInrs";
        //先获取accessToken  此token有效期 2小时  但好像消息推送都只在6点推送其余时间貌似不需要推送 如果没有其他需要accessToken的功能 应该不需要缓存(上限2000个)
        //access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token TODO:如果后续还有别的功能也要 那么就需要缓存
        //即每天6点获取一次即可
        String accessToken = messageService.getAccessToken(appId, appSecret);
        Map<String,Object> paramap=new HashMap<>();
        List<SubscriptionMessage> messageList = messageService.sendMessage();

        //如果查出来是空 代表明天所有人都没课 直接结束方法 不用发送
        if (messageList.isEmpty()){
            return ;
        }

        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken;
//        上课时间
//        {{time1.DATA}}
//        课程名称
//        {{thing2.DATA}}
//        班级名称
//        {{thing4.DATA}}
//        上课老师
//        {{thing5.DATA}}
//        上课地点
//        {{thing6.DATA}}
        //模版消息封装
        RestTemplate restTemplate = new RestTemplate();
        //拼接base参数
        Map<String, Object> sendBody = new HashMap<>();
        for (SubscriptionMessage subscriptionMessage : messageList) {
            //此处key value需要和消息模版对应
    paramap.put("time1",new WeChatTemplateMsg(subscriptionMessage.getDate()));  //上课时间
    paramap.put("thing2",new WeChatTemplateMsg(subscriptionMessage.getCoursename())); //课程名称
    paramap.put("thing4",new WeChatTemplateMsg(subscriptionMessage.getCname())); //班级名称
    paramap.put("thing5",new WeChatTemplateMsg(subscriptionMessage.getNickname())); //上课老师
    paramap.put("thing6",new WeChatTemplateMsg(subscriptionMessage.getClassroom()));  //上课地点

            sendBody.put("touser", subscriptionMessage.getAppid());    // openId  发送给哪个用户  示例  oNTuVxxxxxxxxxxxnQ2v8EY
         //   sendBody.put("url", "www.baidu.com");         // 点击模板信息跳转地   TODO 换成小程序课表地址
            sendBody.put("data", paramap);                   // 模板参数
            sendBody.put("template_id", templateId);      // 模板Id
            //发送POST请求
            ResponseEntity<String> forEntity = restTemplate.postForEntity(url, sendBody, String.class);

            JSONObject jsonObject = JSONObject.parseObject(forEntity.getBody());

            String messageCode = jsonObject.getString("errcode");

            String msgId = jsonObject.getString("msgid");
            System.out.println("messageCode : " + messageCode + ", msgId: " +msgId);

            System.out.println(forEntity.getBody());

        }

3.踩坑

在测试时候发现内容没有发送过去,后找到问题:

这是对应模版每一个消息的封装,此处是以为结构是 key:time value: String 即可。后发现内容为空,

没修改前

            paramap.put("time1",subscriptionMessage.getDate());
            paramap.put("thing2",subscriptionMessage.getCoursename());
            paramap.put("thing4",subscriptionMessage.getCname());
            paramap.put("thing5",subscriptionMessage.getNickname());
            paramap.put("thing6",subscriptionMessage.getClassroom());

后搜索查到发送的数据格式是这样的。

{"touser":"ogxxxxxxLxxxxxG46xxs","template_id":"1xxxxxs86_x5xxxxxxZSATUPSxxxxxxekk","data":{"first":{"value":"sadasd","color":"#333"},"keyword1":{"value":"keyworasd1","color":"#333"},"keyword2":{"value":"asd","color":"#333"},"keyword3":{"value":"keywoasdrd3","color":"#333"},"keyword4":{"value":"keywoasdrd4","color":"#333"},"keyword5":{"value":"ad","color":"#333"},"remark":{"value":"keyworasdd6","color":"#333"}}}

这个地方的这个值要么是一个map要么就是一个设置好value字段的对象,而不是直接把一个结果字符串传过去。

那么就定义一个字段类,其中这个value值就是我们所需要的内容字段。

模版消息字段DTO:

@Data
public class WeChatTemplateMsg {

    /**
     * 消息
     */
    private String value;
    /**
     * 消息颜色
     */
    private String color;


    public WeChatTemplateMsg(String value) {
        this.value = value;
        this.color = "#173177";
    }

    public WeChatTemplateMsg(String value, String color) {
        this.value = value;
        this.color = color;
    }

}

修正过后:可以正常显示:

paramap.put("time1",new WeChatTemplateMsg(subscriptionMessage.getDate())); 
paramap.put("thing2",new WeChatTemplateMsg(subscriptionMessage.getCoursename()));
paramap.put("thing4",new WeChatTemplateMsg(subscriptionMessage.getCname())); 
paramap.put("thing5",new WeChatTemplateMsg(subscriptionMessage.getNickname())); 
paramap.put("thing6",new WeChatTemplateMsg(subscriptionMessage.getClassroom()));  

  • 25
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值