实现微信公众号发送消息给指定用户

一、前言

在实际项目开发中,需要实现消息中心向关注微信公众号的指定用户发送消息通知,在翻阅了网上很多资料及微信官方开发文档后,最终顺利完成功能开发,但是其中走过的路艰辛且曲折,因此特将开发过程中踩过的坑及心得记录下来,以期给他人带来方便。

二、公众号消息通知开发

1.微信公众号开发配置

实现消息发送前,需要提前在业务系统关联的公众号上,做一些基础配置。配置如下所示:
(1)基础配置
开发者ID开发者密码不必多说,懂者自懂,IP白名单设置部署业务系统的IP地址,否则,微信的回调请求地址无法响应请求。服务器地址配置的是微信验证Token是否生效的接口,秘钥自己生成,加解密方式自己根据业务场景选择。这些都设置好后,就万事具备了接下来进入开发环节。
在这里插入图片描述

(2)消息模板配置
这里根据自己的业务场景合理选择消息模板,用于后续的消息通知生成
在这里插入图片描述

(3)服务器连通性测试配置
这里必须要把图片中提到的txt文件放到服务器的目录下,确保外部可以访问到。
在这里插入图片描述

在这里设置微信回调地址分服务器域名,否则调用微信授权认证接口后,会报以下错误:
在这里插入图片描述

2.编码实现

这里实现前文中提到的服务器配置中设置的服务器URL请求接口,验证配置的令牌是否生效。

/*** @author zhaolc* @version 1.0* @description TODO* @createTime 2021年02月26日 13:36:00*/
@Slf4j
@RestController
public class WeChatController {private static final String TOKEN = "cc2fb962b7bb37833008d65e905614c8";private static final String APPID="wxf1e42af3ecad28c7";private static final String APPSECRET="cc2fb962b7bb37833008d65e905614c8";/*** 微信验证token** @param signature* @param timestamp* @param nonce* @param echostr* @return*/@GetMapping("/checkTokenNotice.do")public String checkToken(@RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp,@RequestParam("nonce") String nonce, @RequestParam("echostr") String echostr) {//排序String[] arr = {TOKEN, timestamp, nonce};Arrays.sort(arr);StringBuilder content = new StringBuilder();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}//sha1Hex 加密MessageDigest md = null;String temp = null;try {md = MessageDigest.getInstance("SHA-1");byte[] digest = md.digest(content.toString().getBytes());temp = byteToStr(digest);log.info("加密后的token:" + temp);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}if ((temp.toLowerCase()).equals(signature)) {return echostr;}return null;}private static String byteToStr(byte[] byteArray){String strDigest = "";for (int i = 0; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);}return strDigest;}private static String byteToHexStr(byte mByte){char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B', 'C', 'D', 'E', 'F' };char[] tempArr = new char[2];tempArr[0] = Digit[(mByte >>> 4)& 0X0F];tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);return s;}}

这个接口是微信请求用户授权地址,具体如何触发授权,这个需由具体业务需求而定,这里不做赘述。因为我只需要用到微信用户的openID,所以本文中用到的是静默授权登录(scope=snsapi_base),即不需要微信用户显式授权,不足之处是获取的用户信息较少。所以这里需要具体业务做选择。

