微信公眾平臺應用開發(fā)(方法、技巧與案例)下篇_第1頁
微信公眾平臺應用開發(fā)(方法、技巧與案例)下篇_第2頁
微信公眾平臺應用開發(fā)(方法、技巧與案例)下篇_第3頁
微信公眾平臺應用開發(fā)(方法、技巧與案例)下篇_第4頁
微信公眾平臺應用開發(fā)(方法、技巧與案例)下篇_第5頁
已閱讀5頁,還剩230頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

微信公眾平臺應用開發(fā)方法、技巧與案例(下篇)目錄\h第6章高級接口的使用\h6.1語音識別\h6.1.1開啟語音識別功能\h6.1.2如何獲取語音消息\h6.2客服接口\h6.2.1接口描述\h6.2.2方法封裝\h6.2.3案例:發(fā)送客服消息\h6.3OAuth2.0網頁授權\h6.3.1配置網頁授權回調域名\h6.3.2網頁授權流程\h6.3.3方法封裝\h6.3.4案例:通過網頁授權獲取用戶信息\h6.4生成帶參數二維碼\h6.4.1創(chuàng)建臨時二維碼\h6.4.2創(chuàng)建永久二維碼\h6.4.3換取二維碼\h6.4.4案例:通過ticket換取二維碼\h6.5獲取用戶地理位置\h6.5.1開啟獲取用戶地理位置功能\h6.5.2接收上報地理位置事件\h6.6獲取用戶基本信息\h6.6.1接口描述\h6.6.2方法封裝\h6.6.3案例:獲取用戶基本信息\h6.7獲取關注者列表\h6.7.1接口描述\h6.7.2方法封裝\h6.7.3案例:獲取公眾賬號關注者列表\h6.8用戶分組接口\h6.8.1查詢分組\h6.8.2創(chuàng)建分組\h6.8.3修改分組名\h6.8.4移動用戶分組\h6.9上傳及下載多媒體文件\h6.9.1上傳多媒體文件接口描述\h6.9.2使用抓包工具分析文件上傳請求\h6.9.3上傳多媒體文件方法封裝\h6.9.4下載多媒體文件\h6.9.5案例:上傳及下載語音文件\h6.10小結\h第7章網絡表情的使用\h7.1微信支持的網絡表情\h7.2QQ表情\h7.2.1微信上的QQ表情代碼\h7.2.2在微信上發(fā)送QQ表情\h7.2.3QQ表情的識別\h7.2.4回復QQ表情\h7.2.5案例:原樣回復QQ表情\h7.3Emoji表情\h7.3.1微信上的Emoji表情編碼\h7.3.2如何使用Emoji表情編碼\h7.3.3案例:回復Emoji表情\h7.4小結\h第8章公眾平臺開發(fā)技巧\h8.1圖文消息使用詳解\h8.1.1單圖文消息的實現\h8.1.2多圖文消息的實現\h8.1.3圖文消息使用注意事項\h8.2公眾賬號無響應的處理\h8.2.1公眾賬號無響應的幾種情況\h8.2.2計算字符串所占字節(jié)數\h8.3應用開發(fā)最佳實踐\h8.3.1解析消息創(chuàng)建時間\h8.3.2換行符的使用\h8.3.3網頁超鏈接的使用\h8.3.4隱藏瀏覽器工具欄\h8.3.5表情飄落效果\h8.4識別微信瀏覽器\h8.4.1判斷微信瀏覽器\h8.4.2只允許微信瀏覽器訪問\h8.5服務多個公眾賬號\h8.5.1公眾賬號托管平臺原理\h8.5.2案例:服務兩個公眾賬號\h8.6業(yè)務系統對接\h8.6.1短信方式綁定賬號\h8.6.2網頁方式綁定賬號\h8.7公眾平臺開發(fā)測試\h8.8小結\h第9章LBS應用開發(fā)實戰(zhàn):周邊搜索\h9.1“周邊搜索”功能及設計\h9.1.1使用方法\h9.1.2功能演示\h9.1.3需求分析\h9.1.4數據表設計\h9.2百度地圖API的使用\h9.2.1百度地圖API產品簡介\h9.2.2申請訪問密鑰\h9.2.3PlaceAPI的使用\h9.2.4步行導航檢索的使用\h9.2.5百度坐標轉換\h9.3MySQL的使用\h9.3.1MySQL的下載與安裝\h9.3.2MySQL的常用操作\h9.3.3JDBC的基本使用\h9.3.4案例:使用JDBC查詢數據\h9.4BAE的MySQL服務\h9.4.1創(chuàng)建數據庫\h9.4.2使用phpMyAdmin操作MySQL\h9.4.3案例:使用JDBC操作MySQL\h9.5“周邊搜索”應用實現\h9.5.1應用開發(fā)準備\h9.5.2封裝數據庫操作\h9.5.3封裝百度地圖操作\h9.5.4編寫步行導航頁面\h9.5.5CoreService類的實現\h9.5.6部署應用及測試體驗\h9.6小結\h第10章游戲開發(fā)實戰(zhàn):猜數字\h10.1“猜數字”功能及設計\h10.1.1游戲規(guī)則\h10.1.2游戲術語\h10.1.3核心流程設計\h10.1.4數據表設計\h10.2“猜數字”游戲的實現\h10.2.1游戲開發(fā)準備\h10.2.2游戲算法封裝\h10.2.3數據庫操作封裝\h10.2.4核心處理邏輯\h10.2.5CoreService類的實現\h10.2.6部署應用及測試體驗\h10.3小結\h第11章智能聊天應用開發(fā)實戰(zhàn):聊天機器人\h11.1聊天機器人原理及設計\h11.1.1實現原理\h11.1.2數據表設計\h11.2全文檢索引擎Lucene\h11.2.1Lucene的組成結構\h11.2.2倒排索引結構\h11.2.3索引和檢索原理\h11.2.4常用API介紹\h11.2.5Lucene的評分機制\h11.2.6案例:使用Lucene索引和檢索\h11.3中文分詞\h11.3.1中文分詞方法\h11.3.2IK分詞器的使用\h11.4索引瀏覽器Luke\h11.4.1Luke的功能及下載\h11.4.2Luke的用法\h11.5聊天機器人的實現\h11.5.1應用開發(fā)準備\h11.5.2封裝數據庫操作\h11.5.3封裝聊天服務類\h11.5.4CoreService類的實現\h11.5.5應用啟動時創(chuàng)建索引\h11.5.6部署應用及測試體驗\h11.6小結第6章高級接口的使用2013年10月29日公眾平臺新版公測,推出了全新的認證服務體系,服務號可以申請微信認證。相比微博認證,微信認證更加嚴格、真實,能夠更好地保護企業(yè)和用戶的合法權益。服務號不再支持微博認證,之前通過微博認證的服務號,認證標識會保留兩個月。訂閱號可以繼續(xù)申請微博認證。微信認證是由第三方專業(yè)審核機構負責,申請微信認證需要支付300元/次的審核服務費用。認證成功后,賬號名稱、認證標識及認證信息會保留一年,我們應該在認證成功后的一年內完成年審認證,年審認證需要另行支付審核服務費。如果未通過年審認證,之前認證的賬號名稱可能會被更改,認證標識及認證信息也會被取消。服務號通過微信認證后,將自動獲得高級接口中所有接口權限,包括語音識別、客服接口、OAuth2.0網頁授權、生成帶參數二維碼、獲取用戶地理位置、獲取用戶基本信息、獲取關注者列表、用戶分組接口和上傳下載多媒體文件,如圖6-1所示。通過這九大接口,公眾賬號能夠為用戶提供更多個性化的服務,能夠將用戶體驗提升到一個新的層次。圖6-1我的服務(通過微信認證后)6.1語音識別微信5.0之前,有一些明星公眾賬號推出了語音搜索功能,例如,中國南方航空、出門問問、微信路況等;而對于普通公眾賬號,在收到用戶發(fā)送的語音消息時,只能夠判斷出這是一條voice類型的語音消息,無法得知用戶在說什么,于是只能給用戶回復“暫不支持語音功能,請使用文本或菜單進行交互”。于是公眾平臺開發(fā)者開始呼吁微信能夠將語音識別接口開放出來。微信5.0推出了語音輸入功能,能夠將用戶輸入的語音轉換成文字,這或許意味著微信團隊自主研發(fā)的語音識別技術趨于成熟,讓開發(fā)者看到了希望,并最終等來了這一天。6.1.1開啟語音識別功能語音識別功能默認是關閉的,如圖6-1所示,開啟語音識別功能后,用戶向公眾賬號發(fā)送語音消息時,微信服務器會在推送的語音消息XML數據包中增加一個Recongnition參數,如下所示:<xml>

