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


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 相关文章推荐
DOM相关内容速查手册
Feb 07 Javascript
基于Jquery的动态添加控件并取值的实现代码
Sep 24 Javascript
JQuery的AJAX实现文件下载的小例子
May 15 Javascript
JS自定义选项卡函数及用法实例分析
Sep 02 Javascript
简单谈谈Vue 模板各类数据绑定
Sep 25 Javascript
JavaScript实现自定义媒体播放器方法介绍
Jan 03 Javascript
assert()函数用法总结(推荐)
Jan 25 Javascript
Vue2.0点击切换类名改变样式的方法
Aug 22 Javascript
如何解决React官方脚手架不支持Less的问题(小结)
Sep 12 Javascript
Vue中对iframe实现keep alive无刷新的方法
Jul 23 Javascript
d3.js实现图形缩放平移
Dec 19 Javascript
Vue实现浏览器打印功能的代码
Apr 17 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实现的下载css文件中的图片的代码
2010/02/08 PHP
JavaScript 获取用户客户端操作系统版本
2009/08/25 Javascript
基于jQuery的一个扩展form序列化到json对象
2010/12/09 Javascript
JSON语法五大要素图文介绍
2012/12/04 Javascript
js/jQuery对象互转(快速操作dom元素)
2013/02/04 Javascript
JavaScript给按钮绑定点击事件(onclick)的方法
2015/04/07 Javascript
jQuery实现的网页左侧在线客服效果代码
2015/10/23 Javascript
整理Javascript函数学习笔记
2015/12/01 Javascript
jquery正则表达式验证(手机号、身份证号、中文名称)
2015/12/31 Javascript
JavaScript Array对象详解
2016/03/01 Javascript
浅析JavaScript函数的调用模式
2016/08/10 Javascript
JavaScript代码里的判断小结
2016/08/22 Javascript
react实现pure render时bind(this)隐患需注意!
2017/03/09 Javascript
jQuery实现简单的手风琴效果
2020/04/17 jQuery
vue移动UI框架滑动加载数据的方法
2018/03/12 Javascript
微信小程序实现聊天对话(文本、图片)功能
2018/07/06 Javascript
JS操作Fckeditor的一些常用方法(获取、插入等)
2020/02/19 Javascript
python采用requests库模拟登录和抓取数据的简单示例
2014/07/05 Python
跟老齐学Python之print详解
2014/09/28 Python
Python contextlib模块使用示例
2015/02/18 Python
浅谈python多线程和队列管理shell程序
2015/08/04 Python
Python 装饰器使用详解
2017/07/29 Python
python 实现查找文件并输出满足某一条件的数据项方法
2019/06/12 Python
python调用pyaudio使用麦克风录制wav声音文件的教程
2019/06/26 Python
Python实现代码统计工具
2019/09/19 Python
利用django创建一个简易的博客网站的示例
2020/09/29 Python
解决TensorFlow训练模型及保存数量限制的问题
2021/03/03 Python
基于CSS3实现的黑色个性导航菜单效果
2015/09/14 HTML / CSS
销售简历自我评价
2014/01/24 职场文书
优秀安全员事迹材料
2014/05/11 职场文书
安全宣传标语
2014/06/10 职场文书
暑期社会实践个人总结
2015/03/06 职场文书
四年级语文教学反思
2016/03/03 职场文书
高效笔记技巧分享:学会这些让你不再困扰
2019/09/04 职场文书
CSS3 制作的图片滚动效果
2021/04/14 HTML / CSS
使用kubeadm命令行工具创建kubernetes集群
2022/03/31 Servers