视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
微信小程序与公众号实现数据互通的方法
2020-11-27 21:53:15 责编:小采
文档


公司因小程序项目先上线,公众号后开发,接到上级的安排实现小程序打通任务,看文档后发现:同一开发者账号只要是在微信开放平台绑定小程序与公众号以后,会有一个唯一的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等用户信息,进行关联后就可以进行数据的查询操作,当然小程序也可以发送公众号模板的相应操作了。如果有更好的实现方式,欢迎各位大佬不吝赐教~

下载本文
显示全文
专题