1. 程式人生 > >微信公眾號java開發沉澱(四)獲取使用者資訊

微信公眾號java開發沉澱(四)獲取使用者資訊

​ 關注公眾號後,公眾號可獲得關注者的OpenID(加密後的微訊號,每個使用者對每個公眾號的OpenID是唯一的。對於不同公眾號,同一使用者的openid不同)。公眾號可通過OpenID獲取使用者基本資訊,包括暱稱、頭像、性別、所在城市、語言和關注時間。

​ 如果開發者有在多個公眾號,或在公眾號、移動應用之間統一使用者帳號的需求,需要前往微信開放平臺(open.weixin.qq.com)繫結公眾號後,才可利用UnionID機制來滿足上述需求。

​ 一個微信使用者對一個公眾號OpenID 是唯一的。一個微信使用者對同一個微信開放平臺UnionID是唯一的。

獲取OpenID前,先要獲取code

在微信裡面引導關注者開啟如下頁面(測試方便起見可以直接把url當成普通訊息通過檔案傳輸助手發到微信上,然後直接點這個連結,效果一樣):

如果使用者同意授權,頁面將跳轉至 redirect_uri?code=CODE&state=STATE 就這樣code自動生成了。會帶進重定向的url的後面引數中。

redirect_uri 是我們java專案提供的一個URL,接收兩個引數:code 和 state。注意redirect_uri 需要URL編碼。

url 編碼以後是 https%3a%2f%2f60cc9d13.ngrok.io%2fwx%2fapi%2fuserInfo

把這個url發到微信,點選,就可以直接訪問了。下面有程式碼和tomcat日誌。

根據code獲取OpenId

訪問

https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APPID}&secret=${APPSECRET}&code=${CODE}&grant_type=authorization_code

返回包含openId的json物件。

獲取access_token

訪問

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}

返回包含accessToken的json物件

獲取使用者資訊

訪問

https://api.weixin.qq.com/cgi-bin/user/info?access_token=${ACCESS_TOKEN}&openid=${OPENID}&lang=zh_CN

返回使用者資訊,注意如果使用了開放平臺,才有unionid。否則unionid為null.

程式碼demo,簡單起見所有東西都放一個類裡了.

不要亂用我的appId和SECRET

package com.tsing.wechat.controller;

import com.alibaba.fastjson.JSON;
import com.tsing.wechat.model.AccessToken;
import com.tsing.wechat.model.WeChatUserInfo;
import com.tsing.wechat.model.WebToken;
import com.tsing.wechat.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrSubstitutor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/api")
public class WxUserInfoController {

    public static final String APP_ID = "APPID";
    public static final String APP_ID_VALUE = "wx5087e91fe1430b1d";
    public static final String APP_SECRET = "APPSECRET";
    public static final String APP_SECRET_VALUE = "*****";
    public static final String CODE = "CODE";

    public static final String ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}";

    private static final String ACCESS_TOKEN_CODE = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APPID}&secret=${APPSECRET}&code=${CODE}&grant_type=authorization_code";

    private static final String USER_INFO = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=${ACCESS_TOKEN}&openid=${OPENID}&lang=zh_CN";

    /**
     * 根據code獲取網頁授權使用者的openid
     */
    @RequestMapping(value = "/userInfo")
    public WeChatUserInfo getUserInfo(@RequestParam String code, @RequestParam String state) {
        String openId = getWebAccessToken(APP_ID_VALUE, APP_SECRET_VALUE, code);
        log.debug("根據code=" + code + "獲取openId值為:" + openId);
        String accessToken = getAccessToken(APP_ID_VALUE, APP_SECRET_VALUE);
        WeChatUserInfo userInfo = getWeChatUserInfo(accessToken, openId);
        log.info("使用者資訊:{}", userInfo);
        return userInfo;
    }

    public WeChatUserInfo getWeChatUserInfo(String accessToken, String openId) {
        Map<String, String> map = new HashMap<>();
        map.put("ACCESS_TOKEN", accessToken);
        map.put("OPENID", openId);
        String usrInfoUrl = urlReplace(USER_INFO, map);
        log.info("獲取到的使用者資訊url:{}", usrInfoUrl);
        String useStr = HttpUtils.doGet(usrInfoUrl);
        log.info("獲取到的使用者資訊為:{}", useStr);
        return JSON.parseObject(useStr, WeChatUserInfo.class);
    }

    public String getWebAccessToken(String appId, String secret, String code) {
        Map<String, String> map = new HashMap<>();
        map.put(APP_ID, appId);
        map.put(APP_SECRET, secret);
        map.put(CODE, code);
        String url = urlReplace(ACCESS_TOKEN_CODE, map);
        log.info("獲取網頁token的URL:{}", url);
        String res = HttpUtils.doGet(url);
        log.info("獲取網頁token的返回:{}", res);
        WebToken token = JSON.parseObject(res, WebToken.class);
        return token.getOpenId();
    }

    public String getAccessToken(String appId, String secret) {
        Map<String, String> map = new HashMap<>();
        map.put(APP_ID, appId);
        map.put(APP_SECRET, secret);
        String url = urlReplace(ACCESS_TOKEN, map);
        String res = HttpUtils.doGet(url);
        log.info("獲取token返回:{}", res);
        AccessToken token = JSON.parseObject(res, AccessToken.class);
        return token.getAccessToken();
    }

    /**
     * 將URL中的模板引數用實際值替換
     *
     * @param url url
     * @param parms 引數
     * @return 替換引數後的url
     */
    public static String urlReplace(String url, Map<String, String> parms) {
        if (StringUtils.isNotBlank(url) && null != parms) {
            StrSubstitutor strsub = new StrSubstitutor(parms);
            url = strsub.replace(url);
        }
        return url;
    }
}