<ToUserName><![CDATA[toUser]]></ToUserName>

<FromUserName><![CDATA[fromUser]]></FromUserName>

<CreateTime>1357290913</CreateTime>

<MsgType><![CDATA[voice]]></MsgType>

<MediaId><![CDATA[media_id]]></MediaId>

<Format><![CDATA[Format]]></Format>

<Recognition><![CDATA[騰訊微信團隊]]></Recognition>

<MsgId>1234567890123456</MsgId>

</xml>6.1.2如何獲取語音消息在公眾賬號后臺的CoreService類中,可以像下面這樣獲取到語音消息的MediaId、Format、Recongnition等參數。//消息類型

StringmsgType=requestMap.get("MsgType");

//判斷消息類型是否為voice

if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)){

//語音消息文件的標識

StringmediaId=requestMap.get("MediaId");

//語音格式:amr

Stringformat=requestMap.get("Format");

//語音識別結果

Stringrecognition=requestMap.get("Recognition");

//TODO處理用戶請求

}說明由于微信客戶端緩存的原因,開發(fā)者開啟或者關閉語音識別功能,對新關注用戶會立刻生效,而對已關注用戶則需要24小時之后才能生效。開發(fā)者可以通過重新關注公眾賬號的方法進行測試。在某些特殊情況下,微信提供的語音識別功能并不能滿足要求,例如,用戶使用方言、少數民族語言或外語。遇到類似情況時,就只能調用下載多媒體文件接口將語音文件下載到本地,然后通過自主研發(fā)的語音識別引擎或者第三方(Google、訊飛、云知聲等)語音識別引擎來實現。6.2客服接口沒有客服接口之前,客服人員向公眾賬號用戶回復消息存在著諸多不便,主要體現在以下幾個方面。1)客服人員只能登錄到公眾平臺給用戶回復消息,不能在企業(yè)自有的客服系統上完成;2)如果有多名客服人員,每名客服人員都會知道登錄賬號和密碼,這無疑增加了賬號管理的風險;3)登錄公眾平臺之后,所有的客服人員看到的操作界面完全相同,極有可能出現多位客服都向同一個用戶回復的情況。在用戶主動給公眾賬號發(fā)送消息之后的24小時以內,開發(fā)者可以調用客服接口給用戶發(fā)消息,并且沒有次數限制。通過客服接口,客服人員能夠在企業(yè)自有的客服系統上查看并回復用戶的提問,企業(yè)客服系統能夠靈活地管控客服人員的登錄賬號和任務,這就很好地解決了前面提到的所有問題。6.2.1接口描述客服接口的請求地址如下:https:///cgi-bin/message/custom/send?access_token=ACCESS_TOKEN發(fā)送客服消息需要向上述請求地址POST特定格式的JSON數據包,各種類型的消息所需的JSON數據包如下。1)發(fā)送文本消息:{

