微信小程序与公众号打通,实现数据互通

news/2024/11/9 4:55:16/

公司因小程序项目先上线,公众号后开发,接到上级的安排实现小程序打通任务,看文档后发现:同一开发者账号只要是在微信开放平台绑定小程序与公众号以后,会有一个唯一的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个数,最大值为10000private WxOpenidInfo data;//列表数据,OPENID的列表private String next_openid;//拉取列表的最后一个用户的OPENIDprivate 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_CNprivate List<String> tagid_list;//用户被打上的标签ID列表private String unionid;  //用户的unionidprivate 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, nonceString[] 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)){//处理订阅事件//获取tokenString 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 blocke.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等用户信息,进行关联后就可以进行数据的查询操作,当然小程序也可以发送公众号模板的相应操作了。

 

如果有更好的实现方式,欢迎各位大佬不吝赐教~

 


http://www.ppmy.cn/news/709533.html

相关文章

Spring中bean使用方法

Spring框架是一个非常重要的开发工具&#xff0c;它提供了丰富的功能和模块&#xff0c;其中核心的概念之一就是Spring Bean。Spring Bean是Spring IoC容器中的一个对象&#xff0c;它负责管理一个Java对象的生命周期以及依赖注入。下面我将通过互联网场景下的相关背景内容来阐…

湖北广电机顶盒(九联HDC-2100K)安装第3方app保姆教程

写这篇的原因&#xff0c;家中1台设备&#xff0c;父母需要看广电的电视频道节目&#xff0c;偶尔自己也看看腾讯视频什么的&#xff0c;用的是九联2100K&#xff0c;和另外的TV盒子&#xff0c;一直两设备来回切换 在本坛区&#xff0c;看见有之前高人smartpc &#xff1b; …

MIT 6.S081 教材第七章内容 -- 调度 --下

MIT 6.S081 教材第七章内容 -- 调度 -- 下 引言调度多路复用代码&#xff1a;上下文切换代码&#xff1a;调度代码&#xff1a;mycpu和myprocsleep与wakeup代码&#xff1a;sleep和wakeup代码&#xff1a;Pipes代码&#xff1a;wait, exit和kill真实世界练习 引言 MIT 6.S081 …

7.2.2 【Linux】实体链接与符号链接:ln

在Linux下面的链接文件中有两种&#xff0c;一种是类似Windows的捷径功能的文件&#xff0c;可以快速链接到目标文件&#xff08;或目录&#xff09;&#xff1b;另一种是通过文件系统的inode链接来产生新文件名&#xff0c;而不是产生新文件。这种称为实体链接&#xff08;har…

Android音量控制调节

//音量控制,初始化定义 AudioManager mAudioManager (AudioManager) getSystemService(Context.AUDIO_SERVICE); //最大音量 int maxVolume mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); //当前音量 int currentVolume mAudioManager.getStreamVolum…

如何调节音频音量大小?

如何调节音频音量大小&#xff1f;我们经常会通过手机、电脑等设备来播放音频文件&#xff0c;当觉得音量较小的时候&#xff0c;我们会一般会通过调整播放器的声音开到最大&#xff0c;如果你用手机播放&#xff0c;只需要按两侧的“&#xff0b;”按钮来提高音量大小&#xf…

如何把音频文件音量调大?三种方法帮你放大音频音量

大家想象一下&#xff0c;当你正在观看一部电影或听一首音乐&#xff0c;但由于音频的音量太小了&#xff0c;需要我们自己不断调整音量才能勉强听得清楚&#xff0c;这对于我们来说一种很糟糕的体验。其实这个时候&#xff0c;我们可以借助一些音频编辑处理工具来进行音量调整…

Android音频 —— 音量调节

一、音量相关概念 1. 相关术语解释 track volume : 单个App设置音量时设置的是这个&#xff0c;它只影响本App的音量。stream volume &#xff1a;设置某一stream的音量&#xff0c;Android系统中支持10种stream。stream volume alias&#xff1a;设置的是同一组stream的音量…