天天看點

Java微信公衆平台開發_05_微信網頁授權

GitHub源碼:https://github.com/shirayner/weixin_gz

一、本節要點

1.網頁授權回調域名

登入微信公衆平台背景, 開發 - 接口權限 - 網頁服務 - 網頁帳号 - 網頁授權擷取使用者基本資訊 - 修改,

Java微信公衆平台開發_05_微信網頁授權

這裡填寫的是域名(是一個字元串),而不是URL

Java微信公衆平台開發_05_微信網頁授權

2. 擷取code

擷取code的流程

(1)建立一個跳轉按鈕,連結為:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxa0064ea657f80062&redirect_uri=http%3A%2F%2Frayner.nat300.top%2Fweixin_gz%2FIDAuthentication.jsp&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect      

(2)在jsp頁面 IDAuthentication.jsp 上接收code

//1.接收code和state
         String code= request.getParameter("code");
         String state=request.getParameter("state");      

 3.通過code換取網頁授權access_token

Java微信公衆平台開發_05_微信網頁授權
Java微信公衆平台開發_05_微信網頁授權
//3.通過code換取網頁授權access_token
    private static final String GET_ACCESSTOKEN_BYCODE_URL="https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; 


/**
     * @desc : 3.通過code換取網頁授權access_token
     *  
     * @param appId  第三方使用者唯一憑證
     * @param appSecret  第三方使用者唯一憑證密鑰,即appsecret
     * @param Code  code作為換取access_token的票據,每次使用者授權帶上的code将不一樣,code隻能使用一次,5分鐘未被使用自動過期。
     * 
     * @return
     * access_token    網頁授權接口調用憑證,注意:此access_token與基礎支援的access_token不同
     * expires_in    access_token接口調用憑證逾時時間,機關(秒)
     * refresh_token    使用者重新整理access_token
     * openid    使用者唯一辨別,請注意,在未關注公衆号時,使用者通路公衆号的網頁,也會産生一個使用者和公衆号唯一的OpenID
     * scope    使用者授權的作用域,使用逗号(,)分隔
     * 
     * @throws Exception String
     */
    public static JSONObject getAccessTokenByCode(String appId,String appSecret,String code) throws Exception {
        //1.擷取請求url
        String url=GET_ACCESSTOKEN_BYCODE_URL.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE", code);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取accessToken
        JSONObject returnJsonObject=null;
        if (null != jsonObject) {  
            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取accessToken
            }else {
                returnJsonObject=jsonObject;
            }  
        }  


        return returnJsonObject;
    }      

View Code

4.通過網頁授權access_token 拉取使用者資訊

Java微信公衆平台開發_05_微信網頁授權
Java微信公衆平台開發_05_微信網頁授權
//3. 拉取使用者資訊(需scope為 snsapi_userinfo)——網頁授權時                                  
    private static final String GET_SNS_USERINFO_URL="https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";


/**
     * @desc :3. 拉取使用者資訊(需scope為 snsapi_userinfo)——網頁授權時      
     *  
     * @param accessToken  網頁授權接口調用憑證,注意:此access_token與基礎支援的access_token不同
     * @param openId 使用者的唯一辨別
     * 
     * @return
     * openid    使用者的唯一辨別
     * nickname    使用者昵稱
     * sex    使用者的性别,值為1時是男性,值為2時是女性,值為0時是未知
     * province    使用者個人資料填寫的省份
     * city    普通使用者個人資料填寫的城市
     * country    國家,如中國為CN
     * headimgurl    使用者頭像,最後一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),使用者沒有頭像時該項為空。若使用者更換頭像,原有頭像URL将失效。
     * privilege    使用者特權資訊,json 數組,如微信沃卡使用者為(chinaunicom)
     * unionid    隻有在使用者将公衆号綁定到微信開放平台帳号後,才會出現該字段。
     * 
     * @throws Exception JSONObject
     */
    public static JSONObject getSNSUserInfo(String accessToken,String openId ) throws Exception {
        //1.擷取請求url
        String url=GET_SNS_USERINFO_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取菜單資料
        JSONObject returnJsonObject=null;
        if (null != jsonObject) {  

            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取菜單資料
            } else {
                returnJsonObject= jsonObject;
            } 
        }   

        return returnJsonObject;


    }      

二、代碼實作

1.Token工具類—AuthHelper

Java微信公衆平台開發_05_微信網頁授權
Java微信公衆平台開發_05_微信網頁授權
package com.ray.weixin.gz.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Formatter;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.ray.weixin.gz.config.Env;
import com.ray.weixin.gz.service.invoice.InvoiceService;