"touser":"OPENID",

"msgtype":"text",

"text":{

"content":"HelloWorld"

}

}2)發(fā)送圖片消息:{

"touser":"OPENID",

"msgtype":"image",

"image":{

"media_id":"MEDIA_ID"

}

}3)發(fā)送語音消息:{

"touser":"OPENID",

"msgtype":"voice",

"voice":{

"media_id":"MEDIA_ID"

}

}4)發(fā)送視頻消息:{

"touser":"OPENID",

"msgtype":"video",

"video":{

"media_id":"MEDIA_ID",

"thumb_media_id":"THUMB_MEDIA_ID"

}

}5)發(fā)送音樂消息:{

"touser":"OPENID",

"msgtype":"music",

"music":{

"title":"MUSIC_TITLE",

"description":"MUSIC_DESCRIPTION",

"musicurl":"MUSIC_URL",

"hqmusicurl":"HQ_MUSIC_URL",

"thumb_media_id":"THUMB_MEDIA_ID"

}

}6)發(fā)送圖文消息:{

"touser":"OPENID",

"msgtype":"news",

"news":{

"articles":[

{

"title":"HappyDay",

"description":"IsReallyAHappyDay",

"url":"URL",

"picurl":"PIC_URL"

},

{

"title":"HappyDay",

"description":"IsReallyAHappyDay",

"url":"URL",

"picurl":"PIC_URL"

}

]

}

}其中,參數touser是消息的發(fā)送對象,msgtype是消息類型,其他參數在第4章介紹響應消息時都有說明。消息發(fā)送成功時返回的JSON結果示例如下:{"errcode":0,"errmsg":"ok"}消息發(fā)送失敗時返回的JSON結果示例如下:{"errcode":40013,"errmsg":"invalidappid"}6.2.2方法封裝發(fā)送客服消息需要POST特定格式的JSON數據包,因此,有必要為每種類型的消息定義一個組裝JSON數據包的方法,代碼如下:/**

*組裝文本客服消息

*

*@paramopenId消息發(fā)送對象

*@paramcontent文本消息內容

*@return

*/

publicstaticStringmakeTextCustomMessage(StringopenId,Stringcontent){

//對消息內容中的雙引號進行轉義

content=content.replace("\"","\\\"");

StringjsonMsg="{\"touser\":\"%s\",\"msgtype\":\"text\",

\"text\":{\"content\":\"%s\"}}";

returnString.format(jsonMsg,openId,content);

}

/**

*組裝圖片客服消息

*

*@paramopenId消息發(fā)送對象

*@parammediaId媒體文件ID

*@return

*/

publicstaticStringmakeImageCustomMessage(StringopenId,StringmediaId){

StringjsonMsg="{\"touser\":\"%s\",\"msgtype\":\"image\",

\"image\":{\"media_id\":\"%s\"}}";

returnString.format(jsonMsg,openId,mediaId);

}

/**

*組裝語音客服消息

*

*@paramopenId消息發(fā)送對象

*@parammediaId媒體文件ID

*@return

*/

publicstaticStringmakeVoiceCustomMessage(StringopenId,StringmediaId){

StringjsonMsg="{\"touser\":\"%s\",\"msgtype\":\"voice\",

\"voice\":{\"media_id\":\"%s\"}}";

returnString.format(jsonMsg,openId,mediaId);

}

/**

*組裝視頻客服消息

*

*@paramopenId消息發(fā)送對象

*@parammediaId媒體文件ID

*@paramthumbMediaId視頻消息縮略圖的媒體ID

*@return

*/

