您现在的位置是:Java微信小程序获取关联公众号用户是否已关注标识 >>正文

Java微信小程序获取关联公众号用户是否已关注标识

德薄能鲜网68人已围观

简介文章目录前言一、绑定相关数据1.小程序绑定公众号2.小程序和公众号关联微信开放平台二、公众号操作回调1.服务器配置2.回调接口(URL)三、获取微信公众号用户是否已关注标识...

文章目录

  • 前言
  • 一、绑定相关数据
    • 1.小程序绑定公众号
    • 2.小程序和公众号关联微信开放平台
  • 二、公众号操作回调
    • 1.服务器配置
    • 2.回调接口(URL)
  • 三、获取微信公众号用户是否已关注标识
    • 1.获取公众号accessToken
    • 2.feign远程调用微信公众号获取用户基本信息(UnionID机制)
    • 3.回调接口补充更新用户关注标识
  • 总结


前言

如果公众号不是认证的服务号就无需看这篇文章,需要先认证,可以参考这篇文章五分钟!手把手教你快速完成微信公众号认证!

你们是否经常在小程序看到这种关注标识
在这里插入图片描述
实现的方法很简单,后端只需要返回给前端给前端当前用户是否有关注公众号就行了,整个逻辑很简单,微信官方也有对应的API,但实际上整个流程就很复杂


一、绑定相关数据

微信官方有很多限制,咱们需要做好一些关联

1.小程序绑定公众号

根据微信官方文档,微信小程序需要关联对应的公众号才能够引导关注公众号
咱们先登录微信公众平台,扫码登录公众号
在这里插入图片描述
然后点击【广告与服务】->【小程序管理】添加关联小程序,这步很简单只需要后台管理员扫码一下就行了。
在这里插入图片描述

2.小程序和公众号关联微信开放平台

这一步比较重要,这是为了获取unionId,关于unionId介绍可以看一下官方说明,UnionID 机制说明,简单来说就是同一个微信开放平台用户的unionId都是唯一的

先注册微信开放平台,然后关联小程序和公众号,关联流程参考文章微信开放平台绑定公众号,小程序也同理,这个时候你们需要改造原来的微信登录接口,会发现登录接口返回的参数多了unionId,把对应用户的unionId存到数据库里,后面会用得上。

二、公众号操作回调

这个是公众号的相关操作会有回调,相当强大,咱们服务器能立马得知用户做了什么操作,这里咱们只需要配公众号关注取消关注的回调。

1.服务器配置

同样登录微信公众平台,选择公众号账号登录,进入【服务与配置】->【基本配置】,会看到有一个服务器配置
在这里插入图片描述
点击修改配置
在这里插入图片描述
这个URL实际上就是咱们要给微信的回调地址,需要外网可访问;
Token咱们随意填写,只要跟服务器对得上;
EncodingAESKey随机生成就好,然后消息加解密选择用明文模式,安全模式可以看看别人写的加解密方式;

2.回调接口(URL)

RequestMethodEnum枚举类是为了判断什么请求方式,如果是get请求实际上就是验证token合法性

publicenumRequestMethodEnum{ /**     * get     */GET(1,"GET"),/**     * post     */POST(2,"POST");privatefinalIntegercode;privatefinalStringdesc;RequestMethodEnum(Integerid,Stringname){ this.code =id;this.desc =name;}publicIntegergetCode(){ returncode;}publicStringgetDesc(){ returndesc;}}

MsgTypeEnum枚举类是为了判断微信公众号执行了什么操作

publicenumMsgTypeEnum{ /**     * 关注/取消关注事件     */EVENT(1,"event");privatefinalIntegercode;privatefinalStringdesc;MsgTypeEnum(Integerid,Stringname){ this.code =id;this.desc =name;}publicIntegergetCode(){ returncode;}publicStringgetDesc(){ returndesc;}}

checkSignature验证回调地址是否合法的工具方法