日誌,因為只是一個測試公眾號,沒有繫結微信開放平臺,所以最後一行日誌大的unionid=null

2018-10-16 10:23:04.467 INFO  [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getWebAccessToken:71 -獲取網頁token的URL:https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx5087e91fe1430b1d&secret=b6428efc6c87d5b8cd29bc757407d8e6&code=07113uKn1wh6si0TCtKn1YpsKn113uK7&grant_type=authorization_code
2018-10-16 10:23:04.669 INFO  [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getWebAccessToken:73 -獲取網頁token的返回:{"access_token":"14_wDfP5QFeN-R8fhq8WgZRuapJGnQSz5lQrI4cOqc6CDAuqJvaeO-FBKJV6f2b6EEUVy-a3TNTBgBDky00M6okPA","expires_in":7200,"refresh_token":"14_mQTvjt1tglGSN82bqxa2XKqRmqdI0slBKGzLkOUlpzR-rPOIwrzMT3HWbgFp3US1zoafY5dF_I4O-yG2spvGgQ","openid":"o-7aj0hBDfVEzsK2P_F9U-IwosZ4","scope":"snsapi_userinfo"}
2018-10-16 10:23:04.670 DEBUG [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getUserInfo:47 -根據code=07113uKn1wh6si0TCtKn1YpsKn113uK7獲取openId值為:o-7aj0hBDfVEzsK2P_F9U-IwosZ4
2018-10-16 10:23:04.854 INFO  [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getAccessToken:84 -獲取token返回:{"access_token":"14_xEbh6Hq5U0MXjAmlEUY88dcm5BrRB7lPnLgcgiIzZE9zkOsUsry1Ms57hKJGIqmXKwakgn10V4MqtGx_zCVrHW3HRpjCQiY6zji2itWpgvN3kNBS1NAJAUK5jNjpHTrLuOisDIIH24L5yZbHNITdAGAXSD","expires_in":7200}
2018-10-16 10:23:04.854 INFO  [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getWeChatUserInfo:59 -獲取到的使用者資訊url:https://api.weixin.qq.com/cgi-bin/user/info?access_token=14_xEbh6Hq5U0MXjAmlEUY88dcm5BrRB7lPnLgcgiIzZE9zkOsUsry1Ms57hKJGIqmXKwakgn10V4MqtGx_zCVrHW3HRpjCQiY6zji2itWpgvN3kNBS1NAJAUK5jNjpHTrLuOisDIIH24L5yZbHNITdAGAXSD&openid=o-7aj0hBDfVEzsK2P_F9U-IwosZ4&lang=zh_CN
2018-10-16 10:23:05.017 INFO  [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getWeChatUserInfo:61 -獲取到的使用者資訊為:{"subscribe":1,"openid":"o-7aj0hBDfVEzsK2P_F9U-IwosZ4","nickname":"_captain","sex":1,"language":"zh_CN","city":"杭州","province":"浙江","country":"中國","headimgurl":"http:\/\/thirdwx.qlogo.cn\/mmopen\/9RibwCfvUfQNnmNiarD2S8A8YNHC4IGOLgzSBRMaeyDSG0JBpmHXZLNOxqJypjnib8vFkDUCbn5IicLvL4ibDps5LvzAEZs5FjQiaib\/132","subscribe_time":1539600947,"remark":"","groupid":0,"tagid_list":[],"subscribe_scene":"ADD_SCENE_QR_CODE","qr_scene":0,"qr_scene_str":""}
2018-10-16 10:23:05.038 INFO  [http-nio-8080-exec-2]com.tsing.wechat.controller.WxUserInfoController.getUserInfo:50 -使用者資訊:WeChatUserInfo(openid=o-7aj0hBDfVEzsK2P_F9U-IwosZ4, subscribe=1, subscribeTime=null, nickName=_captain, sex=1, country=中國, province=浙江, city=杭州, language=zh_CN, headImgUrl=http://thirdwx.qlogo.cn/mmopen/9RibwCfvUfQNnmNiarD2S8A8YNHC4IGOLgzSBRMaeyDSG0JBpmHXZLNOxqJypjnib8vFkDUCbn5IicLvL4ibDps5LvzAEZs5FjQiaib/132, unionid=null)

不要亂用我的appId和SECRET