公众号推送模板消息
模板消息功能插件
开通成功以后会在功能栏下出现模板消息,右侧是我们从模板库引入的一个模板,稍后推送会用到
推送模版消息接口介绍
官方文档:模版消息接口
按照官方文档操作步骤如下:
- http请求方式: POST https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN,access_token 接口调用凭证
POST 请求 data 数据需要传递的参数介绍:
注:url、miniprogram 都是非必填字段,若都不传则模板无跳转;若都传,会优先跳转至小程序。开发者可根据实际需要选择其中一种跳转方式即可;当用户的微信客户端版本不支持跳小程序时,将会跳转至 url
获取 Token 接口凭证
获取 token 接口凭证,获取到的 token 有效时间为 2 小时,在我们程序正常运行的时候,不可能每次都重启,我们可以使用定时器去定时更新我们 token 接口凭证
token 接口凭证类源码如下:
/** * 公众号推送消息所用的实体类 * @author vnjohn * @since 2023/2/19 */ @Data public class AccessToken { /** * 公众号通知类型:1服务号 2订阅号 */ private Integer noticeType; private Integer schoolId; private String accessToken; private int expiresIn; }
/** * @author vnjohn * @since 2023/2/19 */ public class TokenUtil { public static AccessToken accessToken = null; private final static Logger logger = LoggerFactory.getLogger(TokenUtil.class); /** * 获取接口访问凭证 * 刷新 access_token 110 分钟刷新一次,服务器启动的时候刷新一次(access_token 有效期是120分钟,我设置的是每 110 分钟刷新一次) * * @return 认证信息 */ @Scheduled(initialDelay = 1000, fixedDelay = 60 * 1000 * 110) private static AccessToken getAccessToken() { String requestUrl = WxConstant.TOKEN_URL.replace("APPID", WxConstant.GZH_APP_ID) .replace("SECRET", WxConstant.GZH_SECRET); // 发起GET请求获取凭证 JSONObject jsonObject = JSONObject.parseObject(HttpUtil.sendPost(requestUrl, "GET", null)); if (null != jsonObject) { try { TokenUtil.accessToken = new AccessToken(); TokenUtil.accessToken.setAccessToken(jsonObject.getString("access_token")); TokenUtil.accessToken.setExpiresIn(jsonObject.getIntValue("expires_in")); logger.info("AccessToken>>>>>>>>>>>>>" + jsonObject.toString()); } catch (Exception e) { TokenUtil.accessToken = null; // 获取token失败 logger.error(e.getMessage()); } } return TokenUtil.accessToken; } }
模版消息 Send 工具类
/** * @author vnjohn * @since 2023/2/19 */ @Data @NoArgsConstructor @AllArgsConstructor public class TemplateData { /** * 只能是 value 属性不能是 name 属性 */ private String value; private String color; }
/** * @author vnjohn * @since 2023/2/19 */ public class SendTemplateMsgUtil { private final static Logger logger = LoggerFactory.getLogger(SendTemplateMsgUtil.class); private final static String TO_URL = "http://weixin.qq.com/download"; /** * 点击消息跳转相关参数map * * @return */ public static Map<String, String> getMiniProgramMap() { //点击消息跳转相关参数map Map<String, String> miniProgramMap = new HashMap<String, String>(); miniProgramMap.put("appid", WxConstant.APPLET_APP_ID); miniProgramMap.put("path", "pages/me/me"); return miniProgramMap; } /** * 定时推送 打卡消息通知 * * @param openId */ public static void SendWeChatPunchClockMsg(String openId, String studentName, String category, String content) { logger.info(TokenUtil.accessToken.toString()); AccessToken accessToken = TokenUtil.accessToken; // 接口地址 String sendMsgApi = WxConstant.MSG_API.replace("ACCESSTOKEN", accessToken.getAccessToken()); // 消息模板ID String template_id = WxConstant.PUNCH_TEMPLATE_ID; // 整体参数map Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("touser", openId); paramMap.put("template_id", template_id); paramMap.put("url", TO_URL); paramMap.put("miniprogram", getMiniProgramMap()); paramMap.put("data", getDataMap(studentName, category, content, 1)); logger.info(HttpUtil.sendPost(sendMsgApi, "POST", paramMap)); } /** * 消息主题显示相关map * * @param msgType 不同的值走不同的推送 * @return */ public static Map<String, Object> getDataMap(String param1, String param2, String param3, Integer msgType) { Map<String, Object> dataMap = new HashMap<>(); if (msgType.equals(1)) {//打卡通知 dataMap.put("first", new TemplateData("亲爱的" + param1 + "家长," + param1 + "今天的作业如下:", "#173177")); dataMap.put("name", new TemplateData(param1, "#173177")); dataMap.put("subject", new TemplateData(param2, "#173177")); dataMap.put("content", new TemplateData(param3, "#173177")); } else if (msgType.equals(2)) {//收款通知 dataMap.put("first", new TemplateData(param1 + "家长你好,你的孩子需要收取费用:", "#173177")); dataMap.put("keyword1", new TemplateData(param1, "#173177"));//param1 为学生姓名 dataMap.put("keyword2", new TemplateData(param2, "#173177"));//缴费类型 dataMap.put("keyword3", new TemplateData(param3, "#173177"));//缴费金额 dataMap.put("remark", new TemplateData("为有助于学校各项工作的顺利开展,请您务必在缴费截止日期前缴费", "#173177")); } else if (msgType.equals(3)) {//消息通知 dataMap.put("first", new TemplateData("您好,为方便对学生进行管理,特通知如下:", "#173177")); dataMap.put("keyword1", new TemplateData(param1, "#173177"));//keyword1 param1 为学校 dataMap.put("keyword2", new TemplateData(param2, "#173177"));//keyword2 param2 为通知人 dataMap.put("keyword3", new TemplateData(DateUtil.dateToString(new Date()), "#173177"));//keyword3 为通知时间 dataMap.put("keyword4", new TemplateData(param3, "#173177"));//keyword4 param3 为通知内容 dataMap.put("remark", new TemplateData("为有助于学校各项工作的顺利开展", "#173177")); } return dataMap; } }
推送模板消息接口测试
传入刚刚网页授权所拿到的 openId、模板 id 进行测试,在获取 Token 接口凭证时报错:invalid IP
因为该 IP 未设置白名单,进入公众号后台设置 IP 白名单
重新启动以后,已拿到 token 接口凭证,之后我们可以通过 postman 进行发送模板消息请求
@GetMapping("/wx/sendMsg") public void sendMsg(@RequestParam String openId,@RequestParam String studentName,@RequestParam String category,@RequestParam String content){ SendMsgUtil.SendWeChatPunchClockMsg(openId,studentName,category,content); }
Post man 测试推送消息接口:
手机上正常接收到消息提醒
总结
该文章介绍在使用公众号开发功能时,涉及到的菜单、消息回复、推送等功能时,前面需要的一些准备工作,以及如何配置后端服务进行交互,同时提供了 Token 认证配置、网页授权、模版消息推送功能相关的源码给到大家
如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!
大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!