管理系统必备技(11): 对接公众号发送定期提醒通知

1,876 阅读5分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

前言

现在需要通过公众号对用户进行发送值班提醒和巡检提醒的通知。

提醒的内容分为三种:

  • 值班提醒
  • 厂区巡检提醒
  • 高压区巡检提醒

一、提醒模板设计

1.1 添加模板

添加模板的前提是必须是认证过的公众号。目前在广告与服务->模板消息 中可以获取到。下面是我从模板库中添加的。

image-20211104134154910

然后发送模板消息即可。

模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息。

关于使用规则,请注意:

  1. 所有服务号都可以在功能->添加功能插件处看到申请模板消息功能的入口,但只有认证后的服务号才可以申请模板消息的使用权限并获得该权限;
  2. 需要选择公众账号服务所处的2个行业,每月可更改1次所选行业;
  3. 在所选择行业的模板库中选用已有的模板进行调用;
  4. 每个账号可以同时使用25个模板。
  5. 当前每个账号的模板消息的日调用上限为10万次,单个模板没有特殊限制。【2014年11月18日将接口调用频率从默认的日1万次提升为日10万次,可在MP登录后的开发者中心查看】。当账号粉丝数超过10W/100W/1000W时,模板消息的日调用上限会相应提升,以公众号MP后台开发者中心页面中标明的数字为准。

找到适合自己的模板,然后传入模板id即可。以该模板为例测试:

image-20211104135008707

1.2 发送模板消息

发送模板消息据我了解到可以有两种方式:

  • 公众号的 openId 传入发送模板消息

    TEMPLATE_ENUM_SEND("发送模板消息", "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"),
    
  • 小程序的 openId 传入发送模板消息。(前提是要通过微信开放平台绑定公众号和小程序)

    UNIFORM_ENUM_SEND("发送统一模板消息", "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=%s"),
    

区别就是 公众号的 openid 和小程序的 openid 是不一致的,如果公众号仅仅用作小程序的辅助通知的话,可以只维护 小程序的 openid 到数据库中,通过它发送统一服务消息即可;如果更细致点,想维护公众号openid 的话,就可以采用 采用默认的发送方式。在两种都试过后,为了程序的可扩展性,选择了第二种做法。

1.3 发送代码测试

1、首先获取公众号的 accesstoken。公众号的服务是必须要在公网下才能获取,所以比较坑,得先部署个服务到公网环境下。

2、组织好数据,例如下面的这种JSON 体发送模板消息即可(私密信息已隐去)。

{
    "token": "token",
    "data":{
        "touser": "touser",
        "template_id": "template_id",
        "miniprogram":{
                "appid":"appid",
                "pagepath": "pages/me/index"
         },
         "data":{
            "first":{
                "value":"明日巡检排班计划",
                "color":"#130c0e"
            },
            "keyword1":{
                "value": "平顶山电站",
                "color": "#130c0e"
            },
            "keyword2":{
                "value": "值班提醒",
                "color": "#130c0e"
            },
            "keyword3":{
                "value": "潇雷",
                "color": "#130c0e"
            },
           "remark":{
                "value": "亲,明天上午轮到您值班了,别忘记噢,辛苦了,么么哒!",
                "color": "#130c0e"
           }
        }
       
    }
}

最后效果如下:

image-20211104140728173

二、提醒计划设计

根据通知模板,需要制定提醒计划,例如通知时间和通知次数。

现在值班提醒初步设计是每天晚上8点提醒第一次,每天早上8点提醒第二次。同样的消息如果一天超过两次的话,个人觉得就会很反感。

为了可扩展性,应该设计个公众号通知表,在里面发送通知,添加两次巡检时间,然后在代码里面每隔一个小时去数据库中找一次,是否获取的值在这个时间端内,例如7.00-8.00 分这个时间端内有没有通知任务;如果有就发送,然后判断时刻2 的开关是否开启,如果开启了,取它的时刻2也做个判断是否在当前时间段内,再发送。时刻1 和时刻2 都必须是整点。当然可能也只需要发送一次,那就把时刻2 的开关关掉即可。

时刻1到了,就查询明天要值班的用户发消息。

时刻2到了,就查询今天要值班的用户发消息。

数据库表的设计如下:

CREATE TABLE `mp_notification_time` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `type` varchar(60) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '模板类型。例如:101代表值班提醒;201代表厂区巡检提醒;202代表高压区巡检提醒',
  `sys_id` bigint DEFAULT NULL COMMENT '电站id',
  `temp_id` varchar(120) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '模板id',
  `page` varchar(120) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '小程序跳转页面路径',
  `time_one` time DEFAULT NULL COMMENT '时刻1',
  `time_two` time DEFAULT NULL COMMENT '时刻2',
  `two_on` tinyint DEFAULT NULL COMMENT '时刻2是否开启。0:开启;1关闭',
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  `delete_flag` tinyint DEFAULT NULL COMMENT '0正常 1删除',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

定时任务每一小时去执行一次,如果判断在这小时内有巡检任务就发送,判断时间方法可以用下面这:

    /**
     * 判断当前时间是否在[startTime, endTime]区间,注意时间格式要一致
     *
     * @param nowTime 当前时间
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return
     * @author jqlin
     */
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime.getTime() == startTime.getTime()
                || nowTime.getTime() == endTime.getTime()) {
            return true;
        }
        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        if (date.after(begin) && date.before(end)) {
            return true;
        } else {
            return false;
        }
    }

最终效果如下:

image-20211105130111418