publicstaticbooleancheckSignature(Stringsignature,Stringtimestamp,Stringnonce,Stringtoken){ // 1.将token、timestamp、nonce三个参数进行字典序排序String[]arr =newString[]{ token,timestamp,nonce};Arrays.sort(arr);// 2. 将三个参数字符串拼接成一个字符串进行sha1加密StringBuildercontent =newStringBuilder();for(inti =0;i <arr.length;i++){ content.append(arr[i]);}MessageDigestmd =null;StringtmpStr =null;try{ md =MessageDigest.getInstance("SHA-1");// 将三个参数字符串拼接成一个字符串进行sha1加密byte[]digest =md.digest(content.toString().getBytes());tmpStr =byteToStr(digest);}catch(NoSuchAlgorithmExceptione){ e.printStackTrace();}content =null;// 3.将sha1加密后的字符串可与signature对比,标识该请求来源于微信log.info("tmpStr:{ },signature:{ }",tmpStr,signature.toUpperCase());returntmpStr !=null&&tmpStr.equals(signature.toUpperCase());}

然后验证完整方法如下

publicvoidcallback(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{ Stringmethod =request.getMethod();request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");if(RequestMethodEnum.GET.getDesc().equals(method)){ //验证回调地址Stringsignature =request.getParameter("signature");Stringtimestamp =request.getParameter("timestamp");Stringnonce =request.getParameter("nonce");Stringechostr =request.getParameter("echostr");booleancheckSignature =WechatOffiAccountUtil.checkSignature(signature,timestamp,nonce,token);// 这个token要跟服务器配置的token一致if(checkSignature){ log.info("签名验证成功");response.getWriter().write(echostr);}}}

写好接口后,回去填写服务器配置,就会验证成功。


三、获取微信公众号用户是否已关注标识

1.获取公众号accessToken

咱们要先清楚,小程序的accessToken和公众号的accessToken是不同的,所以公众号的accessToken要重新获取一下,先查阅一下微信公众号API获取 Access token
Java获取方法如下:

publicStringgetOfficialAccessToken(){ StringaccessToken =redisCache.getCacheObject("official_access_token");// 这里会用到redisCache工具if(Objects.isNull(accessToken)){ Stringurl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+OFFICIAL_APP_ID+"&secret="+OFFICIAL_SECRET;RestTemplaterestTemplate =newRestTemplate();ResponseEntity<String>response =restTemplate.exchange(url,HttpMethod.GET,null,String.class);StringresponseBody =response.getBody();// 解析返回结果,提取 access_token 字段的值accessToken =parseAccessToken(responseBody);redisCache.setCacheObject("official_access_token",accessToken,1,TimeUnit.HOURS);}if(!isAccessTokenValid(accessToken)){ // 这是为了解析accessToken是否还有效,因为官方的过期时间会变动Stringurl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+OFFICIAL_APP_ID+"&secret="+OFFICIAL_SECRET;RestTemplaterestTemplate =newRestTemplate();ResponseEntity<String>response =restTemplate.exchange(url,HttpMethod.GET,null,String.class);StringresponseBody =response.getBody();// 解析返回结果,提取 access_token 字段的值accessToken =parseAccessToken(responseBody);redisCache.setCacheObject("official_access_token",accessToken,1,TimeUnit.HOURS);}returnaccessToken;}privateStringparseAccessToken(StringresponseBody){ JSONObjectjsonObject =newJSONObject(responseBody);returnjsonObject.getString("access_token");}publicbooleanisAccessTokenValid(StringaccessToken){ Stringurl ="https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token="+accessToken;RestTemplaterestTemplate =newRestTemplate();ResponseEntity<String>response =restTemplate.exchange(url,HttpMethod.GET,null,String.class);StringresponseBody =response.getBody();// 解析返回结果,提取错误信息StringerrorCode =parseErrorCode(responseBody);// 如果错误码为空,则表示 access_token 有效;否则,表示无效returnerrorCode ==null;}

2.feign远程调用微信公众号获取用户基本信息(UnionID机制)

远程调用我是用了feign,这样可以节省很多建远程调用步骤,然后查阅一下微信公众号API获取用户基本信息(UnionID机制)
请求结果实体类

@DatapublicclassPublicUserInfo{ /**     * 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。     */privateintsubscribe;/**     * 用户的标识,对当前公众号唯一     */privateStringopenid;/**     * 用户的语言,简体中文为zh_CN     */privateStringlanguage;/**     * 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间     */privatelongsubscribe_time;/**     * 只有在用户将公众号绑定到微信开放平台账号后,才会出现该字段。     */privateStringunionid;/**     * 公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注     */privateStringremark;/**     * 用户所在的分组ID(兼容旧的用户分组接口)     */privateintgroupid;/**     * 用户被打上的标签ID列表     */privateList<Integer>tagid_list;/**     * 返回用户关注的渠道来源     */privateStringsubscribe_scene;/**     * 二维码扫码场景(开发者自定义)     */privateintqr_scene;/**     * 二维码图片     */privateStringqr_scene_str;privateStringqrSceneImage;// 添加构造方法、getter和setter等}

编写Feign接口方法

@FeignClient(name ="officialAccount",url ="https://api.weixin.qq.com/cgi-bin")publicinterfaceOfficialAccountFeign{ @GetMapping("/user/info?access_token={ accessToken}&openid={ openId}&lang=zh_CN")ResponseEntity<PublicUserInfo>getUserInfo(@PathVariable("accessToken")StringaccessToken,@PathVariable("openId")StringopenId);}

3.回调接口补充更新用户关注标识

补充上面写的callBack回调方法

publicvoidcallBack(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{ Stringmethod =request.getMethod();request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");if(RequestMethodEnum.GET.getDesc().equals(method)){ //验证回调地址Stringsignature =request.getParameter("signature");Stringtimestamp =request.getParameter("timestamp");Stringnonce =request.getParameter("nonce");Stringechostr =request.getParameter("echostr");booleancheckSignature =WechatOffiAccountUtil.checkSignature(signature,timestamp,nonce,token);if(checkSignature){ log.info("签名验证成功");response.getWriter().write(echostr);}}else{ //接收回调xml;Documentdocument =XmlUtil.readXML(request.getReader());StringtoUserName =(String)XmlUtil.getByXPath("//xml/ToUserName",document,XPathConstants.STRING);StringfromUserName =(String)XmlUtil.getByXPath("//xml/FromUserName",document,XPathConstants.STRING);LongcreateTime =Long.valueOf((String)XmlUtil.getByXPath("//xml/CreateTime",document,XPathConstants.STRING));StringmsgType =(String)XmlUtil.getByXPath("//xml/MsgType",document,XPathConstants.STRING);log.info("FromUserName:{ }",fromUserName);log.info("CreateTime:{ }",createTime);log.info("MsgType:{ }",msgType);if(MsgTypeEnum.EVENT.getDesc().equals(msgType)){ //是否事件为关注/取消关注事件Stringevent =(String)XmlUtil.getByXPath("//xml/Event",document,XPathConstants.STRING);log.info("Event:{ }",event);if(EventEnum.SUBSCRIBE.getDesc().equals(event)){ //关注//新增用户Booleaninsert =updateUserSubscribe(fromUserName,1);if(insert){ log.info("新增关注用户成功");response.getWriter().write("success");}}else{ //取关//更新用户状态Booleanupdate =updateUserSubscribe(fromUserName,0);if(update){ log.info("更新关注用户状态成功");response.getWriter().write("success");}}}}}privateBooleanupdateUserSubscribe(StringfromUserName,Integersubscribe){ QueryWrapper<WechatUser>userQueryWrapper =newQueryWrapper<>();// 这里用了mybatis-plus方法,匹配用户的公众号public_openid,匹配上就查出来,否则就根据unionId重新匹配userQueryWrapper.eq("public_openid",fromUserName);WechatUseruser =this.getOne(userQueryWrapper);if(Objects.nonNull(user)){ user.setSubscribe(subscribe);this.updateById(user);returntrue;}else{ PublicUserInfopublicUserInfo =officialAccountFeign.getUserInfo(loginService.getOfficialAccessToken(),fromUserName).getBody();userQueryWrapper.clear();userQueryWrapper.eq("unionid",publicUserInfo.getUnionid());user =this.getOne(userQueryWrapper);if(Objects.nonNull(user)){ user.setPublicOpenid(fromUserName);this.updateById(user);returntrue;}}returnfalse;}

到这里就大功告成了,先注册小程序账号,然后在公众号上点击关注和取消关注操作,关注数据库显示的内容。


总结

很多功能看似很简单实现,但是如果在第三方平台上开发,需要遵从官方的要求,才能把整个环节实现。

参考博客:ruoyi的springboot微信小程序登录实现方式(我自己写的,感兴趣的可以去看一下)

Tags:

相关文章



友情链接