公司因小程序項(xiàng)目先上線,公眾號(hào)后開發(fā),接到上級(jí)的安排實(shí)現(xiàn)小程序打通任務(wù),看文檔后發(fā)現(xiàn):同一開發(fā)者賬號(hào)只要是在微信開放平臺(tái)綁定小程序與公眾號(hào)以后,會(huì)有一個(gè)唯一的unionid,這個(gè)unionid騰訊公司下產(chǎn)品共享。這個(gè)unionid就是我們進(jìn)行打通的關(guān)鍵。
創(chuàng)新互聯(lián)專注于雙橋企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè)公司,電子商務(wù)商城網(wǎng)站建設(shè)。雙橋網(wǎng)站建設(shè)公司,為雙橋等地區(qū)提供建站服務(wù)。全流程定制網(wǎng)站開發(fā),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
先說一下思路:
1.微信小程序與公眾號(hào)進(jìn)行綁定后,在小程序調(diào)用wx.login()方法后會(huì)自動(dòng)獲取unionid,公眾號(hào)根據(jù)官方文檔在獲取用戶基本信息后會(huì)拿到相同的unionid,openid,nickname。。。等相關(guān)信息;
2.將小程序拿到的unionid進(jìn)行數(shù)據(jù)庫(kù)的更新操作,公眾號(hào)拿到的unionid等信息,新建數(shù)據(jù)庫(kù)表A進(jìn)行存儲(chǔ);(注:在這一步,因?yàn)槲覀児镜脑?,我們的公眾?hào)之前就有人關(guān)注了,那么在這之前,我通過公眾號(hào)獲取關(guān)注用戶列表獲取openid的列表,進(jìn)行循環(huán)openid列表,在調(diào)用公眾號(hào)獲取用戶基本信息列表進(jìn)行儲(chǔ)存數(shù)據(jù)庫(kù)表A,循環(huán)結(jié)束后之前關(guān)注的人的信息就儲(chǔ)存在數(shù)據(jù)庫(kù)A,然后在進(jìn)行,這一步的操作)
3.通過公眾號(hào)關(guān)注/取關(guān)的事件相應(yīng),來進(jìn)行數(shù)據(jù)庫(kù)表A的增刪操作,維護(hù)數(shù)據(jù)的新鮮度;
4.進(jìn)行關(guān)聯(lián)查詢,到這一步我們會(huì)發(fā)現(xiàn),通過unionid進(jìn)行表的關(guān)聯(lián)后我們已經(jīng)實(shí)現(xiàn)數(shù)據(jù)的互通了
洋洋灑灑的說了一大堆,其實(shí)就是公眾號(hào)的兩個(gè)接口至關(guān)重要(1.關(guān)注/取關(guān)的事件相應(yīng)接口 2.獲取用戶的基本信息接口)
有關(guān)于公眾號(hào)的安全域名配置,服務(wù)器域名配置以及獲取token就不在這里說了,百度一下一大堆。
代碼實(shí)現(xiàn):
第一步,獲取公眾號(hào)用戶的openid列表操作,根據(jù)opneid進(jìn)進(jìn)行用戶的基本信息的查詢,存入數(shù)據(jù)庫(kù)操作(因?yàn)槲覀児镜墓娞?hào)關(guān)注人數(shù)只有1000+,所以我只調(diào)用了一次獲取關(guān)注列表的接口)
//主要代碼邏輯 //獲取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();//關(guān)注總?cè)藬?shù) //用戶openId 列表 WxOpenidInfo wxOpenidInfo=userList.getData(); ListopenIdList=null; if(null!=wxOpenidInfo) { openIdList=wxOpenidInfo.getOpenid();//公眾號(hào)返回的openid列表數(shù)據(jù) if(null!=openIdList && openIdList.size()>0) { for(String opendid:openIdList) { //獲取用戶的基本信息(unionid機(jī)制) 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); //進(jìn)行數(shù)據(jù)庫(kù)表A的儲(chǔ)存操作 int row = gzhService.addGZHUser(wxUser); } } } /** * 用戶列表 * @author 一葉知秋plus * */ public class WeixinUserList{ private Integer total;//關(guān)注該公眾賬號(hào)的總用戶數(shù) private Integer count;//拉取的OPENID個(gè)數(shù),最大值為10000 private WxOpenidInfo data;//列表數(shù)據(jù),OPENID的列表 private String next_openid;//拉取列表的最后一個(gè)用戶的OPENID private int errcode;//錯(cuò)誤編碼 private String errmsg="ok";//錯(cuò)誤提示 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;// 用戶是否訂閱該公眾號(hào)標(biāo)識(shí),值為0時(shí),代表此用戶沒有關(guān)注該公眾號(hào),拉取不到其余信息。 private String openid;// 用戶的標(biāo)識(shí),對(duì)當(dāng)前公眾號(hào)唯一 private String nickname;// 用戶的昵稱 private String sex;// 用戶的性別,值為1時(shí)是男性,值為2時(shí)是女性,值為0時(shí)是未知 private String city;// 用戶所在城市 private String country;// 用戶所在國(guó)家 private String province;// 用戶所在省份 private String language;// 用戶的語(yǔ)言,簡(jiǎn)體中文為zh_CN private List tagid_list;//用戶被打上的標(biāo)簽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; } }
步驟二:關(guān)注/取關(guān)的事件響應(yīng)接口
/** * 請(qǐng)求校驗(yàn)工具類 */ public class SignUtil { // 與接口配置信息中的Token要一致,我的是明文格式 private static String token = "填寫你服務(wù)器配置時(shí)寫的token"; public static boolean checkSignature(String signature, String timestamp, String nonce) { //從請(qǐng)求中(也就是微信服務(wù)器傳過來的)拿到的token, timestamp, nonce String[] arr = new String[] { token, timestamp, nonce }; // 將token、timestamp、nonce三個(gè)參數(shù)進(jìn)行字典序排序 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"); // 將三個(gè)參數(shù)字符串拼接成一個(gè)字符串進(jìn)行sha1加密 byte[] digest = md.digest(content.toString().getBytes()); //將字節(jié)數(shù)組轉(zhuǎn)成字符串 tmpStr = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } content = null; // 將sha1加密后的字符串可與signature對(duì)比,標(biāo)識(shí)該請(qǐng)求來源于微信 return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; } //將加密后的字節(jié)數(shù)組變成字符串 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; } } } } } //事件響應(yīng)的接口 @RequestMapping(value="/GZHConcern.do") public void GZHConcern(HttpServletRequest request, HttpServletResponse response) throws IOException { String message = "success"; // 微信加密簽名 String signature = request.getParameter("signature"); // 時(shí)間戳 String timestamp = request.getParameter("timestamp"); // 隨機(jī)數(shù) String nonce = request.getParameter("nonce"); // 隨機(jī)字符串 String echostr = request.getParameter("echostr"); PrintWriter out = response.getWriter(); // 通過檢驗(yàn)signature對(duì)請(qǐng)求進(jìn)行校驗(yàn),若校驗(yàn)成功則原樣返回echostr,表示接入成功,否則接入失敗 if (SignUtil.checkSignature(signature, timestamp, nonce)) { out.print(echostr); //在這里相應(yīng)微信的操作 } try { Mapmap = XmlUtil.xmlToMap(request); String fromUserName = map.get("FromUserName");//消息來源用戶標(biāo)識(shí) String toUserName = map.get("ToUserName");//消息目的用戶標(biāo)識(shí) String msgType = map.get("MsgType");//消息類型 String content = map.get("Content");//消息內(nèi)容 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); //進(jìn)行數(shù)據(jù)庫(kù)的操作 weixinUser.setNickname(weixinUser.getNickname()); int row = gzhService.addGZHUser(weixinUser); //通過openid獲取用戶的數(shù)據(jù) message = MessageUtil.subscribeForText(toUserName, fromUserName); }else if(MessageUtil.MESSAGE_UNSUBSCIBE.equals(eventType)){//處理取消訂閱事件 message = MessageUtil.unsubscribe(toUserName, fromUserName); weixinUser.setOpenid(fromUserName); //進(jìn)行數(shù)據(jù)庫(kù)的操作 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); } /* * 響應(yīng)訂閱事件--回復(fù)文本消息 */ public static String subscribeForText(String toUserName,String fromUserName){ return textMsg(toUserName, fromUserName, "歡迎關(guān)注,精彩內(nèi)容不容錯(cuò)過?。?!"); } /* * 響應(yīng)取消訂閱事件 */ public static String unsubscribe(String toUserName,String fromUserName){ //TODO 可以進(jìn)行取關(guān)后的其他后續(xù)業(yè)務(wù)處理 System.out.println("用戶:"+ fromUserName +"取消關(guān)注~"); return ""; } } /* * xml處理工具類 */ public class XmlUtil { /* * xml轉(zhuǎn)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; } /* * 文本消息對(duì)象轉(zhuǎn)xml */ public static String textMsgToxml(TextMessage textMessage){ XStream xstream = new XStream(); xstream.alias("xml", textMessage.getClass()); return xstream.toXML(textMessage); } }
ok,到這一步數(shù)據(jù)庫(kù)中有了小程序opneid unionid 公眾號(hào)opneid unionid等用戶信息,進(jìn)行關(guān)聯(lián)后就可以進(jìn)行數(shù)據(jù)的查詢操作,當(dāng)然小程序也可以發(fā)送公眾號(hào)模板的相應(yīng)操作了。如果有更好的實(shí)現(xiàn)方式,歡迎各位大佬不吝賜教~
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。