实现微信小程序定时发送通知(1)发送请求篇

 引言 关于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实现多定时任务来实现定时的发送下班请求。

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
【资源说明】 基于微信小程序的疫苗预约接种系统源码+项目说明.zip 基于微信小程序的疫苗预约接种系统 对某疫苗预约系统重构后二次开发 系统管理员基本功能: (1)查看数据分析图; (2)接种点信息增删改查; (3)接种点医护人员信息增删改查; (4)预约计划信息增删改查; (5)接种者信息删改查; (6)疫苗信息增删改查; (7)接种者支付历史信息查询; (8)接种者预约历史信息查询; (9)接种者签到历史信息查询; (10)接种者预检历史信息查询; (11)接种者接种历史信息查询; (12)接种者留观历史信息查询; (13)账号密码修改; (14)登录登出。 接种者基本功能: (1)查看疫苗信息列表; (2)查看该疫苗对应的接种点信息列表; (3)查看该疫苗对应接种点的预约计划信息列表; (4)查看该疫苗对应接种点的预约计划信息并提交预约申请表单; (5)模拟支付疫苗单价; (6)查看接种二维码及其状态信息; (7)取消预约; (8)查看支付历史信息; (9)查看预约历史信息; (10)查看预检历史信息; (11)查看接种历史信息; (12)注册登录登出; (13)个人信息修改。 注:接种者需全部满足(1.预约日期在预约计划的日期范围之内;2.预约日期在以今天为基准的明天到预约计划结束日期之间;3.疫苗的可预约量要大于0;4.对应时间段疫苗的剩余量要大于0;5.没有未完成的预约任务。)五个条件后,才能支付疫苗单价完成疫苗预约。 医护人员基本功能: (1)签到信息登记; (2)预检信息登记; (3)接种信息登记; (4)留观信息登记; (5)签到信息登记历史查询; (6)预检信息登记历史查询; (7)接种信息登记历史查询; (8)留观信息登记历史查询; (9)登录登出; (10)个人信息修改。 注:接种者需要严格按照签到、预检、接种、留观四个步骤完成疫苗接种。签到成功后的接种流程不受时间影响。签到需满足(1.预约日期匹配;2.预约时间段匹配;3.预约接种点匹配)三个条件,才能签到成功。 系统启动后会自动运行SpringBoot定时任务,会在每天凌晨处理过期的预约任务和流程未正常结束的接种任务(0代表待签到、1代表待预检、2代表待接种、3代表留观中、4代表接种流程结束、5代表预约过期、6代表接种者取消预约、7代表接种过程异常)。 后端使用SpringMVC拦截器+jwt+自定义注解实现身份验证和权限控制。用户每次登录成功后,后端会返回token交由前端缓存,前端对后端相关接口发起的每次请求都需要携带该token进行验证。 系统使用二维码来充当接种者预约成功后的接种凭证,接种者需要在指定时间到指定地点,将二维码提供给相关医护人员扫描后完成接种流程。 系统在Service层同时操作多表修改时使用了注解式事务保证数据一致性。 本人主要从事Java后端开发,因此本系统的前端UI非常粗糙,只达到了“能用但不好用”的目的,很多参数的判断都直接交给了后端。 由于时间仓促,很多SQL语句的拼接都存在问题,但不影响初期使用。 微信小程序使用uniapp搭配uview-ui组件库进行开发,后台管理页面使用layui-admin进行开发。 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值