/**
 * 微信公衆号 Token、配置工具類
 * @desc  : AccessToken、Jsticket 、Jsapi
 * 
 * @author: shirayner
 * @date  : 2017年9月27日 下午5:00:25
 */
public class AuthHelper {
    private static final Logger logger = LogManager.getLogger(AuthHelper.class);

    //1.擷取access_token的接口位址,有效期為7200秒
    private static final String GET_ACCESSTOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; 
    //2.擷取getJsapiTicket的接口位址,有效期為7200秒 
    private static final String GET_JSAPITICKET_URL="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi"; 

    //3.通過code換取網頁授權access_token
    private static final String GET_ACCESSTOKEN_BYCODE_URL="https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; 


    /**
     * @desc :1.擷取access_token 
     *  
     * @param appId  第三方使用者唯一憑證
     * @param appSecret  第三方使用者唯一憑證密鑰,即appsecret
     * 
     * @return
     *      access_token    擷取到的憑證
     *      expires_in    憑證有效時間,機關:秒
     * @throws Exception String
     */
    public static String getAccessToken(String appId,String appSecret) throws Exception {
        //1.擷取請求url
        String url=GET_ACCESSTOKEN_URL.replace("APPID", appId).replace("APPSECRET", appSecret);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取accessToken
        String accessToken="";  
        if (null != jsonObject) {  
            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取accessToken
            }else {
                accessToken=jsonObject.getString("access_token");
            }  
        }  


