侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

微信小程序与公众号实现数据互通的方法

微信(小程序)  /  管理员 发布于 3年前   221

公司因小程序项目先上线,公众号后开发,接到上级的安排实现小程序打通任务,看文档后发现:同一开发者账号只要是在微信开放平台绑定小程序与公众号以后,会有一个唯一的unionid,这个unionid腾讯公司下产品共享。这个unionid就是我们进行打通的关键。

先说一下思路:

1.微信小程序与公众号进行绑定后,在小程序调用wx.login()方法后会自动获取unionid,公众号根据官方文档在获取用户基本信息后会拿到相同的unionid,openid,nickname。。。等相关信息;

2.将小程序拿到的unionid进行数据库的更新操作,公众号拿到的unionid等信息,新建数据库表A进行存储;(注:在这一步,因为我们公司的原因,我们的公众号之前就有人关注了,那么在这之前,我通过公众号获取关注用户列表获取openid的列表,进行循环openid列表,在调用公众号获取用户基本信息列表进行储存数据库表A,循环结束后之前关注的人的信息就储存在数据库A,然后在进行,这一步的操作)

3.通过公众号关注/取关的事件相应,来进行数据库表A的增删操作,维护数据的新鲜度;

4.进行关联查询,到这一步我们会发现,通过unionid进行表的关联后我们已经实现数据的互通了 

洋洋洒洒的说了一大堆,其实就是公众号的两个接口至关重要(1.关注/取关的事件相应接口     2.获取用户的基本信息接口)

有关于公众号的安全域名配置,服务器域名配置以及获取token就不在这里说了,百度一下一大堆。

代码实现:

第一步,获取公众号用户的openid列表操作,根据opneid进进行用户的基本信息的查询,存入数据库操作(因为我们公司的公众号关注人数只有1000+,所以我只调用了一次获取关注列表的接口)

//主要代码逻辑//获取token AccessToken accessToken=wxUtils.getAccessToken(); String url="https://api.weixin.qq.com/cgi-bin/user/get?access_token="+accessToken.getAccessToken()+"&next_openid=";//获取所有用户openidJSONObject jsonObject = httpRequest(url, "GET", null);  try { if(jsonObject.getString("errcode")!=null){ } }catch(Exception e) { } WeixinUserList userList = (WeixinUserList)JSONObject.toBean(jsonObject, WeixinUserList.class); if(null==userList) {  return "无用户"; } userList.getTotal();//关注总人数 //用户openId 列表 WxOpenidInfo wxOpenidInfo=userList.getData(); List openIdList=null; if(null!=wxOpenidInfo) { openIdList=wxOpenidInfo.getOpenid();//公众号返回的openid列表数据  if(null!=openIdList && openIdList.size()>0) { for(String opendid:openIdList) {      //获取用户的基本信息(unionid机制)  url="https://api.weixin.qq.com/cgi-bin/user/info?    access_token="+accessToken.getAccessToken()+"&openid="+opendid+"&lang=zh_CN";//通过openid获取用户信息  jsonObject = httpRequest(url, "GET", null);   WeixinUser wxUser=(WeixinUser)JSONObject.toBean(jsonObject, WeixinUser.class);      //进行数据库表A的储存操作   int row = gzhService.addGZHUser(wxUser);  } }}    /** * 用户列表  * @author 一叶知秋plus * */public class WeixinUserList{       private Integer total;//关注该公众账号的总用户数    private Integer count;//拉取的OPENID个数,最大值为10000    private WxOpenidInfo data;//列表数据,OPENID的列表    private String next_openid;//拉取列表的最后一个用户的OPENID    private int errcode;//错误编码    private String errmsg="ok";//错误提示    public Integer getTotal() {     return total;   }    public void setTotal(Integer total) {     this.total = total;   }    public Integer getCount() {     return count;   }    public void setCount(Integer count) {     this.count = count;   }    public String getNext_openid() {     return next_openid;   }    public void setNext_openid(String next_openid) {     this.next_openid = next_openid;   }    public WxOpenidInfo getData() {     return data;   }    public void setData(WxOpenidInfo data) {     this.data = data;   }    public int getErrcode() {     return errcode;   }    public void setErrcode(int errcode) {     this.errcode = errcode;   }    public String getErrmsg() {     return errmsg;   }    public void setErrmsg(String errmsg) {     this.errmsg = errmsg;   }  }  /** * 用户基本信息  * @author 一叶知秋plus * */  public class WeixinUser { private String subscribe;// 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。 private String openid;// 用户的标识,对当前公众号唯一 private String nickname;// 用户的昵称 private String sex;// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 private String city;// 用户所在城市 private String country;// 用户所在国家 private String province;// 用户所在省份 private String language;// 用户的语言,简体中文为zh_CN private List tagid_list;//用户被打上的标签ID列表 private String unionid; //用户的unionid private String headimgurl;//用户的头像     public String getHeadimgurl() { return headimgurl; } public void setHeadimgurl(String headimgurl) { this.headimgurl = headimgurl; } public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } public String getSubscribe() { return subscribe; } public void setSubscribe(String subscribe) { this.subscribe = subscribe; } public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } public List getTagid_list() { return tagid_list; } public void setTagid_list(List tagid_list) { this.tagid_list = tagid_list; }}  public class WxOpenidInfo { private List openid;   public List getOpenid() {    return openid;  }   public void setOpenid(List openid) {    this.openid = openid;  }}

