实现微信小程序定时发送通知(1)发送请求篇_微信小程序通知接口-程序员宅基地

技术标签: java  微信小程序  后端  

 引言 关于access_token

小程序发通知需要获取获取小程序全局唯一后台接口调用凭据(access_token)。调用绝大多数后台接口时都需使用 access_token,后面会进行使用redis的存取。

但是急于求成加上先去看了小马如何获取openId,打算使用前端发过来的code获取access_token,这确实是一个获取access_token的方法,照着这个去查找找到了微信小程序官网文档,按照里面的接口介绍,通过前端获取的code实现了获取。在此之间我并不知道access_token是会过期的,后面又了解到前端不能发起定时任务,在微信小程序官方文档中又看到了用AppID和AppSecret获取access_token

官方链接如下:auth.getAccessToken | 微信开放文档

于是我们可以在自己定义的定时任务中实现在需要发送消息通知之前的10秒内(时间上可以接近一点)获取,同时,除了可以用定时任务来自动更新access_token,access_token的有效期为2h,也需要弄一个报错之后可以调用的主动方法获取最新的access_token并存进redis中。

发送通知可参考参考官网文档:templateMessage.send | 微信开放文档

于是我们发现,小程序发送消息通知需要很多的组成,比如OpenId,access_token,template_id(模板id)等,于是我们可以将其封装为一个专门的类。

@Data
public class WxMssVo {
    //小程序用户的OpenId
    private String touser;
    //模板id
    private String template_id;
    //跳转首页
    private String page;
    //接口凭证
    private String access_token;
    //请求路径
    private String request_url;
    //放置数据
    private HashMap<String, Object> map = new HashMap<>(3);

}

用小程序的AppID和AppSecret获取access_token(一般有效期为2min,需要与后面的定时任务结合使用,实现不间断的刷新获取最新可用的access_token)。

 /**
     * 根据AppID和AppSecret获取最新可用的AccessToken
     * @return
     */
    public static String getAccessToken() throws IOException {
//        https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
        String appid = PropUtils.getProp("APPID");
        String appsecret = PropUtils.getProp("APPSECRET");

        //构建url,用于向微信服务器请求用户的openId
        StringBuffer url = new StringBuffer("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&");
        url.append("appid=").append(appid)
                .append("&secret=").append(appsecret);

        //向微信的服务器发送Get请求
        HttpClient client = HttpClientBuilder.create().build();
        HttpGet httpGet = new HttpGet(url.toString());
        HttpResponse httpResponse = client.execute(httpGet);
        HttpEntity result = httpResponse.getEntity();
        String resultStr = EntityUtils.toString(result);
        System.out.println(resultStr);
        JSONObject resultJsonObject = JSONUtil.parseObj(resultStr);
        String accessToken = (String) resultJsonObject.get("access_token");
        return accessToken;
    }

通过输出resultStr 可以得到一个{"access_token":"长字符串","expires_in":7200}的access_token信息

小程序的AppID和AppSecret在发布小程序的官方网页获取对应信息

这些都是不变的,我们可以将其存进resousce下的appconfig.properties

 通过书写一个PropUtil来获取

public class PropUtils {
    private static Properties properties;

    static {
        properties = new Properties();
    }

    public static String getProp(String key) throws IOException {
        //读取配置文件
        ClassPathResource classPathResource = new ClassPathResource("appconfig.properties");
        properties = PropertiesLoaderUtils.loadProperties(classPathResource);
        return properties.getProperty(key);
    }
}

发送模板信息