        return accessToken;
    }


    /**
     * @desc :2.擷取JsapiTicket
     *  
     * @param accessToken  有效憑證
     * @return
     * @throws Exception String
     */
    public static String getJsapiTicket(String accessToken) throws Exception {
        //1.擷取請求url
        String url=GET_JSAPITICKET_URL.replace("ACCESS_TOKEN", accessToken);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取accessToken
        String jsapiTicket="";  
        if (null != jsonObject) {  
            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取jsapiTicket
            }else {
                jsapiTicket=jsonObject.getString("ticket");
            }  
        }  


        return jsapiTicket;
    }

    /**
     * @desc : 3.通過code換取網頁授權access_token
     *  
     * @param appId  第三方使用者唯一憑證
     * @param appSecret  第三方使用者唯一憑證密鑰,即appsecret
     * @param Code  code作為換取access_token的票據,每次使用者授權帶上的code将不一樣,code隻能使用一次,5分鐘未被使用自動過期。
     * 
     * @return
     * access_token    網頁授權接口調用憑證,注意:此access_token與基礎支援的access_token不同
     * expires_in    access_token接口調用憑證逾時時間,機關(秒)
     * refresh_token    使用者重新整理access_token
     * openid    使用者唯一辨別,請注意,在未關注公衆号時,使用者通路公衆号的網頁,也會産生一個使用者和公衆号唯一的OpenID
     * scope    使用者授權的作用域,使用逗号(,)分隔
     * 
     * @throws Exception String
     */
    public static JSONObject getAccessTokenByCode(String appId,String appSecret,String code) throws Exception {
        //1.擷取請求url
        String url=GET_ACCESSTOKEN_BYCODE_URL.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE", code);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取accessToken
        JSONObject returnJsonObject=null;
        if (null != jsonObject) {  
            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取accessToken
            }else {
                returnJsonObject=jsonObject;
            }  
        }  


        return returnJsonObject;
    }


    /**
     * @desc :4.擷取前端jsapi需要的配置參數
     *  
     * @param request
     * @return String
     */
    public static String getJsapiConfig(HttpServletRequest request){  

        //1.準備好參與簽名的字段
        //1.1 url
        /* 
         *以http://localhost/test.do?a=b&c=d為例 
         *request.getRequestURL的結果是http://localhost/test.do 
         *request.getQueryString的傳回值是a=b&c=d 
         */  
        String urlString = request.getRequestURL().toString();
        String queryString = request.getQueryString();
        String queryStringEncode = null;
        String url;
        if (queryString != null) {
            queryStringEncode = URLDecoder.decode(queryString);
            url = urlString + "?" + queryStringEncode;
        } else {
            url = urlString;
        }

        //1.2 noncestr
        String nonceStr=UUID.randomUUID().toString();      //随機數
        //1.3 timestamp
        long timeStamp = System.currentTimeMillis() / 1000;     //時間戳參數  

        String signedUrl = url;

        String accessToken = null;
        String ticket = null;

        String signature = null;       //簽名


        try {  
            //1.4 jsapi_ticket
            accessToken=getAccessToken(Env.APP_ID, Env.APP_SECRET);  
            ticket=getJsapiTicket(accessToken);  

            //2.進行簽名,擷取signature
            signature=getSign(ticket,nonceStr,timeStamp,signedUrl);  


        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  

        logger.info("accessToken:"+accessToken);
        logger.info("ticket:"+ticket);
        logger.info("nonceStr:"+nonceStr);
        logger.info("timeStamp:"+timeStamp);
        logger.info("signedUrl:"+signedUrl);
        logger.info("signature:"+signature);
        logger.info("appId:"+Env.APP_ID);




        String configValue = "{signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'"
                + timeStamp + "',appId:'" + Env.APP_ID + "'}";
        logger.info("configValue:"+configValue);

        return configValue;  
    }  


    /**
     * @desc : 4.1 生成簽名的函數 
     *  
     * @param ticket jsticket
     * @param nonceStr 随機串,自己定義
     * @param timeStamp 生成簽名用的時間戳 
     * @param url 需要進行免登鑒權的頁面位址,也就是執行dd.config的頁面位址 
     * @return
     * @throws Exception String
     */

    public static String getSign(String jsTicket, String nonceStr, Long timeStamp, String url) throws Exception {  
        String plainTex = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;
        System.out.println(plainTex);
        try {  
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(plainTex.getBytes("UTF-8"));
            return byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception(e.getMessage());  
        } catch (UnsupportedEncodingException e) {  
            throw new Exception(e.getMessage());  
        }  
    }  

    /**
     * @desc :4.2 将bytes類型的資料轉化為16進制類型  
     *  
     * @param hash
     * @return 
     *   String
     */
    private static String byteToHex(byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", new Object[] { Byte.valueOf(b) });
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }


    /** 5.擷取前端所需發票簽名參數
     * 
     * @desc :
     *(1)将 api_ticket、appid、timestamp、nonceStr、cardType的value值進行字元串的字典序排序。
     *(2)再将所有參數字元串拼接成一個字元串進行sha1加密,得到cardSign。
     * 
     * @return String
     *  timestamp :卡券簽名時間戳
        nonceStr  : 卡券簽名随機串
        signType  : 簽名方式,預設'SHA1'
        cardSign  : 卡券簽名
     *   
     */
    public static String getInvoiceConfig(){ 
        //1.準備好簽名參數
        //1.1 api_ticket  授權頁ticket
        String apiTicket=null;
        try {
            String  accessToken = AuthHelper.getAccessToken(Env.APP_ID, Env.APP_SECRET);
            apiTicket=InvoiceService.getAuthPageTicket(accessToken);
        } catch (Exception e) {
            logger.info("擷取授權頁ticket失敗");
            e.printStackTrace();
        }


        //1.2 appid
        String appId=Env.APP_ID;

        //1.3 timestamp 時間戳
        String timeStamp = System.currentTimeMillis() / 1000 +"";     

        //1.4 nonceStr 随機數
        String nonceStr=UUID.randomUUID().toString();    

        //1.5 cardType
        String cardType="INVOICE";

        //2.擷取簽名
        String cardSign=null;
        try {

            cardSign = AuthHelper.getCardSign(apiTicket, appId, timeStamp, nonceStr, cardType);

        } catch (Exception e) {
            logger.info("擷取發票簽名失敗");
            e.printStackTrace();
        }

        String signType="SHA1";

        logger.info("apiTicket:"+apiTicket);
        logger.info("appId:"+appId);
        logger.info("timeStamp:"+timeStamp);
        logger.info("nonceStr:"+nonceStr);
        logger.info("cardType:"+cardType);
        logger.info("cardSign:"+cardSign);
        logger.info("signType:"+signType);

        //3.傳回前端所需發票簽名參數
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("timestamp", timeStamp);
        jsonObject.put("nonceStr",nonceStr );
        jsonObject.put("signType",signType );
        jsonObject.put("cardSign", cardSign);

        String configValue = jsonObject.toJSONString();
        logger.info("configValue:"+configValue);

        return configValue;  
    }  



    /**
     * @desc :5.1擷取發票簽名
     *  
     * @param apiTicket  授權頁ticket,見InvoiceService
     * @param appId  
     * @param timeStamp 時間戳
     * @param nonceStr  随機串
     * @param cardType 填入INVOICE
     * @return
     * @throws Exception 
     *   String
     */
    public static String getCardSign(String apiTicket, String appId, String timeStamp, String nonceStr,String cardType) throws Exception {  
        //1.将 api_ticket、appid、timestamp、nonceStr、cardType的value值進行字元串的字典序排序。
        //注意:是value值值
        String[] array = new String[] { apiTicket, appId, timeStamp, nonceStr,cardType};
        StringBuffer sb = new StringBuffer();
        // 字元串排序
        Arrays.sort(array);
        for (int i = 0; i < 5; i++) {
            sb.append(array[i]);
        }
        String plainTex = sb.toString();

        //String plainTex = apiTicket+appId+cardType+nonceStr+timeStamp;
        
        System.out.println("plainTex:"+plainTex);
        try {  
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(plainTex.getBytes("UTF-8"));
            return byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception(e.getMessage());  
        } catch (UnsupportedEncodingException e) {  
            throw new Exception(e.getMessage());  
        }  
    }  

    public static String getSHA1(String apiTicket, String appId, String timeStamp, String nonceStr,String cardType) throws Exception{
        System.out.println("getSHA1-----------");
        try {
            String[] array = new String[] { apiTicket, appId, timeStamp, nonceStr,cardType};
            StringBuffer sb = new StringBuffer();
            // 字元串排序
            Arrays.sort(array);
            for (int i = 0; i < 5; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            logger.info("str:"+str);
            // SHA1簽名生成
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();

            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("擷取發票簽名失敗");
        }
    }


}      

2.使用者管理業務類—UserService

Java微信公衆平台開發_05_微信網頁授權
Java微信公衆平台開發_05_微信網頁授權
package com.ray.weixin.gz.service.user;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.ray.weixin.gz.util.HttpHelper;

/**@desc  : 使用者管理
 * 
 * @author: shirayner
 * @date  : 2017年10月31日 下午5:37:08
 */
public class UserService {
    private static final Logger logger = LogManager.getLogger(UserService.class);

    //1. 擷取使用者基本資訊(UnionID機制)
    private static final String GET_USERINFO_URL="https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
    //2.1 擷取使用者清單(從指定的next_openid的下一個開始擷取)
    private static final String LIST_USER_URL="https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID";
    //2.2 擷取所有使用者清單
    private static final String LIST_ALLUSER_URL="https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN";
    //3. 拉取使用者資訊(需scope為 snsapi_userinfo)——網頁授權時                                  
    private static final String GET_SNS_USERINFO_URL="https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";




    /**
     * @desc :1.擷取使用者基本資訊(UnionID機制)
     *  
     * @param accessToken  有效憑證
     * @param openId 普通使用者的辨別,對目前公衆号唯一
     * 
     * @return  使用者詳細資訊
     * subscribe    使用者是否訂閱該公衆号辨別,值為0時,代表此使用者沒有關注該公衆号,拉取不到其餘資訊。
     * openid    使用者的辨別,對目前公衆号唯一
     * nickname    使用者的昵稱
     * sex    使用者的性别,值為1時是男性,值為2時是女性,值為0時是未知
     * city    使用者所在城市
     * country    使用者所在國家
     * province    使用者所在省份
     * language    使用者的語言,簡體中文為zh_CN
     * headimgurl    使用者頭像,最後一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),
     *              使用者沒有頭像時該項為空。若使用者更換頭像,原有頭像URL将失效。
     * subscribe_time    使用者關注時間,為時間戳。如果使用者曾多次關注,則取最後關注時間
     * unionid    隻有在使用者将公衆号綁定到微信開放平台帳号後,才會出現該字段。
     * remark    公衆号營運者對粉絲的備注,公衆号營運者可在微信公衆平台使用者管理界面對粉絲添加備注
     * groupid    使用者所在的分組ID(相容舊的使用者分組接口)
     * tagid_list    使用者被打上的标簽ID清單
     * 
     * @throws Exception JSONObject
     */
    public static JSONObject getUserInfo(String accessToken,String openId ) throws Exception {
        //1.擷取請求url
        String url=GET_USERINFO_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取菜單資料
        JSONObject returnJsonObject=null;
        if (null != jsonObject) {  

            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取菜單資料
            } else {
                returnJsonObject= jsonObject;
            } 
        }   

        return returnJsonObject;
    }

    /** 2.1  擷取使用者清單(從指定的next_openid的下一個開始擷取)
     * 
     * @desc :一次拉取調用最多拉取10000個關注者的OpenID,可以通過多次拉取的方式來滿足需求。
     *  
     * @param accessToken 調用接口憑證
     * @param nextOpenId  從指定的next_openid的下一個開始擷取
     * 
     * @return
     * total    關注該公衆賬号的總使用者數
     * count    拉取的OPENID個數,最大值為10000
     * data    清單資料,OPENID的清單
     * next_openid    拉取清單的最後一個使用者的OPENID
     *   
     * @throws Exception JSONObject
     */
    public static JSONObject listUser(String accessToken,String nextOpenId ) throws Exception {
        //1.擷取請求url
        String url=LIST_USER_URL.replace("ACCESS_TOKEN", accessToken).replace("NEXT_OPENID", nextOpenId);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取菜單資料
        JSONObject returnJsonObject=null;
        if (null != jsonObject) {  

            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取菜單資料
            } else {
                returnJsonObject= jsonObject;
            } 
        }   

        return returnJsonObject;
    }

    /**2.2擷取所有使用者清單
     * 
     * @desc :一次拉取調用最多拉取10000個關注者的OpenID,可以通過多次拉取的方式來滿足需求。
     *  
     * @param accessToken  調用接口憑證
     * 
     * @return
     * total    關注該公衆賬号的總使用者數
     * count    拉取的OPENID個數,最大值為10000
     * data    清單資料,OPENID的清單
     * next_openid    拉取清單的最後一個使用者的OPENID
     * 
     * @throws Exception JSONObject
     */
    public static JSONObject listAllUser(String accessToken) throws Exception {
        //1.擷取請求url
        String url=LIST_ALLUSER_URL.replace("ACCESS_TOKEN", accessToken);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取菜單資料
        JSONObject returnJsonObject=null;
        if (null != jsonObject) {  

            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取菜單資料
            } else {
                returnJsonObject= jsonObject;
            } 
        }   

        return returnJsonObject;
    }


    /**
     * @desc :3. 拉取使用者資訊(需scope為 snsapi_userinfo)——網頁授權時      
     *  
     * @param accessToken  網頁授權接口調用憑證,注意:此access_token與基礎支援的access_token不同
     * @param openId 使用者的唯一辨別
     * 
     * @return
     * openid    使用者的唯一辨別
     * nickname    使用者昵稱
     * sex    使用者的性别,值為1時是男性,值為2時是女性,值為0時是未知
     * province    使用者個人資料填寫的省份
     * city    普通使用者個人資料填寫的城市
     * country    國家,如中國為CN
     * headimgurl    使用者頭像,最後一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),使用者沒有頭像時該項為空。若使用者更換頭像,原有頭像URL将失效。
     * privilege    使用者特權資訊,json 數組,如微信沃卡使用者為(chinaunicom)
     * unionid    隻有在使用者将公衆号綁定到微信開放平台帳号後,才會出現該字段。
     * 
     * @throws Exception JSONObject
     */
    public static JSONObject getSNSUserInfo(String accessToken,String openId ) throws Exception {
        //1.擷取請求url
        String url=GET_SNS_USERINFO_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);

        //2.發起GET請求,擷取傳回結果
        JSONObject jsonObject=HttpHelper.doGet(url);
        logger.info("jsonObject:"+jsonObject.toJSONString());

        //3.解析結果,擷取菜單資料
        JSONObject returnJsonObject=null;
        if (null != jsonObject) {  

            //4.錯誤消息處理
            if (jsonObject.getInteger("errcode")!=null && 0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                //5.成功擷取菜單資料
            } else {
                returnJsonObject= jsonObject;
            } 
        }   

        return returnJsonObject;


    }



}      