publicstaticStringmakeVideoCustomMessage(StringopenId,StringmediaId,String

thumbMediaId){

StringjsonMsg="{\"touser\":\"%s\",\"msgtype\":\"video\",\"video\":

{\"media_id\":\"%s\",\"thumb_media_id\":\"%s\"}}";

returnString.format(jsonMsg,openId,mediaId,thumbMediaId);

}

/**

*組裝音樂客服消息

*

*@paramopenId消息發(fā)送對象

*@parammusic音樂對象

*@return

*/

publicstaticStringmakeMusicCustomMessage(StringopenId,Musicmusic){

StringjsonMsg="{\"touser\":\"%s\",\"msgtype\":\"music\",\"music\":%s}";

jsonMsg=String.format(jsonMsg,openId,JSONObject.fromObject(music).toString());

//將jsonMsg中的thumbmediaid替換為thumb_media_id

jsonMsg=jsonMsg.replace("thumbmediaid","thumb_media_id");

returnjsonMsg;

}

/**

*組裝圖文客服消息

*

*@paramopenId消息發(fā)送對象

*@paramarticleList圖文消息列表

*@return

*/

publicstaticStringmakeNewsCustomMessage(StringopenId,List<Article>

articleList){

StringjsonMsg="{\"touser\":\"%s\",\"msgtype\":\"news\",

\"news\":{\"articles\":%s}}";

jsonMsg=String.format(jsonMsg,openId,JSONArray.fromObject(articleList).

toString().replaceAll("\"","\\\""));

//將jsonMsg中的picUrl替換為picurl

jsonMsg=jsonMsg.replace("picUrl","picurl");

returnjsonMsg;

}調用上面的方法就能夠得到發(fā)送客服消息所需的JSON數據包。代碼中的JSONObject和JSONArray都是JSON-lib工具中的類,我們在第5章學習過它的用法;代碼中的Music、Article是我們在4.2.3節(jié)中定義的類。筆者將發(fā)送客服消息的操作封裝成sendCustomMessage()方法,該方法的實現如下:/**

*發(fā)送客服消息

*

*@paramaccessToken接口訪問憑證

*@paramjsonMsgjson格式的客服消息(包括touser、msgtype和消息內容)

*@returntrue|false

*/

publicstaticbooleansendCustomMessage(StringaccessToken,StringjsonMsg){

("消息內容:{}",jsonMsg);

booleanresult=false;

//拼接請求地址

StringrequestUrl="https:///cgi-bin/message/

custom/send?access_token=ACCESS_TOKEN";

requestUrl=requestUrl.replace("ACCESS_TOKEN",accessToken);

//發(fā)送客服消息

JSONObjectjsonObject=CommonUtil.httpsRequest(requestUrl,"POST",jsonMsg);

if(null!=jsonObject){

interrorCode=jsonObject.getInt("errcode");

StringerrorMsg=jsonObject.getString("errmsg");

if(0==errorCode){

result=true;

("客服消息發(fā)送成功errcode:{}errmsg:{}",errorCode,errorMsg);

}else{

log.error("客服消息發(fā)送失敗errcode:{}errmsg:{}",errorCode,errorMsg);

}

}

returnresult;

}通過sendCustomMessage()方法就能向指定用戶發(fā)送客服消息,調用該方法需要傳入參數accessToken和jsonMsg,分別表示接口訪問憑證和JSON數據包。sendCustomMessage()方法中的CommonUtil類是我們在5.6.3節(jié)中封裝的通用工具類,該類中的httpsRequest()和getToken()方法分別用于發(fā)送HTTPS請求和獲取接口訪問憑證,本章后面的接口調用還會用到這兩個方法。6.2.3案例:發(fā)送客服消息下面是sendCustomMessage()方法的使用示例,向公眾賬號的某個關注用戶發(fā)送一條文本消息。publicstaticvoidmain(Stringargs[]){

//獲取接口訪問憑證

StringaccessToken=CommonUtil.getToken("APPID","APPSECRET").getAccessToken();

//組裝文本客服消息

StringjsonTextMsg=makeTextCustomMessage("oEdzejiHCDqafJbz4WNJtWTMbDcE",

"測試發(fā)送客服消息!");

//發(fā)送客服消息

sendCustomMessage(accessToken,jsonTextMsg);

}讀者需要將代碼中的APPID和APPSECRET替換成自已的。執(zhí)行上面的main()方法,能夠在MyEclipse控制臺看到執(zhí)行日志,包括JSON數據包和消息發(fā)送結果,如下所示:[INFO]2013-11-0921:34:14,325org.liufeng.course.util.AdvancedUtil消息內容:

{"touser":"oEdzejiHCDqafJbz4WNJtWTMbDcE","msgtype":"text",

"text":{"content":"測試發(fā)送客服消息!"}}

[INFO]2013-11-0921:34:14,439org.liufeng.course.util.AdvancedUtil客服消息發(fā)送成功

errcode:0errmsg:ok如果看到上面的日志,就說明客服消息發(fā)送成功了,用戶會立即收到由公眾賬號發(fā)來的消息“測試發(fā)送客服消息!”。需要再次強調的是,只有24小時之內給公眾賬號發(fā)送過消息的用戶我們才能給他們發(fā)送客服消息。說明通過客服消息接口發(fā)送圖片、語音、視頻和音樂消息時,需要先將對應的多媒體文件上傳到微信服務器,筆者將在6.9.1節(jié)介紹上傳多媒體文件的相關知識。6.3OAuth2.0網頁授權自定義菜單的按鈕類型有click和view兩種。點擊view按鈕會直接通過微信內置瀏覽器打開網頁,但是在網頁中卻無法獲取用戶的OpenID,不能確定是哪個用戶在訪問網頁。因此,view按鈕只能指向一些與用戶身份無關的頁面,例如企業(yè)介紹、使用幫助、活動宣傳等,而不能指向賬號綁定、會員信息查詢、下訂單等頁面。常用的解決方案是放棄使用view按鈕,改用click按鈕。用戶點擊click按鈕后,公眾賬號回復圖文消息或包含網頁鏈接的文本消息,用戶點擊消息中的鏈接后再跳轉到網頁,如圖6-2所示。雖然這種實現會多一步操作,但開發(fā)者能夠在圖文消息或文本消息的網頁鏈接上附加參數以傳遞當前用戶的OpenID,例如,圖6-2所示的文本消息中的“綁定賬號”4個字所帶的網頁超鏈接中含有wx_token參數,其實就是當前用戶的OpenID或者加密后的OpenID,如下所示。圖6-2“小米手機”的賬號綁定功能http:///frontend/wxUser/bind?wx_token=oMH_GjixCjNQupuM6sssAA5588JU從上面的描述可以得知:通過view按鈕進入網頁,操作次數少,用戶體驗好,但獲取不到OpenID,無法滿足要求;通過click按鈕進入網頁,能夠獲取到OpenID,但是會多一次操作和交互,使用門檻較高。那么,有沒有兩全其美的解決方案呢?答案是肯定的。通過OAuth2.0網頁授權接口,開發(fā)者能夠獲取到訪問公眾賬號網頁的用戶信息,包括OpenID、用戶昵稱、性別、所在城市、用戶頭像等。利用獲取到的信息,可以實現體驗優(yōu)化、用戶來源統計、賬號綁定、身份鑒權等功能。例如,圖6-2所示的賬號綁定功能就可以省略中間那步,直接設計成點擊view按鈕打開賬號綁定頁面。6.3.1配置網頁授權回調域名在公眾賬號請求用戶網頁授權之前,開發(fā)者需要先在公眾平臺上配置OAuth2.0網頁授權回調域名,如圖6-3所示。假如配置的域名為,那么此域名下的所有頁面都可以進行OAuth2.0鑒權,如/login.html。圖6-3OAuth2.0網頁授權回調域名6.3.2網頁授權流程通過OAuth2.0實現網頁授權的流程分為3步。1)引導用戶進入授權頁面,用戶同意授權后,開發(fā)者能夠獲取到code。2)通過code換取網頁授權access_token,access_token的有效時長為7200秒。如果需要,開發(fā)者可以刷新網頁授權access_token,避免過期。3)通過網頁授權access_token和OpenID獲取用戶基本信息。注意code是一個32位的隨機字符串,作為換取網頁授權access_token的票據。每次用戶授權后接收到的code都不一樣,code只能使用一次,如果5分鐘后仍未使用則自動過期。1.獲取code首先,引導用戶訪問下面的網頁鏈接進入授權頁面。https:///connect/oauth2/authorize?appid=APPID&redirect_uri=

REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect鏈接中的參數說明如表6-1所示。表6-1引導用戶進入授權頁面的網頁鏈接參數在表6-1中,比較重要的兩個參數是redirect_uri和scope?!駌edirect_uri是授權后的回調地址,必須在圖6-3中所設置的回調域名下。當用戶同意授權給公眾賬號后,微信服務器會將授權數據(主要是code)傳到redirect_uri所表示的鏈接地址?!駍cope是應用授權作用域,它的值有兩個:snsapi_base和snsapi_userinfo。如果只需要獲取用戶的OpenID,則將scope設置為snsapi_base;如果除OpenID之外還需要獲取用戶的其他信息(用戶昵稱、性別、所在城市等),則需要將scope設置為snsapi_userinfo。當scope等于snsapi_base時,不會彈出授權頁面;當scope等于snsapi_userinfo時,會彈出授權頁面,授權界面如圖6-4所示。圖6-4授權頁面當用戶同意授權后,頁面將跳轉至redirect_uricode=CODE&state=STATE。如果用戶拒絕授權,頁面將跳轉至redirect_uricode=authdeny&state=STATE。也就是說,不管用戶是否同意授權,頁面都將跳轉到回調地址redirect_uri,在redirect_uri指向的請求處理程序中,可以獲取參數code和state,如果code的值為authdeny,就表示用戶拒絕授權。說明如果引導鏈接中的網頁授權作用域scope等于snsapi_base時,用戶點擊后會直接跳轉至redirect_uricode=CODE&state=STATE,一樣能夠獲取到code。2.獲取access_token(1)根據code獲取access_token接下來,通過調用接口獲取網頁授權access_token,這里的access_token與調用自定義菜單接口、客服消息接口需要的access_token不同。獲取網頁授權access_token的接口地址如下:https:///sns/oauth2/access_token?appid=

APPID&secret=SECRET&code=CODE&grant_type=authorization_code上述接口地址中的參數說明如表6-2所示。表6-2獲取網頁授權access_token接口的參數說明獲取網頁授權access_token接口調用成功時返回的JSON數據包如下:{

"access_token":"ACCESS_TOKEN",

"expires_in":7200,

"refresh_token":"REFRESH_TOKEN",

"openid":"OPENID",

"scope":"SCOPE"

}上述JSON數據包的參數說明如表6-3所示。表6-3獲取網頁授權access_token接口返回參數說明OAuth2.0網頁授權不僅針對關注用戶,對于未關注公眾賬號的用戶也同樣有效。未關注公眾賬號的用戶在訪問公眾賬號的網頁時,也會產生一個OpenID,該OpenID對于同一個公眾賬號也是唯一不變的。獲取網頁授權access_token接口調用失敗時返回的JSON數據包如下:{"errcode":40029,"errmsg":"invalidcode"}說明如果網頁授權作用域scope等于snsapi_base,在這一步獲取網頁授權access_token的同時,也獲取到了用戶的OpenID,scope等于snsapi_base的網頁授權流程到此結束。(2)刷新access_tokenaccess_token的有效時間為7200秒,如果超時,則可以使用上一步返回的refresh_token刷新access_token。refresh_token的有效期比較長,至少一星期,當refresh_token失效后,就需要用戶重新授權。刷新access_token的請求地址如下:https:///sns/oauth2/refresh_token?appid=

APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN上述請求地址中的參數說明如表6-4所示。表6-4刷新access_token接口參數說明刷新access_token接口的返回結果與獲取網頁授權access_token接口的完全一樣,不再贅述。3.獲取用戶信息如果網頁授權作用域為snsapi_userinfo,開發(fā)者還可以通過access_token和OpenID獲取用戶的基本信息,即使用戶未關注公眾賬號也能獲取。獲取用戶信息的請求地址如下:https:///sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID用戶信息獲取成功時返回的JSON數據包如下:{

"openid":"OPENID",

"nickname":NICKNAME,

"sex":"1",

"province":"PROVINCE",

"city":"CITY",

"country":"COUNTRY",

"headimgurl":"http:///mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxL

SUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",

"privilege":[

"PRIVILEGE1",

"PRIVILEGE2"

]

}以上JSON數據包中的參數說明如表6-5所示。表6-5獲取用戶信息接口返回參數說明用戶信息獲取失敗時返回的JSON數據包示例如下:{"errcode":40003,"errmsg":"invalidopenid"}6.3.3方法封裝1.封裝獲取access_token方法筆者將調用接口獲取網頁授權access_token的操作封裝成getOauth2AccessToken()方法,該方法的實現如下:/**

*獲取網頁授權憑證

*

*@paramappId公眾賬號的唯一標識

*@paramappSecret公眾賬號的密鑰

*@paramcode

*@returnWeixinAouth2Token

*/