//发送模板消息
    public static String sendTemplateMessage(WxMssVo wxMssVo) {
        String info = "";
        try {
            //创建连接
            URL url = new URL(wxMssVo.getRequest_url());
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestProperty("Content-Type", "utf-8");
            connection.connect();

            //POST请求
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            JSONObject obj = new JSONObject();

            //设置参数
            //不可缺失 缺失会出现invalid openid rid
            //putOpt 等效于当两个参数都为非空时;除此之外什么都不做。put(name, value)
            obj.putOpt("touser", wxMssVo.getTouser());
          //不可缺失 缺失出现invalid template_id
            obj.putOpt("template_id", wxMssVo.getTemplate_id());
            obj.putOpt("page", wxMssVo.getPage());

            JSONObject jsonObject = new JSONObject();

            //发送自定义数据
            Set<Map.Entry<String, Object>> entries = wxMssVo.getMap().entrySet();

            for (Map.Entry<String, Object>entry:entries){

                JSONObject dataInfo = new JSONObject();
                dataInfo.putOpt("value", entry.getValue());
                jsonObject.putOpt(entry.getKey(), dataInfo);
            }
            obj.putOpt("data", jsonObject);

            System.out.println(obj.toString());
            out.write(obj.toString().getBytes());
            out.flush();
            out.close();

            //读取响应
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String lines;
            StringBuffer sb = new StringBuffer("");
            while ((lines = reader.readLine()) != null) {
                lines = new String(lines.getBytes(), "utf-8");
                sb.append(lines);
            }
            info = sb.toString();
            System.out.println(sb);
            reader.close();
            // 断开连接
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return info;
    }

创建测试类

  @Test
    public void publishModelMessage(){
        WxMssVo wxMssVo = new WxMssVo();
        //设置模板id
        wxMssVo.setTemplate_id("");
        String accessToken=null;
        try {
            //设置openId
            wxMssVo.setTouser("");
//            设置accessToken
            accessToken=WXUtils.getAccessToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
//        设置小程序 跳转首页
        wxMssVo.setPage("pages/index/index");

        wxMssVo.setRequest_url("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken);
//        将模板中的值一一赋值 发送到小程序的数据要转化为json格式 可以使用下面的方法直接拼接成JSONObject
      /*  JSONObject jsonObject = new JSONObject();
        JSONObject dataInfo = new JSONObject();
        dataInfo.putOpt("value", TimeUtils.getNowTime());
        jsonObject.putOpt("time5", dataInfo);
*/
//        使用map结合模板 后续再加遍历拼接成JSONObject
        HashMap<String, Object> map = new HashMap<>(3);
        //根据模板写值  
        map.put("time",TimeUtils.getNowTime());
        map.put("thing1","下班打卡");
        wxMssVo.setMap(map);
        WXUtils.sendTemplateMessage(wxMssVo);
    }

发送请求

没有权限用户,返回错误,需要每一次都设置权限(企业版才不需要)比较容易出现

小程序发送通知需要传递json数据,订阅号的模板对于每⼀个字段的类型都有特别要求,例如这个模板中的“通知”字段是叫time5.DATA,那么你在后端调取微信的时候也必须使用这个名字,而且对于类型也有一定的限制。

首先,我们看看小程序模板大概的样子

这时,我们就需要设置成data->time5->value(替换为值)这样的json格式传值。

传值之后容易出现数据不合法,需要参考参数值内容限制说明

 参数类别  参数说明              参数值限制    说明
  thing.DATA    事务            20个以内字符   可汉字、数字、字母或符号组合
number.DATA    数字            32位以内数字       只能数字,可带小数
 letter.DATA    字母             32位以内字母                只能字母
 symbol.DATA     符号               5位以内符号                只能符号
 character_string.DATA    字符串     32位以内数字、字母或符号    可数字、字母或符号组合
 time.DATA    时间   24小时制时间格式(可以为年月日),支持时间段;两个时间点之间用~连接 (如2022-09-27 19:31:28或19:38)
date.DATA     日期   年月日格式(支持加24小时制时间和时间段),两个时间点之间用~连接     如2022年9月27日,2022年9月27日 19:31
amount.DATA     金额 一个货币符号+10位以内纯数字,可带小数,结尾可带元  ¥8.8
phone_number.DATA    电话号码    17位以内数字、符号

如11122223333,+86-1111-11111111

car_number.DATA  车牌  8位以内,第一位与最后一位可为汉字,其余为字母或数字 车牌号 :如粤A8888Z桂
name.DATA  姓名  10字以内纯汉字或20个以内纯字母或符号 小明
phrase.DATA 汉字 5个字以内汉字  点赞的都帅

成功结果

 

 

总结

在实现不同外部接口的调用时,应多去看相对应的使用文档,积极搜索相同需求下不同的实现方法,再搭配上业务需求,实现特定功能。下期将更新基于SchedulingConfigurer实现多定时任务来实现定时的发送下班请求。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_63546281/article/details/127062809

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;stdlib.h&gt;#include&lt;malloc.h&gt;#include&lt;iostream&gt;#include&lt;stack&gt;#include&lt;queue&gt;using namespace std;typed_二叉树的建立

推荐文章

热门文章

相关标签