3.IDAuthentication.jsp

Java微信公衆平台開發_05_微信網頁授權
Java微信公衆平台開發_05_微信網頁授權
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@page language="java" import="com.ray.weixin.gz.config.*"%>
<%@page language="java" import="com.alibaba.fastjson.JSONObject"%>
<%@page language="java" import="com.ray.weixin.gz.util.*"%>
<%@page language="java" import="com.ray.weixin.gz.service.user.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>身份認證</title>
<script src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript"
    src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

</head>
<body>



<%
         //1.接收code和state
         String code= request.getParameter("code");
         String state=request.getParameter("state");
         
         //2.擷取網頁授權時的accessToken 以及 openId
         JSONObject jsonObject = AuthHelper.getAccessTokenByCode(Env.APP_ID,Env.APP_SECRET, code);
         String accessToken=jsonObject.getString("access_token");
         String openId=jsonObject.getString("openid");
         
         //3.拉取使用者資訊
         JSONObject userInfoJsonObject =UserService.getSNSUserInfo(accessToken, openId);
         
   
%>

hello,這裡是第三方應用

code=<%= code%>    <br>
state=<%= state%>      <br>
nickname=<%= userInfoJsonObject.getString("nickname") %>    <br><br>
sex=<%= userInfoJsonObject.getString("sex") %>    <br><br>
headimgurl=<%= userInfoJsonObject.getString("headimgurl") %>    <br><br>

</body>
</html>