微信小程序與公衆號打通,實現數據互通

公司因小程序項目先上線,公衆號後開發,接到上級的安排實現小程序打通任務,看文檔後發現:同一開發者賬號只要是在微信開放平臺綁定小程序與公衆號以後,會有一個唯一的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 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等用戶信息,進行關聯後就可以進行數據的查詢操作,當然小程序也可以發送公衆號模板的相應操作了。如果有更好的實現方式,歡迎各位大佬不吝賜教~

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章