publicstaticWeixinOauth2TokengetOauth2AccessToken(StringappId,

StringappSecret,Stringcode){

WeixinOauth2Tokenwat=null;

//拼接請求地址

StringrequestUrl="https:///sns/oauth2/

access_token?appid=APPID&secret=SECRET&code=COD

E&grant_type=authorization_code";

requestUrl=requestUrl.replace("APPID",appId);

requestUrl=requestUrl.replace("SECRET",appSecret);

requestUrl=requestUrl.replace("CODE",code);

//獲取網頁授權憑證

JSONObjectjsonObject=CommonUtil.httpsRequest(requestUrl,"GET",null);

if(null!=jsonObject){

try{

wat=newWeixinOauth2Token();

wat.setAccessToken(jsonObject.getString("access_token"));

wat.setExpiresIn(jsonObject.getInt("expires_in"));

wat.setRefreshToken(jsonObject.getString("refresh_token"));

wat.setOpenId(jsonObject.getString("openid"));

wat.setScope(jsonObject.getString("scope"));

}catch(Exceptione){

wat=null;

interrorCode=jsonObject.getInt("errcode");

StringerrorMsg=jsonObject.getString("errmsg");

log.error("獲取網頁授權憑證失敗errcode:{}errmsg:{}",errorCode,errorMsg);

}

}

returnwat;

}getOauth2AccessToken()方法的返回值是WeixinOauth2Token對象,它封裝了調用接口返回的所有參數,該類的代碼如下:packageorg.liufeng.course.pojo;