    @Overridepublic String weChatAuth(SendSmsParam req) {//这个url的域名必须要进行在公众号中进行注册验证,这个地址是成功后的回调地址String callBackUrl = "";if ("uat".equals(mark)) {callBackUrl = backUrl + "/uat/api/installment/vip/login/getOpenid.pub?mobile=" + req.getMobile();} else {callBackUrl = backUrl + "/api/installment/vip/login/getOpenid.pub?mobile=" + req.getMobile();}// 静默授权登录(scope=snsapi_base),一种为非静默授权登录(scope=snsapi_userinfo)String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appID + "&redirect_uri=" + URLEncoder.encode(callBackUrl) + "&response_type=code"+ "&scope=snsapi_base" + "&state=STATE#wechat_redirect";log.info("forward重定向地址{" + url + "}");return "redirect:" + url;}

这个接口是微信授权成功后的回调地址,用户授权后,获得授权码,再请求获取openId接口,得到openId,进行进一步的业务操作。

 @Overridepublic void getOpenidNotice(HttpServletRequest request, HttpServletResponse response) {String code = request.getParameter("code");String mobile = request.getParameter("mobile");log.info("手机号码[{}]", mobile);try {request.setCharacterEncoding("UTF-8");//通过获取access_token获得openid和access_tokenString backResult = HttpUtil.get("https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ appID + "&secret=" + appSecret + "&code=" + code +"&grant_type=authorization_code");//根据用户Access_token和openid获取用户信息log.info("用户openId[{}]", backResult);}}

调用消息发送接口发送微信消息到指定用户。

 public Boolean sendWeChatMsg(List<MessageRecordDTO> messageRecordList) {Boolean sendFlag = true;//从redis中获取accessTokenString accessToken = redisCacheService.getMap(MAP_NAME, MAP_KEY);if (StrUtil.isBlank(accessToken)) {accessToken = this.getAndSetAccessToken();}for (MessageRecordDTO messageRecordDTO : messageRecordList) {UserPO userPO = userManager.getById(messageRecordDTO.getUserId());if (ObjectUtil.isNull(userPO)) {continue;}// 根据配置的消息模板构建消息体发送。Map<String, MsgElement> dataMap = getMsgElementMap(messageRecordDTO);String extend2 = userPO.getExtend2();if (StrUtil.isNotBlank(extend2)) {WeChatMsgDTO weChatMsgDTO = new WeChatMsgDTO(extend2, msgTemplateId, dataMap);String json = JSON.toJSONString(weChatMsgDTO);String result = "";try {result = HttpUtil.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken, json);} catch (Exception e) {log.error("发送微信消息失败", e);sendFlag = false;messageRecordDTO.setSendState("2");if (messageRecordDTO.getFirstFlag() == null) {DelayTaskScheduler.putWithDefaultStrategy(new SyncRetryWechatNoticeTask(), new SyncRetryWechatNoticeMessage(messageRecordDTO, weChatMsgService), null);}}log.info("消息记录[{}],微信消息发送结果[{}]", messageRecordDTO.getId(), result);// 发送成功后,可继续进行业务操作}}return sendFlag;}private Map<String, MsgElement> getMsgElementMap(MessageRecordDTO messageRecordDTO) {Map<String, MsgElement> elementMap = new HashMap<>();elementMap.put("first", new MsgElement("亲爱的用户,您有一条新的消息", "#000000"));elementMap.put("keyword1", new MsgElement(ENMessageTypeEnum.getLabelByValue(messageRecordDTO.getMsgType()), "#000000"));elementMap.put("keyword2", new MsgElement(this.getSendMsg(messageRecordDTO), "#000000"));elementMap.put("keyword3", new MsgElement(DateTimeUtil.getDateTimeFormat(messageRecordDTO.getCreateTime()), "#000000"));return elementMap;}

这里涉及到每次发送时,需要accessToken,微信设置的过期时间是2小时,我的处理方式是将accessToken存放到redis中,淘汰时间设置同微信官方过期时间,交由redis来维护accessToken。实现代码如下所示:

 private String getAndSetAccessToken() {String accessToken = "";String backResult = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appID + "&secret=" + appSecret);if (StrUtil.isNotBlank(backResult)) {WeChatTokenDTO weChatTokenDTO = JSON.parseObject(backResult, WeChatTokenDTO.class);accessToken = weChatTokenDTO.getAccess_token();redisCacheService.setMap(MAP_NAME, MAP_KEY, accessToken, weChatTokenDTO.getExpires_in());}return accessToken;}

发送微信消息流程图如下所示:
在这里插入图片描述

三、总结

关于微信公众号发送用户消息,微信官方文档已经很详细了,但是笔者在实践过程中,还是遇到了很多坑,前后用时几天,才将整个流程串通,因此将心路历程记录下来。结合官方文档及笔者的总结后,基本不会再遇到太大的坑了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/67257.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【uiautomation】微信群发消息,可发送文本 文件

前言 接到了一个需求&#xff1a;现微信有8000好友&#xff0c;需要给所有好友发送一则一样的消息。网上搜索一番后&#xff0c;发现uiautomation 可以解决该需求&#xff0c;遂有此文。这是第二篇&#xff0c;群发消息给微信好友 代码在文章末尾&#xff0c;自取~ 更多功能的微…

java发送微信订阅消息

使用java发布订阅消息 之前接到了一个需求&#xff0c;要求我使用java发布订阅消息。那么首先&#xff0c;我要知道订阅消息是个什么&#xff0c;他能完成什么功能 一.什么是订阅消息 我直接去官网查看订阅消息的相关文档说明&#xff1a; https://developers.weixin.qq.com…

微信公众号开发——向指定用户发送模板消息

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; 微信公众号开发——向指定用户发送模板消息 ⏱️ 创作时间&#xff1a…

微信公众号一次性订阅消息功能开发实践

截止到2021年6月10日&#xff0c;微信公众号测试号是不支持“微信公众号一次性订阅消息”的开发&#xff0c;必须用正式的微信公众号测试&#xff0c;那如何在不影响正式的微信公众号运营的情况下来开发这个小功能呢&#xff0c;请看看笔者的实践。 微信一次性订阅官方开发文档…

python实现微信公众号给你的重要用户推送消息

最近小红书上这个很火&#xff0c;觉得做起来应该也不会太难&#xff0c;捣鼓了两天有了初步成效&#xff0c;还有一些功能没实现&#xff08;比如定时推送&#xff09;&#xff0c;保姆级教程&#xff0c;大家可以借鉴&#xff0c;动手给自己重要的人做一个&#xff0c;或许可…

JAVA对接微信公众号(服务号、订阅号)实现模板消息推送功能

最近做了个需求要求对接微信公众号&#xff0c;使用模板进行消息推送&#xff0c;今天抽时间总结一下相关的逻辑。 大概逻辑分为四个步骤&#xff1a; 获取微信调用接口凭证access_token。获取微信模板列表。使用模板进行消息推送。公众号配置服务器URL。 我这里的实现没有使…

微信开发工具实现订阅消息功能

微信开发工具实现订阅消息功能 1、新建文件夹&#xff0c;取名为&#xff1a;push1 2、push1.wxml写下如下代码&#xff1a; <button bindtap"dingyue">订阅</button>3、push1.js写下如下代码&#xff1a; // pages/push1/push1.js Page({/*** 页面…

微信公众号 - Java推送小程序订阅消息给用户

不啰嗦&#xff0c;我们直接开始&#xff01; 本文使用体验版小程序进行调试。 一、开发前小程序准备&#xff1a; 1、登录微信公众平台 点开下面链接&#xff0c;使用微信扫码 微信公众平台 然后选择一个小程序并登录 2、在小程序后台找到Appid、AppSecret、Token、Encod…

微信公众号订阅号开发的学习(二):获取用户发送的消息、简单的自动回复、自定义菜单

获取用户发送的消息 基础 微信服务器会发送两种类型的消息给开发者服务器。 get请求 验证服务器的有效性post请求 微信服务器会将用户发送的数据转发到开发者服务器上 实现 基于微信公众号订阅号开发的学习&#xff08;一&#xff09;&#xff1a;基础知识 auth.js //引…

微信第三方平台集成公众号发送模板消息

最近老板下发了个任务&#xff0c;有一个业务是整合用户的微信公众号&#xff08;服务号&#xff09;&#xff0c;然后在我们的erp系统里给下家客户发送模板消息&#xff0c;找了一下发现微信第三方平台可以实现&#xff0c;那就干起来。 先在微信开放平台&#xff0c;申请一个…

元宇宙iwemeta:元宇宙数字人实践落地应用场景

把虚拟数字人装进你的手机&#xff01;百度、腾讯、讯飞盯准这条新赛道。 短短三个月内&#xff0c;几乎每一家拥有智能语音技术能力的大厂都在采取行动布局虚拟数字人。 百度、华为、阿里等都纷纷引入AI数字人入职&#xff0c;担任技术宣讲员、形象代言人&#xff1b;OPPO、…

考研人常说的“死亡211”和“984.5”是什么学校?

&#x1f603;这几所211院校&#xff0c;真香&#xff01;被称为984.5&#xff01;众所周知&#xff0c;985高校是国内最顶尖的一批名牌大学&#xff0c;每年报考的人都疯狂扎堆&#xff0c;分也很高&#xff0c;想去分一杯羹很难。但考个一般211吧&#xff0c;有时又不甘心&am…

华工计算机网络辅修,【JZT干货】双手献上华工辅修攻略

原标题&#xff1a;【JZT干货】双手献上华工辅修攻略 辅修进行了一个多月&#xff0c;相信小伙伴们也对辅修有了基本的了解。那么各课程的期末考试是怎样的&#xff1f;一些老师上课有什么特点&#xff1f;想了解吗&#xff0c;团仔在此献上纯干货给大家。 当然啦&#xff0c;涉…

z世代消费力白皮书_猫哥清华新传考研|如何让Z世代粉上你?

猫小菇/新传考研猫 不管愿不愿意承认&#xff0c;“Z世代”主宰的未来已经悄然来临了。 每个时代的年轻人都是品牌主最想触及的群体&#xff0c;因为他们代表着市场的未来。 当“千禧一代”仍然是当下消费重点群体时&#xff0c;“Z世代”已经带着与生俱来的敏感力和决策力进入…

本土网络安全公司——上讯信息的“老兵新传”

上讯信息&#xff0c;这个名字听起来很耳熟&#xff0c;但是很多人还是对这个公司有点儿陌生。其实就在今年年初&#xff0c;上讯信息获得了由ISCCC颁发的信息安全风险评估一级服务资质&#xff0c;以及信息安全应急处理二级服务资质&#xff0c;成为金融行业“年度信赖品牌”。…

社工库制作

项目结构 https://github.com/Collapsar-G/social_worker_library 后端使用以下模块&#xff1a; pymsql、flask 前端使用vue搭建 完成过程 在完成上参考了《“系统安全”课程项目&#xff1a;一个实用社工库的建设》&#xff0c;加入了一些自己的理解。 数据初始化 导出为c…

社工库2.0

#大题目 社工库2.0 ###环境 whoosh2.7jieba12306python3.7网上嫖来的网页模板(感谢站长之家 ###实现效果建立的索引文件 好看的页面 更快的查找速度 ###实现过程 具体的实现过程比较简易,毕竟whoosh已经封装的很好了第一步 建立索引并存储schema = Schema(zhanghao=TEXT(sto…

搭建社工库

成品大概是这样子&#xff0c;我把主要源码贴在下面 <!doctype html> <html> <head> <meta charset"utf-8"> <meta name"viewport" content"widthdevice-width,initialscale1"> <title>社工库</title&…

计算机专业的八字,生辰八字自动计算器软件 生辰八字在线计算器

大家对于计算器都很熟悉吧&#xff0c;一点也不陌生&#xff0c;与此同时&#xff0c;那么计算机是大家在日常生活中使用的一个简单软件&#xff0c;在使用的同时&#xff0c;既简单又方便&#xff0c;那么对于计算器大家都有所掌握 &#xff0c;所以这次小编将要给你介绍一下新…

html中如何做出生年月日,出生年月日怎么换成生辰八字

天干有 十个:甲、乙、丙、丁、戊、己、庚、辛、壬、癸。 地支有十二个:子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥。 二者顺序配合可以产生六十个单位&#xff0c;叫六十甲子。那生出生的年、月、日、时分别用天干、地支配合来表示&#xff0c;正好有八个字&#xff0c;因…