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


Posted in Javascript onJuly 25, 2019

公司因小程序项目先上线,公众号后开发,接到上级的安排实现小程序打通任务,看文档后发现:同一开发者账号只要是在微信开放平台绑定小程序与公众号以后,会有一个唯一的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=";//获取所有用户openid
JSONObject 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<String> 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<String> 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<String> getTagid_list() {
 return tagid_list;
 }
 public void setTagid_list(List<String> tagid_list) {
 this.tagid_list = tagid_list;
 }
}
 
 
public class WxOpenidInfo {
 private List<String> openid;
 
  public List<String> getOpenid() {
    return openid;
  }
 
  public void setOpenid(List<String> 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<String, String> 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<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException{
 HashMap<String, String> map = new HashMap<String,String>();
 SAXReader reader = new SAXReader();
 
 InputStream ins = request.getInputStream();
 Document doc = reader.read(ins);
 
 Element root = doc.getRootElement();
 @SuppressWarnings("unchecked")
 List<Element> list = (List<Element>)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等用户信息,进行关联后就可以进行数据的查询操作,当然小程序也可以发送公众号模板的相应操作了。如果有更好的实现方式,欢迎各位大佬不吝赐教~

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

Javascript 相关文章推荐
jQuery 常见开发使用技巧总结
Dec 26 Javascript
Ubuntu 11.10 安装Node.js的方法
Nov 30 Javascript
用js调用迅雷下载代码的二种方法
Apr 15 Javascript
Node.js中对通用模块的封装方法
Jun 06 Javascript
JavaScript函数模式详解
Nov 07 Javascript
当jquery ajax遇上401请求的解决方法
May 19 Javascript
详解Jquery Easyui的验证扩展
Jan 09 Javascript
JavaScript关联数组用法分析【概念、定义、遍历】
Mar 15 Javascript
利用JavaScript对中文(汉字)进行排序实例详解
Jun 18 Javascript
详解Vue单元测试Karma+Mocha学习笔记
Jan 31 Javascript
vue组件(全局,局部,动态加载组件)
Sep 02 Javascript
详解如何在Node.js的httpServer中接收前端发送的arraybuffer数据
Nov 11 Javascript
微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡)
Jul 25 #Javascript
微信小程序实现收货地址左滑删除
Nov 18 #Javascript
jquery-ui 进度条功能示例【测试可用】
Jul 25 #jQuery
微信小程序实现左滑动删除效果
Mar 30 #Javascript
jquery ui 实现 tab标签功能示例【测试可用】
Jul 25 #jQuery
小程序实现左滑删除效果
Jul 25 #Javascript
微信公众号获取用户地理位置并列出附近的门店的示例代码
Jul 25 #Javascript
You might like
php+mysql 实现身份验证代码
2010/03/24 PHP
PHP数组无限分级数据的层级化处理代码
2012/12/29 PHP
php Hex RGB颜色值互换的使用
2013/05/10 PHP
JavaScript 浏览器验证代码(来自discuz)
2010/07/17 Javascript
jQuery仿360导航页图标拖动排序效果代码分享
2015/08/24 Javascript
jquery带动画效果幻灯片特效代码
2015/08/27 Javascript
Node.js如何自动审核团队的代码
2016/07/20 Javascript
浅谈JS中的!=、== 、!==、===的用法和区别
2016/09/24 Javascript
Javascript之面向对象--方法
2016/12/02 Javascript
AngularJS定时器的使用与移除操作方法【interval与timeout】
2016/12/14 Javascript
javascript基于定时器实现进度条功能实例
2017/10/13 Javascript
详解mpvue scroll-view自动回弹bug解决方案
2018/10/01 Javascript
Vue CLI2升级至Vue CLI3的方法步骤
2019/05/20 Javascript
ES6中字符串的使用方法扩展
2019/06/04 Javascript
[43:43]完美世界DOTA2联赛PWL S2 FTD.C vs Rebirth 第一场 11.22
2020/11/24 DOTA
[54:10]完美世界DOTA2联赛PWL S2 Magma vs FTD 第二场 11.29
2020/12/03 DOTA
下载糗事百科的内容_python版
2008/12/07 Python
如何在django里上传csv文件并进行入库处理的方法
2019/01/02 Python
Django 迁移、操作数据库的方法
2019/08/02 Python
对Django的restful用法详解(自带的增删改查)
2019/08/28 Python
Python函数中的可变长参数详解
2019/09/12 Python
利用Python制作动态排名图的实现代码
2020/04/09 Python
Python + opencv对拍照得到的图片进行背景去除的实现方法
2020/11/18 Python
使用phonegap获取位置信息的实现方法
2017/03/31 HTML / CSS
世界上最大的专业美容用品零售商:Sally Beauty
2017/07/02 全球购物
Hotels.com台湾:饭店订房网
2017/09/06 全球购物
康拓普公司Java笔面试
2016/09/23 面试题
电气工程师岗位职责
2014/01/01 职场文书
单位单身证明范本
2014/01/11 职场文书
协议书格式
2014/04/23 职场文书
数学兴趣小组活动总结
2014/07/08 职场文书
公司员工活动策划方案
2014/08/20 职场文书
四风问题党员个人整改措施
2014/10/27 职场文书
财务总监岗位职责
2015/02/03 职场文书
2015年学校减负工作总结
2015/05/19 职场文书
Nginx服务器如何设置url链接
2021/03/31 Servers