/**

*網頁授權信息

*

*@authorliufeng

*@date2013-11-09

*/

publicclassWeixinOauth2Token{

//網頁授權接口調用憑證

privateStringaccessToken;

//憑證有效時長

privateintexpiresIn;

//用于刷新憑證

privateStringrefreshToken;

//用戶標識

privateStringopenId;

//用戶授權作用域

privateStringscope;

publicStringgetAccessToken(){

returnaccessToken;

}

publicvoidsetAccessToken(StringaccessToken){

this.accessToken=accessToken;

}

publicintgetExpiresIn(){

returnexpiresIn;

}

publicvoidsetExpiresIn(intexpiresIn){

this.expiresIn=expiresIn;

}

publicStringgetRefreshToken(){

returnrefreshToken;

}

publicvoidsetRefreshToken(StringrefreshToken){

this.refreshToken=refreshToken;

}

publicStringgetOpenId(){

returnopenId;

}

publicvoidsetOpenId(StringopenId){

this.openId=openId;

}

publicStringgetScope(){

returnscope;

}

publicvoidsetScope(Stringscope){

this.scope=scope;

}

}2.封裝刷新access_token方法筆者將調用接口刷新網頁授權access_token的操作封裝成refreshOauth2AccessToken()方法,該方法的實現如下:/**

*刷新網頁授權憑證

*

*@paramappId公眾賬號的唯一標識

*@paramrefreshToken

*@returnWeixinAouth2Token

*/

publicstaticWeixinOauth2TokenrefreshOauth2AccessToken

(StringappId,StringrefreshToken){

WeixinOauth2Tokenwat=null;

//拼接請求地址

StringrequestUrl="https:///sns/oauth2/

refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";

requestUrl=requestUrl.replace("APPID",appId);

requestUrl=requestUrl.replace("REFRESH_TOKEN",refreshToken);

//刷新網頁授權憑證

JSONObjectjsonObject=CommonUtil.httpsRequest(requestUrl,"GET",null);

if(null!=jsonObject){

try{

wat=newWeixinOauth2Token();

wat.setAccessToken(jsonObject.getString("access_token"));

wat.setExpiresIn(jsonObject.getInt("expires_in"));

wat.setRefreshToken(jsonObject.getString("refresh_token"));

wat.setOpenId(jsonObject.getString("openid"));

wat.setScope(jsonObject.getString("scope"));

}catch(Exceptione){

wat=null;

interrorCode=jsonObject.getInt("errcode");

StringerrorMsg=jsonObject.getString("errmsg");

log.error("刷新網頁授權憑證失敗errcode:{}errmsg:{}",errorCode,

errorMsg);

}

}

returnwat;

}refreshOauth2AccessToken()方法的返回值也是WeixinOauth2Token對象,前面有該方法的定義。3.封裝獲取用戶信息方法筆者將通過網頁授權access_token獲取用戶信息的操作封裝成getSNSUserInfo()方法,該方法的實現如下:/**

*通過網頁授權獲取用戶信息

*

*@paramaccessToken網頁授權接口調用憑證

*@paramopenId用戶標識

*@returnSNSUserInfo

*/

@SuppressWarnings({"deprecation","unchecked"})

publicstaticSNSUserInfogetSNSUserInfo(StringaccessToken,StringopenId){

SNSUserInfosnsUserInfo=null;

//拼接請求地址

StringrequestUrl="https:///sns/

userinfo?access_token=ACCESS_TOKEN&openid=OPENID";

requestUrl=requestUrl.replace("ACCESS_TOKEN",accessToken).replace("OPENID",

openId);

//通過網頁授權獲取用戶信息

JSONObjectjsonObject=CommonUtil.httpsRequest(requestUrl,"GET",null);

if(null!=jsonObject){

try{

snsUserInfo=newSNSUserInfo();

//用戶的標識

snsUserInfo.setOpenId(jsonObject.getString("openid"));

//昵稱

snsUserInfo.setNickname(jsonObject.getString("nickname"));

//性別(1是男性,2是女性,0是未知)

snsUserInfo.setSex(jsonObject.getInt("sex"));

//用戶所在國家

snsUserInfo.setCountry(jsonObject.getString("country"));

//用戶所在省份

snsUserInfo.setProvince(jsonObject.getString("province"));

//用戶所在城市

snsUserInfo.setCity(jsonObject.getString("city"));

//用戶頭像

snsUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));

//用戶特權信息

snsUserInfo.setPrivilegeList(JSONArray.toList

(jsonObject.getJSONArray("privilege"),List.class));

}catch(Exceptione){

snsUserInfo=null;

interrorCode=jsonObject.getInt("errcode");

StringerrorMsg=jsonObject.getString("errmsg");

log.error("獲取用戶信息失敗errcode:{}errmsg:{}",errorCode,errorMsg);

}

}