步骤二:关注/取关的事件响应接口

/** * 请求校验工具类 */public class SignUtil {  // 与接口配置信息中的Token要一致,我的是明文格式  private static String token = "填写你服务器配置时写的token";     public static boolean checkSignature(String signature, String timestamp,      String nonce) {    //从请求中(也就是微信服务器传过来的)拿到的token, timestamp, nonce    String[] arr = new String[] { token, timestamp, nonce };    // 将token、timestamp、nonce三个参数进行字典序排序    sort(arr);    StringBuilder content = new StringBuilder();    for (int i = 0; i < arr.length; i++) {      content.append(arr[i]);    }    MessageDigest md = null;    String tmpStr = null;     try {      md = MessageDigest.getInstance("SHA-1");      // 将三个参数字符串拼接成一个字符串进行sha1加密      byte[] digest = md.digest(content.toString().getBytes());      //将字节数组转成字符串      tmpStr = byteToStr(digest);    } catch (NoSuchAlgorithmException e) {      e.printStackTrace();    }     content = null;    // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信    return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;  }  //将加密后的字节数组变成字符串  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;  }//用于字典排序  public static void sort(String a[]) {    for (int i = 0; i < a.length - 1; i++) {      for (int j = i + 1; j < a.length; j++) {        if (a[j].compareTo(a[i]) < 0) {          String temp = a[i];          a[i] = a[j];          a[j] = temp;        }      }    }  }}  //事件响应的接口@RequestMapping(value="/GZHConcern.do") public void GZHConcern(HttpServletRequest request, HttpServletResponse response) throws IOException { String message = "success"; // 微信加密签名  String signature = request.getParameter("signature");  // 时间戳  String timestamp = request.getParameter("timestamp");  // 随机数  String nonce = request.getParameter("nonce");  // 随机字符串  String echostr = request.getParameter("echostr");  PrintWriter out = response.getWriter();  // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败  if (SignUtil.checkSignature(signature, timestamp, nonce)) {   out.print(echostr);  //在这里相应微信的操作 }   try {  Map map = XmlUtil.xmlToMap(request);  String fromUserName = map.get("FromUserName");//消息来源用户标识  String toUserName = map.get("ToUserName");//消息目的用户标识  String msgType = map.get("MsgType");//消息类型  String content = map.get("Content");//消息内容    String eventType = map.get("Event");  WeixinUser weixinUser = new WeixinUser();  if(MessageUtil.MSGTYPE_EVENT.equals(msgType)){//如果为事件类型  if(MessageUtil.MESSAGE_SUBSCIBE.equals(eventType)){//处理订阅事件   //获取token   String token = WXUtil.getGZHToken();   weixinUser = WXUtil.getUnionid(fromUserName, token);   //进行数据库的操作   weixinUser.setNickname(weixinUser.getNickname());   int row = gzhService.addGZHUser(weixinUser);   //通过openid获取用户的数据   message = MessageUtil.subscribeForText(toUserName, fromUserName);  }else if(MessageUtil.MESSAGE_UNSUBSCIBE.equals(eventType)){//处理取消订阅事件   message = MessageUtil.unsubscribe(toUserName, fromUserName);   weixinUser.setOpenid(fromUserName);   //进行数据库的操作   int row = gzhService.deleteGZHUser(weixinUser);  }  } } catch (DocumentException e) {  // TODO Auto-generated catch block  e.printStackTrace(); }finally {  out.close(); } out = null; } /* * 消息处理工具类 */public class MessageUtil { public static final String MSGTYPE_EVENT = "event";//消息类型--事件 public static final String MESSAGE_SUBSCIBE = "subscribe";//消息事件类型--订阅事件 public static final String MESSAGE_UNSUBSCIBE = "unsubscribe";//消息事件类型--取消订阅事件 public static final String MESSAGE_TEXT = "text";//消息类型--文本消息  /* * 组装文本消息 */ public static String textMsg(String toUserName,String fromUserName,String content){ TextMessage text = new TextMessage(); text.setFromUserName(toUserName); text.setToUserName(fromUserName); text.setMsgType(MESSAGE_TEXT); text.setCreateTime(new Date().getTime()); text.setContent(content); return XmlUtil.textMsgToxml(text); }  /* * 响应订阅事件--回复文本消息 */ public static String subscribeForText(String toUserName,String fromUserName){ return textMsg(toUserName, fromUserName, "欢迎关注,精彩内容不容错过!!!"); }  /* * 响应取消订阅事件 */ public static String unsubscribe(String toUserName,String fromUserName){ //TODO 可以进行取关后的其他后续业务处理 System.out.println("用户:"+ fromUserName +"取消关注~"); return ""; }}  /* * xml处理工具类 */public class XmlUtil { /* * xml转map */ public static Map xmlToMap(HttpServletRequest request) throws IOException, DocumentException{ HashMap map = new HashMap(); SAXReader reader = new SAXReader();  InputStream ins = request.getInputStream(); Document doc = reader.read(ins);  Element root = doc.getRootElement(); @SuppressWarnings("unchecked") List list = (List)root.elements();  for(Element e:list){  map.put(e.getName(), e.getText()); } ins.close(); return map; } /* * 文本消息对象转xml */ public static String textMsgToxml(TextMessage textMessage){ XStream xstream = new XStream(); xstream.alias("xml", textMessage.getClass()); return xstream.toXML(textMessage); }}

ok,到这一步数据库中有了小程序opneid unionid 公众号opneid  unionid等用户信息,进行关联后就可以进行数据的查询操作,当然小程序也可以发送公众号模板的相应操作了。如果有更好的实现方式,欢迎各位大佬不吝赐教~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

您可能感兴趣的文章:

  • 微信小程序如何访问公众号文章
  • 微信公众号菜单配置微信小程序实例详解


  • 上一条:
    如何使用ajax读取Json中的数据
    下一条:
    微信小程序tabBar 返回tabBar不刷新页面
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 小程序开发之跳转微信直播示例api(0个评论)
    • 在uni_app中开发小程序之常用功能示例代码汇总(0个评论)
    • 小程序开发之多端框架:taro(0个评论)
    • 微信小程序前端使用七牛云官方SDK上传七牛云代码示例(0个评论)
    • 百度小程序审核未通过,真机审核存在点击返回键退出小程序...解决方式之一tabBar(0个评论)
    • 近期文章
    • 如何优雅处理async await错误推荐:await-to-js库(0个评论)
    • lodash工具库(0个评论)
    • 在Laravel项目中使用中间件方式统计用户在线时长功能代码示例(0个评论)
    • 在Laravel中构建业务流程模型(0个评论)
    • windows系统中安装FFMpeg及在phpstudy环境php7.3 + php-ffmpeg扩展的使用流程步骤(0个评论)
    • 在go语言中对浮点的数组、切片(slice)进行正向排序和反向排序(0个评论)
    • 在go语言中对整数数组、切片(slice)进行排序和反向排序(0个评论)
    • 在go语言中对字符串数组、切片(slice)进行排序和反向排序(0个评论)
    • 最新国内免注册ChatGPT体验站_ChatGPT镜像站访问链接地址2023/3/28持续更新(0个评论)
    • 在Laravel项目中的实现无密码认证之:发送邮箱链接授权(0个评论)
    • 近期评论
    • 博主 在

      2023年国务院办公厅春节放假通知:1月21日起休7天中评论 @ xiaoB 你只管努力,剩下的叫给天意;天若有情天亦老,..
    • xiaoB 在

      2023年国务院办公厅春节放假通知:1月21日起休7天中评论 会不会春节放假后又阳一次?..
    • BUG4 在

      你翻墙过吗?国内使用vpn翻墙可能会被网警抓,你需了解的事中评论 不是吧?..
    • 博主 在

      go语言+beego框架中获取get,post请求的所有参数中评论 @ t1  直接在router.go文件中配就ok..
    • Jade 在

      如何在MySQL查询中获得当月记录中评论 Dear zongscan.com team, We can skyroc..
    • 2017-10
    • 2018-01
    • 2020-03
    • 2021-06
    • 2021-10
    • 2022-03
    • 2023-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客