微信小程序與公眾號實(shí)現(xiàn)數(shù)據(jù)互通的方法
公司因小程序項目先上線,公眾號后開發(fā),接到上級的安排實(shí)現(xiàn)小程序打通任務(wù),看文檔后發(fā)現(xiàn):同一開發(fā)者賬號只要是在微信開放平臺綁定小程序與公眾號以后,會有一個唯一的unionid,這個unionid騰訊公司下產(chǎn)品共享。這個unionid就是我們進(jìn)行打通的關(guān)鍵。
先說一下思路:
1.微信小程序與公眾號進(jìn)行綁定后,在小程序調(diào)用wx.login()方法后會自動獲取unionid,公眾號根據(jù)官方文檔在獲取用戶基本信息后會拿到相同的unionid,openid,nickname。。。等相關(guān)信息;
2.將小程序拿到的unionid進(jìn)行數(shù)據(jù)庫的更新操作,公眾號拿到的unionid等信息,新建數(shù)據(jù)庫表A進(jìn)行存儲;(注:在這一步,因為我們公司的原因,我們的公眾號之前就有人關(guān)注了,那么在這之前,我通過公眾號獲取關(guān)注用戶列表獲取openid的列表,進(jìn)行循環(huán)openid列表,在調(diào)用公眾號獲取用戶基本信息列表進(jìn)行儲存數(shù)據(jù)庫表A,循環(huán)結(jié)束后之前關(guān)注的人的信息就儲存在數(shù)據(jù)庫A,然后在進(jìn)行,這一步的操作)
3.通過公眾號關(guān)注/取關(guān)的事件相應(yīng),來進(jìn)行數(shù)據(jù)庫表A的增刪操作,維護(hù)數(shù)據(jù)的新鮮度;
4.進(jìn)行關(guān)聯(lián)查詢,到這一步我們會發(fā)現(xiàn),通過unionid進(jìn)行表的關(guān)聯(lián)后我們已經(jīng)實(shí)現(xiàn)數(shù)據(jù)的互通了
洋洋灑灑的說了一大堆,其實(shí)就是公眾號的兩個接口至關(guān)重要(1.關(guān)注/取關(guān)的事件相應(yīng)接口 2.獲取用戶的基本信息接口)
有關(guān)于公眾號的安全域名配置,服務(wù)器域名配置以及獲取token就不在這里說了,百度一下一大堆。
代碼實(shí)現(xiàn):
第一步,獲取公眾號用戶的openid列表操作,根據(jù)opneid進(jìn)進(jìn)行用戶的基本信息的查詢,存入數(shù)據(jù)庫操作(因為我們公司的公眾號關(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();
List<String> openIdList=null;
if(null!=wxOpenidInfo) {
openIdList=wxOpenidInfo.getOpenid();//公眾號返回的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ù)庫表A的儲存操作
int row = gzhService.addGZHUser(wxUser);
}
}
}
/**
* 用戶列表
* @author 一葉知秋plus
*
*/
public class WeixinUserList{
private Integer total;//關(guān)注該公眾賬號的總用戶數(shù)
private Integer count;//拉取的OPENID個數(shù),最大值為10000
private WxOpenidInfo data;//列表數(shù)據(jù),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;// 用戶是否訂閱該公眾號標(biāo)識,值為0時,代表此用戶沒有關(guān)注該公眾號,拉取不到其余信息。
private String openid;// 用戶的標(biāo)識,對當(dāng)前公眾號唯一
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;//用戶被打上的標(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<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;
}
}
步驟二:關(guān)注/取關(guān)的事件響應(yīng)接口
/**
* 請求校驗工具類
*/
public class SignUtil {
// 與接口配置信息中的Token要一致,我的是明文格式
private static String token = "填寫你服務(wù)器配置時寫的token";
public static boolean checkSignature(String signature, String timestamp,
String nonce) {
//從請求中(也就是微信服務(wù)器傳過來的)拿到的token, timestamp, nonce
String[] arr = new String[] { token, timestamp, nonce };
// 將token、timestamp、nonce三個參數(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");
// 將三個參數(shù)字符串拼接成一個字符串進(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對比,標(biāo)識該請求來源于微信
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");
// 時間戳
String timestamp = request.getParameter("timestamp");
// 隨機(jī)數(shù)
String nonce = request.getParameter("nonce");
// 隨機(jī)字符串
String echostr = request.getParameter("echostr");
PrintWriter out = response.getWriter();
// 通過檢驗signature對請求進(jìn)行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
//在這里相應(yīng)微信的操作
}
try {
Map<String, String> map = XmlUtil.xmlToMap(request);
String fromUserName = map.get("FromUserName");//消息來源用戶標(biāo)識
String toUserName = map.get("ToUserName");//消息目的用戶標(biāo)識
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ù)庫的操作
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ù)庫的操作
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)容不容錯過?。?!");
}
/*
* 響應(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<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;
}
/*
* 文本消息對象轉(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ù)庫中有了小程序opneid unionid 公眾號opneid unionid等用戶信息,進(jìn)行關(guān)聯(lián)后就可以進(jìn)行數(shù)據(jù)的查詢操作,當(dāng)然小程序也可以發(fā)送公眾號模板的相應(yīng)操作了。如果有更好的實(shí)現(xiàn)方式,歡迎各位大佬不吝賜教~
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
正則中的回溯定義與用法分析【JS與java實(shí)現(xiàn)】
這篇文章主要介紹了正則中的回溯定義與用法,結(jié)合實(shí)例形式分析了回溯的概念、功能并提供了JS與java實(shí)現(xiàn)方法,需要的朋友可以參考下2016-12-12
js檢測IE8及以下瀏覽器版本并做出提示的函數(shù)代碼
這篇文章主要介紹了js檢測IE8及以下瀏覽器版本并做出提示的函數(shù)代碼,需要的朋友可以參考下2023-02-02