returnsnsUserInfo;

}getSNSUserInfo()方法的返回值是SNSUserInfo對象,它封裝了調用接口返回的所有參數,該類的代碼如下:packageorg.liufeng.course.pojo;

importjava.util.List;

/**

*通過網頁授權獲取的用戶信息

*

*@authorliufeng

*@date2013-11-09

*/

publicclassSNSUserInfo{

//用戶標識

privateStringopenId;

//用戶昵稱

privateStringnickname;

//性別(1是男性,2是女性,0是未知)

privateintsex;

//國家

privateStringcountry;

//省份

privateStringprovince;

//城市

privateStringcity;

//用戶頭像鏈接

privateStringheadImgUrl;

//用戶特權信息

privateList<String>privilegeList;

publicStringgetOpenId(){

returnopenId;

}

publicvoidsetOpenId(StringopenId){

this.openId=openId;

}

publicStringgetNickname(){

returnnickname;

}

publicvoidsetNickname(Stringnickname){

this.nickname=nickname;

}

publicintgetSex(){

returnsex;

}

publicvoidsetSex(intsex){

this.sex=sex;

}

publicStringgetCountry(){

returncountry;

}

publicvoidsetCountry(Stringcountry){

this.country=country;

}

publicStringgetProvince(){

returnprovince;

}

publicvoidsetProvince(Stringprovince){

vince=province;

}

publicStringgetCity(){

returncity;

}

publicvoidsetCity(Stringcity){

this.city=city;

}

publicStringgetHeadImgUrl(){

returnheadImgUrl;

}

publicvoidsetHeadImgUrl(StringheadImgUrl){

this.headImgUrl=headImgUrl;

}

publicList<String>getPrivilegeList(){

returnprivilegeList;

}

publicvoidsetPrivilegeList(List<String>privilegeList){

this.privilegeList=privilegeList;

}

}6.3.4案例:通過網頁授權獲取用戶信息為了讓讀者進一步理解并掌握網頁授權流程及其實現,下面來看一個演示案例。1.編寫授權回調請求處理程序如果要在網頁中得到用戶信息,就必須先引導用戶進入網頁授權頁面;用戶同意授權后會跳轉到回調地址redirect_uri,redirect_uri是授權回調請求處理程序的訪問地址;在處理程序中,開發(fā)者能夠獲取到code,再通過code獲取access_token,最終得到用戶信息。授權回調請求處理程序的實現如下:1packageorg.liufeng.course.servlet;

2importjava.io.IOException;

3importjavax.servlet.ServletException;

4importjavax.servlet.http.HttpServlet;

5importjavax.servlet.http.HttpServletRequest;

6importjavax.servlet.http.HttpServletResponse;

7importorg.liufeng.course.pojo.SNSUserInfo;

8importorg.liufeng.course.pojo.WeixinOauth2Token;

9importorg.liufeng.course.util.AdvancedUtil;

10

11/**

12*授權后的回調請求處理

13*

14*@authorliufeng

15*@date2013-11-12

16*/

17publicclassOAuthServletextendsHttpServlet{

18privatestaticfinallongserialVersionUID=-1847238807216447030L;

19

20publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)

21throwsServletException,IOException{

22request.setCharacterEncoding("gb2312");

23response.setCharacterEncoding("gb2312");

24

25//用戶同意授權后,能獲取到code

26Stringcode=request.getParameter("code");

27

28//用戶同意授權

29if(!"authdeny".equals(code)){

30//獲取網頁授權access_token

31WeixinOauth2TokenweixinOauth2Token=

AdvancedUtil.getOauth2AccessToken("APPID","APPSECRET",code);

32//網頁授權接口訪問憑證

33StringaccessToken=weixinOauth2Token.getAccessToken();

34//用戶標識

35StringopenId=weixinOauth2Token.getOpenId();

36//獲取用戶信息

37SNSUserInfosnsUserInfo=AdvancedUtil.getSNSUserInfo(accessToken,

openId);

38

39//設置要傳遞的參數

40request.setAttribute("snsUserInfo",snsUserInfo);

41}

42//跳轉到index.jsp

43request.getRequestDispatcher("index.jsp").forward(request,response);

44}

45}上代碼是通過Servlet接收和處理授權回調請求,由于授權完成后是通過URL傳遞code參數,只需要在doGet()方法中進行處理即可。第26行代碼用于獲取code參數。第29行是根據code判斷用戶是否同意授權,如果code等于"authdeny"表示用戶不同意授權,否則表示同意授權。如果用戶不同意授權,則直接跳轉到目標頁面;如果用戶同意授權,則可以調用已經封裝好的方法獲取用戶信息。第31行是根據APPID、APPSECRET和code獲取網頁授權access_token,同時也能獲取到用戶的OpenID。第37行是獲取用戶信息。第40行代碼是將用戶信息放到request對象中,這樣可以傳遞到目標頁面。如果網頁授權作用域為snsapi_base,則不能獲取用戶信息,只需將OpenID放到request對象中即可。最后,通過第43行代碼跳轉到目標頁面。接下來,需要在項目的web.xml中增加關于OAuthServlet類的配置,代碼如下:<servlet>

<servlet-name>oauthServlet</servlet-name>

<servlet-class>

org.liufeng.course.servlet.OAuthServlet

</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>oauthServlet</servlet-name>

<url-pattern>/oauthServlet</url-pattern>

</servlet-mapping>2.編寫目標頁面用戶授權完成后,會通過redirect_uri跳轉到目標頁面index.jsp,該頁面的代碼如下:1<%@pagelanguage="java"pageEncoding="gb2312"%>

2<%@pageimport="org.liufeng.course.pojo.SNSUserInfo;"%>

3<html>

4<head>

5<title>OAuth2.0網頁授權</title>

6<metaname="viewport"content="width=device-width,user-scalable=0">

7<styletype="text/css">

8*{margin:0;padding:0}

9table{border:1pxdashed#B9B9DD;font-size:12pt}

10td{border:1pxdashed#B9B9DD;word-break:break-all;word-wrap:break-word;}

11</style>

12</head>

13<body>

14<%

15//獲取由OAuthServlet傳入的參數

16SNSUserInfouser=(SNSUserInfo)request.getAttribute("snsUserInfo");

17if(null!=user){

18%>

19<tablewidth="100%"cellspacing="0"cellpadding="0">

20<tr><tdwidth="20%">屬性</td><tdwidth="80%">值</td></tr>

21<tr><td>OpenID</td><td><%=user.getOpenId()%></td></tr>

22<tr><td>昵稱</td><td><%=user.getNickname()%></td></tr>

23<tr><td>性別</td><td><%=user.getSex()%></td></tr>

24<tr><td>國家</td><td><%=user.getCountry()%></td></tr>

25<tr><td>省份</td><td><%=user.getProvince()%></td></tr>

26<tr><td>城市</td><td><%=user.getCity()%></td></tr>

27<tr><td>頭像</td><td><%=user.getHeadImgUrl()%></td></tr>

28<tr><td>特權</td><td><%=user.getPrivilegeList()%></td></tr>

29</table>

30<%

31}

32else

33out.print("未獲取到用戶信息!");

34%>

35</body>

36</html>上述目標頁面的實現比較簡單,只是簡單展示了當前用戶的詳細信息。第6行的meta標簽用于設置網頁的寬度以及是否可縮放,這樣頁面就能自適應各種大小屏幕的手機。如果不進行此項設置,則頁面顯示在手機上會非常小,不方便查看。"width=device-width"是將網頁寬度設置為手機屏幕的寬度,“user-scalable=0”是禁止用戶手動縮放。第16~28行的作用是將獲取到的用戶信息顯示在頁面上。3.構造網頁授權鏈接在6.3.2節(jié)曾介紹過網頁授權相關內容,網頁授權鏈接的格式如下:https:///connect/oauth2/authorize?appid=APPID&redirect_uri=

REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect我們要根據實際情況替換鏈接中的APPID、REDIRECT_URI和SCOPE。相信讀者對APPID和SCOPE已經非常熟悉了,這里需要注意的是REDIRECT_URI,它表示授權回調地址(OAuthServlet的訪問地址),但是要進行URL編碼。假如項目部署到BAE上以后,OAuthServlet的訪問地址如下:http://0./oauthServlet則對上述地址進行URL編碼得到的結果就是REDIRECT_URI的值,URL編碼方法如下:/**

*URL編碼(utf-8)

*

*@paramsource

*@return

*/

publicstaticStringurlEncodeUTF8(Stringsource){

Stringresult=source;

try{

result=.URLEncoder.encode(source,"utf-8");

}catch(UnsupportedEncodingExceptione){

e.printStackTrace();

}

returnresult;

}

StringoauthUrl="http://0./oauthServlet"

System.out.println(urlEncodeUTF8(oauthUrl));編碼后的結果如下:http%3A%2F%2F0.%2FoauthServlet最終得到的網頁授權鏈接如下:https:///connect/oauth2/authorize?appid=wx9fd67526e31e66bb&redirect_uri=

http%3A%2F%2F0.%2FoauthServlet

&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect在公眾賬號中,可以通過文本消息、圖文消息或view菜單按鈕將網頁授權鏈接提供給用戶。對于view菜單按鈕,只需要將它的url屬性值設置成上面的鏈接即可,用戶點擊菜單后就會進入到網頁授權界面。4.測試體驗為了演示方便,筆者直接將網頁授權鏈接以文本消息的形式提供給用戶,完整案例的演示結果如圖6-5所示。圖6-5通過OAuth2.0網頁授權獲取用戶信息演示6.4生成帶參數二維碼為了滿足用戶渠道推廣分析的需要,公眾平臺提供了生成帶參數二維碼的接口。使用該接口可以獲得多個帶不同場景值的二維碼,用戶掃描后,公眾賬號可以接收到事件推送。獲取帶參數二維碼的過程分為兩步:首先創(chuàng)建二維碼ticket,然后憑借ticket到指定URL換取二維碼。帶場景值的二維碼分為臨時二維碼和永久二維碼兩種,前者有過期時間,最長為1800秒,但生成數量較多,后者無過期時間,數量較少(目前參數只支持1~1000)。兩種二維碼分別適用于賬號綁定、用戶來源統計等場景。6.4.1創(chuàng)建臨時二維碼1.接口描述創(chuàng)建臨時二維碼的接口地址如下:https:///cgi-bin/qrcode/create?access_token=TOKEN調用該接口需要POST如下格式的JSON數據包:{"expire_seconds":1800,"action_name":"QR_SCENE","action_info":

{"scene":上述JSON數據包中的參數說明如表6-6所示。表6-6臨時二維碼接口的參數說明接口調用成功時返回的JSON結果如下:{"ticket":"gQG28DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0FuWC1DNmZuVEhvMV

p4NDNMRnNRAAIEes

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論