C#開發微信門戶及應用教程javascript
C#開發微信門戶及應用(1)--開始使用微信接口... 6php
一、微信帳號... 6html
二、微信菜單定義... 7java
三、接入微信的連接處理... 8web
四、使用開發方式建立菜單... 14ajax
五、我建立的菜單案例... 17數據庫
C#開發微信門戶及應用(2)--微信消息的處理和應答... 18json
一、微信的消息應答交互... 18api
二、微信的管理接口... 25數組
C#開發微信門戶及應用(3)--文本消息和圖文消息的應答... 29
一、實體信息關係及定義... 30
二、消息的回覆處理... 37
C#開發微信門戶及應用(4)--關注用戶列表及詳細信息管理... 41
一、關注用戶列表及用戶分組信息... 41
二、獲取AIP調用者的的Token.. 47
三、獲取關注用戶列表... 50
四、獲取用戶詳細信息... 59
C#開發微信門戶及應用(5)--用戶分組信息管理... 62
一、用戶分組管理內容... 62
二、用戶分組管理接口的實現... 67
三、用戶分組接口的調用... 79
C#開發微信門戶及應用(6)--微信門戶菜單的管理操做... 82
一、菜單的基礎信息... 82
二、菜單的實體類定義... 85
三、菜單管理操做的接口實現... 91
C#開發微信門戶及應用(7)-微信多客服功能及開發集成... 100
一、多客服準備工做... 101
二、使用多客服客戶端或助手操做... 102
三、微信多客服的開發使用... 103
C#開發微信門戶及應用(8)-微信門戶應用管理系統功能介紹... 108
一、微信菜單管理... 109
二、菜單事件的處理... 112
三、微信消息內容管理... 116
四、應答指令的維護... 121
五、訂閱用戶管理... 129
六、用戶分組管理... 134
七、多媒體管理... 136
八、圖文消息處理... 139
九、會話消息管理... 145
十、羣發消息管理... 147
C#開發微信門戶及應用(9)-微信門戶菜單管理及提交到微信服務器... 149
一、微信菜單的要求及相關界面設計... 150
二、提交菜單到微信服務器的操做... 153
C#開發微信門戶及應用(10)--在管理系統中同步微信用戶分組信息... 160
一、用戶分組,在管理系統中的界面設計... 161
二、分組同步操做代碼展現... 163
C#開發微信門戶及應用(11)--微信菜單的多種表現方式介紹... 172
一、微信自定義菜單的分類... 172
二、重定向類型菜單的URL. 174
三、重定向連接菜單的用途... 182
C#開發微信門戶及應用(12)-使用語音處理... 182
一、微信語音接口的定義0. 183
二、語音的處理操做... 186
C#開發微信門戶及應用(13)-使用地理位置擴展相關應用... 197
一、微信的地理位置信息... 198
二、地址位置的應用處理... 205
三、地址位置應用擴展... 208
C#開發微信門戶及應用(14)-在微信菜單中採用重定向獲取用戶數據... 223
一、微信重定向菜單的配置... 224
二、腳本轉換操做的實現代碼... 227
三、重定向頁面的設計及處理... 230
C#開發微信門戶及應用(15)-微信菜單增長掃一掃、發圖片、發地理位置功能... 233
一、微信幾個功能的官方介紹... 234
二、微信新菜單功能的測試公衆號... 236
三、改進菜單對象和提交菜單... 238
四、微信掃一掃功能集成... 245
五、新菜單功能測試發現的問題... 250
C#開發微信門戶及應用(16)-微信企業號的配置和使用... 251
一、微信企業號的註冊和登錄... 251
二、設置開發回調模式... 256
三、實現回調頁面的功能開發... 259
C#開發微信門戶及應用(17)-微信企業號的通信錄管理開發之部門管理... 266
一、企業組織的建立和配置... 266
二、API訪問的全局惟一票據AccessToken的獲取... 270
二、通信錄管理之部門信息的維護... 272
三、部門管理的API調用... 278
C#開發微信門戶及應用(18)-微信企業號的通信錄管理開發之成員管理... 281
一、成員的建立操做... 281
二、成員的更新操做... 287
三、成員的刪除、成員的獲取、部門成員的獲取操做... 290
七、綜合例子調用代碼... 295
C#開發微信門戶及應用(19)-微信企業號的消息發送(文本、圖片、文件、語音、視頻、圖文消息等) 299
一、企業號特色... 299
二、企業號的管理接口內容... 300
三、企業號消息和事件的處理... 302
四、企業號消息管理... 304
五、消息接口的定義和實現... 310
六、消息的發送操做和實際效果... 313
C#開發微信門戶及應用(20)-微信企業號的菜單管理... 317
一、菜單的整體介紹... 318
二、菜單的實體類定義和接口定義處理... 319
三、企業號菜單管理接口的調用和處理效果... 324
微信應用如火如荼,不少公司都但願搭上信息快車,這個是一個商機,也是一個技術的方向,所以,有空研究下、學習下微信的相關開發,也就 成爲平常計劃的重要事情之一了。本系列文章但願從一個按部就班的角度上,全面介紹微信的相關開發過程和相關經驗總結,但願給你們瞭解一下相關的開發歷程。 本隨筆主要針對微信開發過程的前期準備和一些初始的工做的介紹。
在寫下本文的以前一週時間裏,我主要就是參考一些介紹文章以及微信公衆平臺的相關接口說明,並結合C#的代碼開發,整理了本身公司的門 戶界面,實現了微信工做號的初步用戶交互和信息展現工做,隨着工做的進一步開展,愈來愈多的功能可能加入,並但願從應用角度上擴展微信的接口,從而實現我 對微信接口的技術探祕和了解過程。
要開發使用微信的平臺API,就須要到微信的公衆平臺(https://mp.weixin.qq.com/)去註冊,擁有一個服務號或者訂閱號,服務號主要面對企業和組織,訂閱號主要面向組織和我的,他們之間有必定的差別,根據不一樣的須要本身申請對應的帳號便可。
爲了使用一些高級的接口,你可能須要擁有服務號和高級的認證。帳號註冊過程,須要下載一個申請表格,打印並蓋公章,另外還須要申請人拿着身份證拍照(有點怪異,呵呵),而後上傳到服務器進行審覈,通常很快就能獲取批覆。
我以公司名義申請了服務號,帳號註冊後,會在主界面上顯示你的相關信息,另外給你申請一個二維碼的東西,掃描二維碼便可進入公司的微信關注確認對話框,很是方便。以下就是我申請後的公司帳號二維碼,能夠直接使用掃描。
微信有兩種方式的菜單定義,一種是編輯模式,一種是開發模式,二者互斥,也就是說,一旦咱們採用了開發模式,就不能使用編輯模式了,反過來也同樣。編輯下的菜單,其實也是能夠管理的,可是微信不支持,以爲很不爽。
通常狀況下,若是咱們剛剛申請了微信號碼,能夠使用編輯菜單測試一下,根聽說明編輯一些菜單試試。雖然微信說24小時內更新,不過通常很快,最快可能一兩分鐘就更新了,感受仍是不錯的。
使用開發者模式,你須要根據微信的要求,在服務器上放置一個頁面連接,使用C#開發的,能夠採用***.ashx的命名方式,使用Asp.NET的通常處理程序便可,不須要使用普通的頁面。
使用開發模式的菜單,也就是能夠調用微信API進行菜單建立的工做,對於調用微信的API(微信有不少API能夠調用),咱們須要知道,有幾個參數的重要性,因此在開發模式打開的時候,會給你列出這些參數,以下所示。
上面說了,你申請開發模式對菜單或者對其餘API的調用,你須要順利經過接入微信的測試,也就是確認你填寫的連接存在並能順利通過微信的回調測試。微信提供了一個PHP的頁面處理例子,若是咱們是C#開發的呢,能夠搜一下就會獲得答案,個人處理方式以下所示。
建立一個通常處理程序,而後在其處理頁面裏面增長一個處理邏輯,若是是非POST方式的內容,就是表示微信進行的Get測試,你須要增長一些處理邏輯,把它給你的內容傳回去便可,若是是POST方式的,就是微信服務器對接口消息的請求操做了,後面介紹。
///<summary>
/// 微信接口。統一接收並處理信息的入口。
///</summary>
publicclass wxapi : IHttpHandler
{
publicvoid ProcessRequest(HttpContext context)
{
string postString = string.Empty;
if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST")
{
using (Stream stream = HttpContext.Current.Request.InputStream)
{
Byte[] postBytes = new Byte[stream.Length];
stream.Read(postBytes, 0, (Int32)stream.Length);
postString = Encoding.UTF8.GetString(postBytes);
}
if (!string.IsNullOrEmpty(postString))
{
Execute(postString);
}
}
else
{
Auth(); //微信接入的測試
}
}
通常來講,Auth函數裏面,就是要對相關的參數進行獲取,而後進行處理返回給微信服務器。
string token = "****";//你申請的時候填寫的Token
string echoString = HttpContext.Current.Request.QueryString["echoStr"];
string signature = HttpContext.Current.Request.QueryString["signature"];
string timestamp = HttpContext.Current.Request.QueryString["timestamp"];
string nonce = HttpContext.Current.Request.QueryString["nonce"];
完整的Author函數代碼以下所示,其中我把業務邏輯進行進一步抽取到了一個新的類裏面,方便業務邏輯的管理。
///<summary>
/// 成爲開發者的第一步,驗證並相應服務器的數據
///</summary>
privatevoid Auth()
{
string token = ConfigurationManager.AppSettings["WeixinToken"];//從配置文件獲取Token
if (string.IsNullOrEmpty(token))
{
LogTextHelper.Error(string.Format("WeixinToken 配置項沒有配置!"));
}
string echoString = HttpContext.Current.Request.QueryString["echoStr"];
string signature = HttpContext.Current.Request.QueryString["signature"];
string timestamp = HttpContext.Current.Request.QueryString["timestamp"];
string nonce = HttpContext.Current.Request.QueryString["nonce"];
if (new BasicApi().CheckSignature(token, signature, timestamp, nonce))
{
if (!string.IsNullOrEmpty(echoString))
{
HttpContext.Current.Response.Write(echoString);
HttpContext.Current.Response.End();
}
}
}
而對微信參數的簽名並返回的操做CheckSignature,代碼以下所示。
///<summary>
/// 驗證微信簽名
///</summary>
publicbool CheckSignature(string token, string signature, string timestamp, string nonce)
{
string[] ArrTmp = { token, timestamp, nonce };
Array.Sort(ArrTmp);
string tmpStr = string.Join("", ArrTmp);
tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
tmpStr = tmpStr.ToLower();
if (tmpStr == signature)
{
returntrue;
}
else
{
returnfalse;
}
}
一旦你順利經過微信的認證,那麼它就讓你以開發方式調用它的API,而且能夠隨意建立你的菜單了。
建立菜單的方式,你能夠經過下面的位置進入到他的API處理界面裏面。
進入後,你會發現微信把不少消息的處理,分門別類放到不一樣的分類裏面了。
其實咱們如今初步要作的就是如何看看,使用代碼方式調用建立菜單,進入菜單的API調試界面裏面。
你會發現裏面還須要輸入一個Access_Token的東西,這個是一個會話身份認證,所以你還須要到接口裏面去找這個如何建立的。下面圖中的兩個紅色部分,就是咱們開始的時候,微信提示咱們「開發者憑據」的兩個關鍵參數。
弄完這些,你就能夠根據得到的Access_Token進行菜單的建立工做了,根據菜單的定義,它分爲幾類,能夠分爲URL方式(View),事件方式(Click)。
click:用戶點擊click類型按鈕後,微信服務器會經過消息接口推送消息類型爲event 的結構給開發者(參考消息接口指南),而且帶上按鈕中開發者填寫的key值,開發者能夠經過自定義的key值與用戶進行交互;
view:用戶點擊view類型按鈕後,微信客戶端將會打開開發者在按鈕中填寫的url值 (即網頁連接),達到打開網頁的目的,建議與網頁受權獲取用戶基本信息接口結合,得到用戶的登入我的信息。
在隨筆的開始,我公佈了一個二維碼,一旦使用微信掃一掃,進行關注服務號後,那麼就能夠看到我本身建立的菜單了。主菜單通常最多三列,每一個主菜單還能夠有子菜單,他們的文字都有所限制的。
咱們來看看我公司的微信門戶菜單,看起來是否是很酷呢。
微信應用如火如荼,不少公司都但願搭上信息快車,這個是一個商機,也是一個技術的方向,所以,有空研究下、學習下微信的相關開發,也就 成爲計劃的安排事情之一了。本系列文章但願從一個按部就班的角度上,全面介紹微信的相關開發過程和相關經驗總結,但願給你們瞭解一下相關的開發歷程。本篇 隨筆主要基於上一篇《C#開發微信門戶及應用(1)--開始使用微信接口》的基礎上進行深刻的介紹,介紹微信消息的處理和應答的過程。
咱們知道,微信的服務器架起了客戶手機和開發者服務器的一個橋樑,經過消息的傳遞和響應,實現了與用戶的交互操做,下面是它的消息流程圖。
微信向開發者服務器請求的消息包含了多種類型,不過基原本說,分爲了文本消息處理、事件消息處理、語音消息的識別,以及成爲開發者以前的那個消息認證操做基本分類,下面是我繪製的一個消息分類圖,其中介紹了這幾種關係,以及各自的消息細化分類。
對於這些消息的請求,咱們在開發服務器端,須要編寫相關的邏輯進行對應給的處理,而後給微信服務器平臺迴應消息便可。
在前一篇的隨筆裏面我貼過代碼,介紹微信消息處理的入口操做,代碼以下所示。
publicvoid ProcessRequest(HttpContext context)
{
//WHC.Framework.Commons.LogTextHelper.Info("測試記錄");
string postString = string.Empty;
if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST")
{
using (Stream stream = HttpContext.Current.Request.InputStream)
{
Byte[] postBytes = new Byte[stream.Length];
stream.Read(postBytes, 0, (Int32)stream.Length);
postString = Encoding.UTF8.GetString(postBytes);
}
if (!string.IsNullOrEmpty(postString))
{
Execute(postString);
}
}
else
{
Auth();
}
}
其中的Execute(postString);就是對消息的處理函數,它實現了對不一樣消息的分發處理過程。‘
///<summary>
/// 處理各類請求信息並應答(經過POST的請求)
///</summary>
///<param name="postStr">POST方式提交的數據</param>
privatevoid Execute(string postStr)
{
WeixinApiDispatch dispatch = new WeixinApiDispatch();
string responseContent = dispatch.Execute(postStr);
HttpContext.Current.Response.ContentEncoding = Encoding.UTF8;
HttpContext.Current.Response.Write(responseContent);
}
裏面的WeixinApiDispatch就是一個分發的管理類,它提取請求消息的內容,並構建不一樣類型的消息參數,傳遞給不一樣的響應函數進行處理,而後返回封裝好的XML內容,做爲響應。
具體的代碼處理邏輯以下圖所示。
這個消息處理接口,其實就是定義好一系列的對請求消息的處理操做,參數是不一樣給的消息對象,具體的代碼定義以下所示(因爲篇幅緣由,省略部分接口,具體能夠參考上圖)。
///<summary>
/// 客戶端請求的數據接口
///</summary>
publicinterface IWeixinAction
{
///<summary>
/// 對文本請求信息進行處理
///</summary>
///<param name="info">文本信息實體</param>
///<returns></returns>
string HandleText(RequestText info);
///<summary>
/// 對圖片請求信息進行處理
///</summary>
///<param name="info">圖片信息實體</param>
///<returns></returns>
string HandleImage(RequestImage info);
...........................
///<summary>
/// 對訂閱請求事件進行處理
///</summary>
///<param name="info">訂閱請求事件信息實體</param>
///<returns></returns>
string HandleEventSubscribe(RequestEventSubscribe info);
///<summary>
/// 對菜單單擊請求事件進行處理
///</summary>
///<param name="info">菜單單擊請求事件信息實體</param>
///<returns></returns>
string HandleEventClick(RequestEventClick info);
..............................
}
從上面的代碼能夠看出,不一樣的消息,處處理函數這裏,就以不一樣的消息實體類的方式傳遞過來了(注意:實體類是我根據程序開發須要本身定義的,非微信自己的實體類),這樣很是方便咱們處理操做,不然每次須要解析不一樣的消息內容,很容易出現問題,這樣強類型的數據類型,提升了咱們開發微信應用的強壯型和高效性。這些實體類的對象有必定的繼承關係的,他們的繼承關係以下所示。
上面的消息分類是微信服務器向開發者服務器發送的消息請求操做,還有一種消息,是咱們開發者服務器向微信服務器進行的消息請求或者響應,這種這裏暫且稱之爲微信的管理接口,它代表了咱們能夠經過這些接口進行相關的消息回覆或者數據管理操做。它的分類圖以下所示。
微信的回覆消息處理,它也和上面小節的信息同樣,它也是繼承自BaseMessage實體類的(一樣,下圖的實體類及其繼承關係也是自定義的,方便程序開發),它的關係以下所示
回覆的消息,通常用的最多的是文本消息和圖文消息。
文本消息的效果以下所示。
圖文消息,能夠增長圖片,還能夠增長詳細的連接頁面,是很是好看的一種效果,對於一些內容比較多,但願展示更好效果的,通常採用這種,效果以下所示。
微信應用如火如荼,不少公司都但願搭上信息快車,這個是一個商機,也是一個技術的方向,所以,有空研究下、學習下微信的相關開發,也就 成爲計劃的安排事情之一了。本系列文章但願從一個按部就班的角度上,全面介紹微信的相關開發過程和相關經驗總結,但願給你們瞭解一下相關的開發歷程。
在前面兩篇兩篇隨筆《C#開發微信門戶及應用(1)--開始使用微信接口》和《C#開發微信門戶及應用(2)--微信消息的處理和應答》裏面,大體介紹了我微信應用的框架構建,本隨筆繼續介紹這一主題,介紹消息應答裏面的文本應答和圖文應答的過程。
咱們知道,給手機用戶發送響應消息,它能夠分爲好多種方式,如回覆文本消息、回覆圖片消息、回覆語音消息、回覆視頻消息、回覆音樂消息、回覆圖文消息等,以下所示。
而其中圖片、視頻、語音這三種方式,是須要開通微信認證才能夠向用戶發送存在微信服務器上的媒體信息,通常沒有認證的公衆號或者服務號,是不能發送這幾種內容的。
在上一篇微信開發的隨筆中,我展現了對接收消息和回覆消息的應用實體類,這些實體類是我根據須要,根據開發須要,在應用層面對它們進行了封裝,如回覆的消息關係以下所示。
消息基類BaseMessage的實體類定義以下所示,它對日期構造了一個整形數值,並具有了一些常規的屬性,而且還有一個重要的ToXML方法,用來給方法傳遞這些XML數據的。
///<summary>
/// 基礎消息內容
///</summary>
[XmlRoot(ElementName = "xml")]
publicclass BaseMessage
{
///<summary>
/// 初始化一些內容,如建立時間爲整形,
///</summary>
public BaseMessage()
{
this.CreateTime = DateTime.Now.DateTimeToInt();
}
///<summary>
/// 開發者微信號
///</summary>
publicstring ToUserName { get; set; }
///<summary>
/// 發送方賬號(一個OpenID)
///</summary>
publicstring FromUserName { get; set; }
///<summary>
/// 消息建立時間 (整型)
///</summary>
publicint CreateTime { get; set; }
///<summary>
/// 消息類型
///</summary>
publicstring MsgType { get; set; }
publicvirtualstring ToXml()
{
this.CreateTime = DateTime.Now.DateTimeToInt();//從新更新
return MyXmlHelper.ObjectToXml(this);
}
}
回覆的文本消息實體類代碼以下所示,咱們能夠看到,它繼承了不少通用的實體屬性,而且還具有了一個ToXml的通用方法,咱們須要把它轉換爲響應的XML的時候,就使用這個方法就能夠了。
///<summary>
/// 回覆文本消息
///</summary>
[System.Xml.Serialization.XmlRoot(ElementName = "xml")]
publicclass ResponseText : BaseMessage
{
public ResponseText()
{
this.MsgType = ResponseMsgType.Text.ToString().ToLower();
}
public ResponseText(BaseMessage info) : this()
{
this.FromUserName = info.ToUserName;
this.ToUserName = info.FromUserName;
}
///<summary>
/// 內容
///</summary>
publicstring Content { get; set; }
}
而圖文消息對象類ResponseNews,它包含更多的信息定義
///<summary>
/// 回覆圖文消息
///</summary>
[System.Xml.Serialization.XmlRoot(ElementName = "xml")]
publicclass ResponseNews : BaseMessage
{
public ResponseNews()
{
this.MsgType = ResponseMsgType.News.ToString().ToLower();
this.Articles = new List<ArticleEntity>();
}
public ResponseNews(BaseMessage info) : this()
{
this.FromUserName = info.ToUserName;
this.ToUserName = info.FromUserName;
}
///<summary>
/// 圖文消息個數,限制爲10條之內
///</summary>
publicint ArticleCount
{
get
{
returnthis.Articles.Count;
}
set
{
;//增長這個步驟纔出來XML內容
}
}
///<summary>
/// 圖文列表。
/// 多條圖文消息信息,默認第一個item爲大圖,注意,若是圖文數超過10,則將會無響應
///</summary>
[System.Xml.Serialization.XmlArrayItem("item")]
public List<ArticleEntity> Articles { get; set; }
}
而其中的圖文列表集合中的對象,它也是一個實體類型,包含了一些圖文的連接,標題等信息,不在贅述。
如對於文本消息,咱們能夠用如下的方式進行處理。
ResponseText response = new ResponseText(info);
response.Content = "抱歉,此功能暫未開通。";
result = response.ToXml();
對於圖文消息,咱們可能須要錄入更多的消息才能返回更好的效果。
注意圖文的消息,圖片的尺寸最好按照官方的標準,不然在手機上看起來很差看,官方的標準好像是寬高是(360,200)像素
///<summary>
/// 訂閱或者顯示公司信息
///</summary>
///<param name="info"></param>
///<returns></returns>
privatestring ShowCompanyInfo(BaseMessage info)
{
string result = "";
//使用在微信平臺上的圖文信息(單圖文信息)
ResponseNews response = new ResponseNews(info);
ArticleEntity entity = new ArticleEntity();
entity.Title = "廣州愛奇迪軟件科技有限公司";
entity.Description = "歡迎關注廣州愛奇迪軟件--專業的單位信息化軟件和軟件開發框架提供商,咱們立志於爲客戶提供最好的軟件及服務。\r\n";
entity.Description += "咱們是一家極富創新性的軟件科技公司,從事研究、開發並銷售最可靠的、安全易用的技術產品及優質專業的服務,幫助全球客戶和合做夥伴取得成功。\r\n......(此處省略1000字,哈哈)";
entity.PicUrl = "http://www.iqidi.com/WeixinImage/company.png";
entity.Url = "http://www.iqidi.com";
response.Articles.Add(entity);
result = response.ToXml();
return result;
}
咱們來看看我公司的微信門戶菜單,看起來是否是很酷呢。
對於這兩種(文本消息、圖文消息)用的地方是最多,不少微信門戶,都主要是使用這兩種方式進行響應。固然,咱們還能夠根據客戶手機提交上來的各類消息進行不一樣的處理,請求消息的類型我在上一篇的隨筆有介紹,以下所示。
須要關注瞭解總體效果,能夠使用微信直接掃描二維碼便可。
在上個月的對C#開發微信門戶及應用作了介紹,寫過了幾篇的隨筆進行分享,因爲時間關係,間隔了一段時間沒有繼續寫這個系列的博客了,並非對這個方面中止了研究,而是繼續深刻探索這方面的技術,爲了更好的應用起來,專心作好底層的技術開發。
微信的很重要的一個特色就是可以利用其平臺龐大的用戶羣體,所以很容易整合在CRM(客戶關係管理)系統裏面,服務號和訂閱好都可以向關注者推送相 關的產品消息,還能和48小時內響應消息和事件的活躍用戶進行交互對話,所以用戶信息是微信API裏面很是重要的一環,本隨筆主要介紹獲取關注用戶、查看 用戶信息、分組管理等方面的開發應用。
在微信的管理平臺上,咱們能夠看到本身帳號的關注者用戶,以及用戶分組信息,以下所示。
上面的管理界面,能看到關注者用戶的基礎信息,可是使用微信API獲取到的是一個稱之爲OpenID的列表,咱們先了解這個東西是什麼?微信API的說明給出下面的解析:
關注者列表由一串OpenID(加密後的微信號,每一個用戶對每一個公衆號的OpenID是惟一的。對於不一樣公衆號,同一用戶的openid不一樣)組成。公衆號可經過本接口來根據OpenID獲取用戶基本信息,包括暱稱、頭像、性別、所在城市、語言和關注時間。
上面的解析意思很清楚了,就是一個用戶關注咱們的公衆號,那麼無論他是第幾回關注,對咱們公衆號來講,都是一個肯定的值;可是,一個用戶對其餘公衆號,卻有着其餘不一樣的OpenID。
微信提供了爲數很少的幾個關鍵字信息,用來記錄用戶的相關內容,根據用戶的相關定義,咱們定義一個實體類,用來放置獲取回來的用戶信息。
///<summary>
/// 高級接口獲取的用戶信息。
/// 在關注者與公衆號產生消息交互後,公衆號可得到關注者的OpenID
/// (加密後的微信號,每一個用戶對每一個公衆號的OpenID是惟一的。對於不一樣公衆號,同一用戶的openid不一樣)。
/// 公衆號可經過本接口來根據OpenID獲取用戶基本信息,包括暱稱、頭像、性別、所在城市、語言和關注時間。
///</summary>
publicclass UserJson : BaseJsonResult
{
///<summary>
/// 用戶是否訂閱該公衆號標識,值爲0時,表明此用戶沒有關注該公衆號,拉取不到其他信息。
///</summary>
publicint subscribe { get; set; }
///<summary>
/// 用戶的標識,對當前公衆號惟一
///</summary>
publicstring openid { get; set; }
///<summary>
/// 用戶的暱稱
///</summary>
publicstring nickname { get; set; }
///<summary>
/// 用戶的性別,值爲1時是男性,值爲2時是女性,值爲0時是未知
///</summary>
publicint sex { get; set; }
///<summary>
/// 用戶的語言,簡體中文爲zh_CN
///</summary>
publicstring language { get; set; }
///<summary>
/// 用戶所在城市
///</summary>
publicstring city { get; set; }
///<summary>
/// 用戶所在省份
///</summary>
publicstring province { get; set; }
///<summary>
/// 用戶所在國家
///</summary>
publicstring country { get; set; }
///<summary>
/// 用戶頭像,最後一個數值表明正方形頭像大小(有0、4六、6四、9六、132數值可選,0表明640*640正方形頭像),用戶沒有頭像時該項爲空
///</summary>
publicstring headimgurl { get; set; }
///<summary>
/// 用戶關注時間,爲時間戳。若是用戶曾屢次關注,則取最後關注時間
///</summary>
publiclong subscribe_time { get; set; }
}
根據分組信息定義,咱們定義一個分組的實體類信息。
///<summary>
/// 分組信息
///</summary>
publicclass GroupJson : BaseJsonResult
{
///<summary>
/// 分組id,由微信分配
///</summary>
publicint id { get; set; }
///<summary>
/// 分組名字,UTF8編碼
///</summary>
publicstring name { get; set; }
}
在作微信API的開發,不少時候,咱們都須要傳入一個AccessToken,這個就是區分調用者和記錄會話信息的字符串,所以,在學習全部API開發以前,咱們須要很好理解這個訪問控制參數。
這個對象的定義,咱們能夠從微信的API說明中瞭解。
access_token是公衆號的全局惟一票據,公衆號調用各接口時都需使用access_token。正常狀況下access_token有效期爲7200秒,重複獲取將致使上次獲取的access_token失效。因爲獲取access_token的api調用次數很是有限,建議開發者全局存儲與更新access_token,頻繁刷新access_token會致使api調用受限,影響自身業務。
根據上面的說明定義,咱們能夠看到,它是一個和身份,以及會話時間有關的一個參數,並且它的產生次數有限制,所以要求咱們須要對它進行緩存並重複利用,在會話到期以前,咱們應該儘量重用這個參數,避免反覆請求,增長服務器壓力,以及調用的時間。
我定義了一個方法,用來構造生成相關的Access Token,並且它具備緩存的功能,但具體如何緩存及使用,對我API的調用是透明的,咱們只要用的時候,就對它調用就是了。
/// 獲取憑證接口
///</summary>
///<param name="appid">第三方用戶惟一憑證</param>
///<param name="secret">第三方用戶惟一憑證密鑰,既appsecret</param>
string GetAccessToken(string appid, string secret);
緩存主要是基於.NET4增長的類庫MemoryCache,這個是一個很是不錯的緩存類。
個人獲取AccessToken的操做實現代碼以下所示。
///<summary>
/// 獲取每次操做微信API的Token訪問令牌
///</summary>
///<param name="appid">應用ID</param>
///<param name="secret">開發者憑據</param>
///<returns></returns>
publicstring GetAccessToken(string appid, string secret)
{
//正常狀況下access_token有效期爲7200秒,這裏使用緩存設置短於這個時間便可
string access_token = MemoryCacheHelper.GetCacheItem<string>("access_token", delegate()
{
string grant_type = "client_credential";
var url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type={0}&appid={1}&secret={2}",
grant_type, appid, secret);
HttpHelper helper = new HttpHelper();
string result = helper.GetHtml(url);
string regex = "\"access_token\":\"(?<token>.*?)\"";
string token = CRegex.GetText(result, regex, "token");
return token;
},
new TimeSpan(0, 0, 7000)//7000秒過時
);
return access_token;
}
因爲咱們知道,AccessToken默認是7200秒過時,所以在這個時間段裏面,咱們儘量使用緩存來記錄它的值,若是超過了這個時間,咱們調用這個方法的時候,它會自動從新獲取一個新的值給咱們了。
獲取關注用戶列表,一次拉取API調用,最多拉取10000個關注者的OpenID,能夠經過屢次拉取的方式來知足需求。微信的接口定義以下所示。
http請求方式: GET(請使用https協議)
https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
這個接口返回的數據是
{"total":2,"count":2,"data":{"openid":["","OPENID1","OPENID2"]},"next_openid":"NEXT_OPENID"}
根據返回的Json數據定義,咱們還須要定義兩個實體類,用來存放返回的結果。
///<summary>
/// 獲取關注用戶列表的Json結果
///</summary>
publicclass UserListJsonResult : BaseJsonResult
{
///<summary>
/// 關注該公衆帳號的總用戶數
///</summary>
publicint total { get; set; }
///<summary>
/// 拉取的OPENID個數,最大值爲10000
///</summary>
publicint count { get; set; }
///<summary>
/// 列表數據,OPENID的列表
///</summary>
public OpenIdListData data { get; set; }
///<summary>
/// 拉取列表的後一個用戶的OPENID
///</summary>
publicstring next_openid { get; set; }
}
///<summary>
/// 列表數據,OPENID的列表
///</summary>
publicclass OpenIdListData
{
///<summary>
/// OPENID的列表
///</summary>
public List<string> openid { get; set; }
}
爲了獲取相關的用戶信息,我定義了一個接口,用來獲取用戶的信息,接口定義以下所示。
///<summary>
/// 微信用戶管理的API接口
///</summary>
publicinterface IUserApi
{
///<summary>
/// 獲取關注用戶列表
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="nextOpenId">第一個拉取的OPENID,不填默認從頭開始拉取</param>
///<returns></returns>
List<string> GetUserList(string accessToken, string nextOpenId = null);
///<summary>
/// 獲取用戶基本信息
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="openId">普通用戶的標識,對當前公衆號惟一</param>
///<param name="lang">返回國家地區語言版本,zh_CN 簡體,zh_TW 繁體,en 英語</param>
UserJson GetUserDetail(string accessToken, string openId, Language lang = Language.zh_CN);
而後在實現類裏面,咱們分別對上面兩個接口進行實現,獲取用戶列表信息以下所示。
///<summary>
/// 獲取關注用戶列表
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="nextOpenId">第一個拉取的OPENID,不填默認從頭開始拉取</param>
///<returns></returns>
public List<string> GetUserList(string accessToken, string nextOpenId = null)
{
List<string> list = new List<string>();
string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}", accessToken);
if (!string.IsNullOrEmpty(nextOpenId))
{
url += "&next_openid=" + nextOpenId;
}
UserListJsonResult result = JsonHelper<UserListJsonResult>.ConvertJson(url);
if (result != null&& result.data != null)
{
list.AddRange(result.data.openid);
}
return list;
}
咱們看到,轉換的邏輯已經放到了JsonHelper裏面去了,這個輔助類裏面分別對數值進行了獲取內容,驗證返回值,而後轉換正確實體類幾個部分的操做。
獲取內容,經過輔助類HttpHelper進行,這個在個人公用類庫裏面,裏面的邏輯主要就是經過HttpRequest進行數據的獲取操做,不在贅述。
HttpHelper helper = new HttpHelper();
string content = helper.GetHtml(url);
因爲返回的內容,咱們須要判斷它是否正確返回所需的結果,若是沒有,拋出自定義的相關異常,方便處理,具體以下所示。
///<summary>
/// 檢查返回的記錄,若是返回沒有錯誤,或者結果提示成功,則不拋出異常
///</summary>
///<param name="content">返回的結果</param>
///<returns></returns>
privatestaticbool VerifyErrorCode(string content)
{
if (content.Contains("errcode"))
{
ErrorJsonResult errorResult = JsonConvert.DeserializeObject<ErrorJsonResult>(content);
//非成功操做才記錄異常,由於有些操做是返回正常的結果({"errcode": 0, "errmsg": "ok"})
if (errorResult != null&& errorResult.errcode != ReturnCode.請求成功)
{
string error = string.Format("微信請求發生錯誤!錯誤代碼:{0},說明:{1}", (int)errorResult.errcode, errorResult.errmsg);
LogTextHelper.Error(errorResult);
thrownew WeixinException(error);//拋出錯誤
}
}
returntrue;
}
而後轉換爲相應的格式,就是經過Json.NET的類庫進行轉換。
T result = JsonConvert.DeserializeObject<T>(content);
return result;
這樣咱們就能夠在ConvertJson函數實體裏面,完整的進行處理和轉換了,轉換完整的函數代碼以下所示。
///<summary>
/// Json字符串操做輔助類
///</summary>
publicclass JsonHelper<T>where T : class, new()
{
///<summary>
/// 檢查返回的記錄,若是返回沒有錯誤,或者結果提示成功,則不拋出異常
///</summary>
///<param name="content">返回的結果</param>
///<returns></returns>
privatestaticbool VerifyErrorCode(string content)
{
if (content.Contains("errcode"))
{
ErrorJsonResult errorResult = JsonConvert.DeserializeObject<ErrorJsonResult>(content);
//非成功操做才記錄異常,由於有些操做是返回正常的結果({"errcode": 0, "errmsg": "ok"})
if (errorResult != null&& errorResult.errcode != ReturnCode.請求成功)
{
string error = string.Format("微信請求發生錯誤!錯誤代碼:{0},說明:{1}", (int)errorResult.errcode, errorResult.errmsg);
LogTextHelper.Error(errorResult);
thrownew WeixinException(error);//拋出錯誤
}
}
returntrue;
}
///<summary>
/// 轉換Json字符串到具體的對象
///</summary>
///<param name="url">返回Json數據的連接地址</param>
///<returns></returns>
publicstatic T ConvertJson(string url)
{
HttpHelper helper = new HttpHelper();
string content = helper.GetHtml(url);
VerifyErrorCode(content);
T result = JsonConvert.DeserializeObject<T>(content);
return result;
}
}
調用這個API的界面層代碼以下所示(測試代碼)
IUserApi userBLL = new UserApi();
List<string> userList = userBLL.GetUserList(token)
上面的獲取列表操做,相對比較簡單,並且不用POST任何數據,所以經過Get協議就能獲取到所需的數據。
本小節繼續介紹獲取用戶詳細信息的操做,這個操做也是經過GET協議就能夠完成的。
這個API的調用定義以下所示:
http請求方式: GET
https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
經過傳入一個OpenId,咱們就能很好獲取到用戶的相關信息了。
前面小節咱們已經定義了它的接口,說明了傳入及返回值,根據定義,它的實現函數以下所示。
///<summary>
/// 獲取用戶基本信息
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="openId">普通用戶的標識,對當前公衆號惟一</param>
///<param name="lang">返回國家地區語言版本,zh_CN 簡體,zh_TW 繁體,en 英語</param>
public UserJson GetUserDetail(string accessToken, string openId, Language lang = Language.zh_CN)
{
string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang={2}",
accessToken, openId, lang.ToString());
UserJson result = JsonHelper<UserJson>.ConvertJson(url);
return result;
}
最後,咱們結合獲取用戶列表和獲取用戶詳細信息的兩個API,咱們看看調用的代碼(測試代碼)。
privatevoid btnGetUsers_Click(object sender, EventArgs e)
{
IUserApi userBLL = new UserApi();
List<string> userList = userBLL.GetUserList(token);
foreach (string openId in userList)
{
UserJson userInfo = userBLL.GetUserDetail(token, openId);
if (userInfo != null)
{
string tips = string.Format("{0}:{1}", userInfo.nickname, userInfo.openid);
Console.WriteLine(tips);
}
}
}
在上個月的對C#開發微信門戶及應用作了介紹,寫過了幾篇的隨筆進行分享,因爲時間關係,間隔了一段時間沒有繼續寫這個系列的博客了,並非對這個 方面中止了研究,而是繼續深刻探索這方面的技術,爲了更好的應用起來,專心作好底層的技術開發。本篇繼續上一篇的介紹,主要介紹分組管理方面的開發應用, 這篇的內容和上一篇,做爲一個完整的用戶信息和分組信息管理的組合。
用戶分組的引入,主要是方便管理關注者列表,以及方便向不一樣的組別發送消息的操做的,一個公衆帳號,最多支持建立500個分組。
用戶分組管理,包含下面幾個方面的內容:
1 建立分組
2 查詢全部分組
3 查詢用戶所在分組
4 修改分組名
5 移動用戶分組
微信對於建立分組的定義以下所示。
http請求方式: POST(請使用https協議)
https://api.weixin.qq.com/cgi-bin/groups/create?access_token=ACCESS_TOKEN
POST數據格式:json
POST數據例子:{"group":{"name":"test"}}
正常返回的結果以下所示。
{
"group": {
"id": 107,
"name": "test"
}
}
其餘接口,也是相似的方式,經過POST一些參數進去URL裏面,獲取返回的Json數據。
前面隨筆定義了GroupJson的實體類信息以下所示。
/// <summary>
/// 分組信息
/// </summary>
public class GroupJson : BaseJsonResult
{
/// <summary>
/// 分組id,由微信分配
/// </summary>
public int id { get; set; }
/// <summary>
/// 分組名字,UTF8編碼
/// </summary>
public string name { get; set; }
}
根據以上幾個接口的定義,我定義了幾個接口,並把它們概括到用戶管理的API接口裏面。
///<summary>
/// 查詢全部分組
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<returns></returns>
List<GroupJson> GetGroupList(string accessToken);
///<summary>
/// 建立分組
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="name">分組名稱</param>
///<returns></returns>
GroupJson CreateGroup(string accessToken, string name);
///<summary>
/// 查詢用戶所在分組
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="openid">用戶的OpenID</param>
///<returns></returns>
int GetUserGroupId(string accessToken, string openid);
///<summary>
/// 修改分組名
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="id">分組id,由微信分配</param>
///<param name="name">分組名字(30個字符之內)</param>
///<returns></returns>
CommonResult UpdateGroupName(string accessToken, int id, string name);
///<summary>
/// 移動用戶分組
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="openid">用戶的OpenID</param>
///<param name="to_groupid">分組id</param>
///<returns></returns>
CommonResult MoveUserToGroup(string accessToken, string openid, int to_groupid);
2.1 建立用戶分組
爲了解析如何實現建立用戶分組的POST數據操做,咱們來一步步瞭解建立用戶的具體過程。
首先須要建立一個動態定義的實體類信息,它包含幾個須要說起的屬性,以下所示。
string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/create?access_token={0}", accessToken);
var data = new
{
group = new
{
name = name
}
};
string postData = data.ToJson();
其中咱們把對象轉換爲合適的Json數據操做,放到了擴展方法ToJson裏面了,這個主要就是方便把動態定義的實體類轉換Json內容,主要就是調用Json.NET的序列號操做。
///<summary>
/// 把對象爲json字符串
///</summary>
///<param name="obj">待序列號對象</param>
///<returns></returns>
publicstaticstring ToJson(thisobject obj)
{
return JsonConvert.SerializeObject(obj, Formatting.Indented);
}
準備好Post的數據後,咱們就進一步看看獲取數據並轉換爲合適格式的操做代碼。
GroupJson group = null;
CreateGroupResult result = JsonHelper<CreateGroupResult>.ConvertJson(url, postData);
if (result != null)
{
group = result.group;
}
其中POST數據並轉換爲合適格式實體類的操做,放在了ConvertJson方法裏面,這個方法的定義以下所示,裏面的HttpHelper是我公用類庫的輔助類,主要就是調用底層的httpWebRequest對象方法,進行數據的提交,並獲取返回結果。
///<summary>
/// 轉換Json字符串到具體的對象
///</summary>
///<param name="url">返回Json數據的連接地址</param>
///<param name="postData">POST提交的數據</param>
///<returns></returns>
publicstatic T ConvertJson(string url, string postData)
{
HttpHelper helper = new HttpHelper();
string content = helper.GetHtml(url, postData, true);
VerifyErrorCode(content);
T result = JsonConvert.DeserializeObject<T>(content);
return result;
}
這樣,完整的建立用戶分組的操做函數以下所示。
///<summary>
/// 建立分組
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="name">分組名稱</param>
///<returns></returns>
public GroupJson CreateGroup(string accessToken, string name)
{
string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/create?access_token={0}", accessToken);
var data = new
{
group = new
{
name = name
}
};
string postData = data.ToJson();
GroupJson group = null;
CreateGroupResult result = JsonHelper<CreateGroupResult>.ConvertJson(url, postData);
if (result != null)
{
group = result.group;
}
return group;
}
2.2 查詢全部分組
查詢全部分組,能夠把服務器上的分組所有獲取下來,也就是每一個分組的ID和名稱。
///<summary>
/// 查詢全部分組
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<returns></returns>
public List<GroupJson> GetGroupList(string accessToken)
{
string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/get?access_token={0}", accessToken);
List<GroupJson> list = new List<GroupJson>();
GroupListJsonResult result = JsonHelper<GroupListJsonResult>.ConvertJson(url);
if (result != null&& result.groups != null)
{
list.AddRange(result.groups);
}
return list;
}
2.3 查詢用戶所在分組
每一個用戶都屬於一個分組,默認在 未分組 這個分組裏面,咱們能夠經過API獲取用戶的分組信息,也就是獲取所在用戶分組的ID。
///<summary>
/// 查詢用戶所在分組
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="openid">用戶的OpenID</param>
///<returns></returns>
publicint GetUserGroupId(string accessToken, string openid)
{
string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/getid?access_token={0}", accessToken);
var data = new
{
openid = openid
};
string postData = data.ToJson();
int groupId = -1;
GroupIdJsonResult result = JsonHelper<GroupIdJsonResult>.ConvertJson(url, postData);
if (result != null)
{
groupId = result.groupid;
}
return groupId;
}
2.4 修改分組名稱
也能夠在實際中,調整用戶所在的分組,操做代碼以下。
///<summary>
/// 修改分組名
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="id">分組id,由微信分配</param>
///<param name="name">分組名字(30個字符之內)</param>
///<returns></returns>
public CommonResult UpdateGroupName(string accessToken, int id, string name)
{
string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/update?access_token={0}", accessToken);
var data = new
{
group = new
{
id = id,
name = name
}
};
string postData = data.ToJson();
return Helper.GetExecuteResult(url, postData);
}
這裏的返回值CommonResult是,一個實體類,包含了bool的成功與否的標誌,以及String類型的錯誤信息(若是有的話)。
對於這個GetExecuteResult函數體,裏面主要就是提交數據,而後獲取結果,並根據結果進行處理的函數。
///<summary>
/// 通用的操做結果
///</summary>
///<param name="url">網頁地址</param>
///<param name="postData">提交的數據內容</param>
///<returns></returns>
publicstatic CommonResult GetExecuteResult(string url, string postData = null)
{
CommonResult success = new CommonResult();
try
{
ErrorJsonResult result;
if (postData != null)
{
result = JsonHelper<ErrorJsonResult>.ConvertJson(url, postData);
}
else
{
result = JsonHelper<ErrorJsonResult>.ConvertJson(url);
}
if (result != null)
{
success.Success = (result.errcode == ReturnCode.請求成功);
success.ErrorMessage = result.errmsg;
}
}
catch (WeixinException ex)
{
success.ErrorMessage = ex.Message;
}
return success;
}
}
上面紅色部分的意思,就是轉換爲實體類的時候,若是錯誤是微信裏面定義的,那麼記錄錯誤信息,其餘異常我不處理(也就是拋出去)。
2.5 移動用戶到新的分組
移動用戶到新的分組的操做和上面小節的差很少,具體看代碼。
///<summary>
/// 移動用戶分組
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="openid">用戶的OpenID</param>
///<param name="to_groupid">分組id</param>
///<returns></returns>
public CommonResult MoveUserToGroup(string accessToken, string openid, int to_groupid)
{
string url = string.Format("https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token={0}", accessToken);
var data = new
{
openid = openid,
to_groupid = to_groupid
};
string postData = data.ToJson();
return Helper.GetExecuteResult(url, postData);
}
上面小節,定義並實現了用戶分組的各種接口,全部的用戶相關的都已經毫無保留貼出代碼,它的調用操做以下代碼所示(測試代碼)。
privatevoid btnGetGroupList_Click(object sender, EventArgs e)
{
IUserApi userBLL = new UserApi();
List<GroupJson> list = userBLL.GetGroupList(token);
foreach (GroupJson info in list)
{
string tips = string.Format("{0}:{1}", info.name, info.id);
Console.WriteLine(tips);
}
}
privatevoid btnFindUserGroup_Click(object sender, EventArgs e)
{
IUserApi userBLL = new UserApi();
int groupId = userBLL.GetUserGroupId(token, openId);
string tips = string.Format("GroupId:{0}", groupId);
Console.WriteLine(tips);
}
privatevoid btnCreateGroup_Click(object sender, EventArgs e)
{
IUserApi userBLL = new UserApi();
GroupJson info = userBLL.CreateGroup(token, "建立測試分組");
if (info != null)
{
string tips = string.Format("GroupId:{0} GroupName:{1}", info.id, info.name);
Console.WriteLine(tips);
string newName = "建立測試修改";
CommonResult result = userBLL.UpdateGroupName(token, info.id, newName);
Console.WriteLine("修改分組名稱:" + (result.Success ? "成功" : "失敗:" + result.ErrorMessage));
}
}
privatevoid btnUpdateGroup_Click(object sender, EventArgs e)
{
int groupId = 111;
string newName = "建立測試修改";
IUserApi userBLL = new UserApi();
CommonResult result = userBLL.UpdateGroupName(token, groupId, newName);
Console.WriteLine("修改分組名稱:" + (result.Success ? "成功" : "失敗:" + result.ErrorMessage));
}
privatevoid btnMoveToGroup_Click(object sender, EventArgs e)
{
int togroup_id = 111;//輸入分組ID
if (togroup_id >0)
{
IUserApi userBLL = new UserApi();
CommonResult result = userBLL.MoveUserToGroup(token, openId, togroup_id);
Console.WriteLine("移動用戶分組名稱:" + (result.Success ? "成功" : "失敗:" + result.ErrorMessage));
}
}
瞭解了上面的代碼和調用規則,咱們就能經過API進行用戶分組信息的管理了。經過在應用程序中集成相關的接口代碼,咱們就可以很好的控制咱們的關注用戶列表和用戶分組信息。從而爲咱們下一步用戶的信息推送打好基礎。
前面幾篇繼續了我本身對於C#開發微信門戶及應用的技術探索和相關的經驗總結,繼續探索微信API並分享相關的技術,一方面是爲了和你們對這方面進行互動溝通,另外一方面也是專心作好微信應用的底層技術開發,把基礎模塊夯實,在將來的應用中派上用途。本隨筆繼續介紹微信門戶菜單的管理操做。
微信門戶的菜單,通常服務號和訂閱號均可以擁有這個模塊的開發,可是訂閱號好像須要認證後才能擁有,而服務號則不須要認證就能夠擁有 了。這個菜單能夠有編輯模式和開發模式,編輯模式主要就是在微信門戶的平臺上,對菜單進行編輯;而開發模式,就是用戶能夠經過調用微信的API對菜單進行 定製開發,經過POST數據到微信服務器,從而生成對應的菜單內容。本文主要介紹基於開發模式的菜單管理操做。
自定義菜單可以幫助公衆號豐富界面,讓用戶更好更快地理解公衆號的功能。目前自定義菜單最多包括3個一級菜單,每一個一級菜單最多包含5個二級菜單。一級菜單最多4個漢字,二級菜單最多7個漢字,多出來的部分將會以「...」代替。目前自定義菜單接口可實現兩種類型按鈕,以下:
click:
用戶點擊click類型按鈕後,微信服務器會經過消息接口推送消息類型爲event 的結構給開發者(參考消息接口指南),而且帶上按鈕中開發者填寫的key值,開發者能夠經過自定義的key值與用戶進行交互;
view:
用戶點擊view類型按鈕後,微信客戶端將會打開開發者在按鈕中填寫的url值 (即網頁連接),達到打開網頁的目的,建議與網頁受權獲取用戶基本信息接口結合,得到用戶的登入我的信息。
菜單提交的數據,自己是一個Json的數據字符串,它的官方例子數據以下所示。
{
"button":[
{
"type":"click",
"name":"今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"type":"click",
"name":"歌手簡介",
"key":"V1001_TODAY_SINGER"
},
{
"name":"菜單",
"sub_button":[
{
"type":"view",
"name":"搜索",
"url":"http://www.soso.com/"
},
{
"type":"view",
"name":"視頻",
"url":"http://v.qq.com/"
},
{
"type":"click",
"name":"贊一下咱們",
"key":"V1001_GOOD"
}]
}]
}
從上面咱們能夠看到,菜單不一樣的type類型,有不一樣的字段內容,如type爲view的有url屬性,而type爲click的,則有key屬性。而菜單能夠有子菜單sub_button屬性,總得來講,爲了構造好對應的菜單實體類信息,不是一下就能分析的出來。
我看過一些微信接口的開發代碼,把菜單的分爲了好多個實體類,指定了繼承關係,而後分別對他們進行屬性的配置,大概的關係以下所示。
這種多層關係的繼承方式能解決問題,不過我以爲並非優雅的解決方案。其實結合Json.NET自身的Attribute屬性配置,能夠指定那些爲空的內容在序列號爲Json字符串的時候,不顯示出來的。
[JsonProperty( NullValueHandling = NullValueHandling.Ignore)]
有了這個屬性,咱們就能夠統必定義菜單的實體類信息更多的屬性了,能夠把View類型和Click類型的菜單屬性的url和key合併在一塊兒。
///<summary>
/// 菜單基本信息
///</summary>
publicclass MenuInfo
{
///<summary>
/// 按鈕描述,既按鈕名字,不超過16個字節,子菜單不超過40個字節
///</summary>
publicstring name { get; set; }
///<summary>
/// 按鈕類型(click或view)
///</summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
publicstring type { get; set; }
///<summary>
/// 按鈕KEY值,用於消息接口(event類型)推送,不超過128字節
///</summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
publicstring key { get; set; }
///<summary>
/// 網頁連接,用戶點擊按鈕可打開連接,不超過256字節
///</summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
publicstring url { get; set; }
///<summary>
/// 子按鈕數組,按鈕個數應爲2~5個
///</summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public List<MenuInfo> sub_button { get; set; }
.......
可是,這麼多信息,不一樣的類型我須要指定不一樣的屬性類型,那不是挺麻煩,萬一我在View類型的菜單裏面,把key屬性設置了,那怎麼辦?
解決方法就是咱們定義幾個構造函數,分別用來構造不一樣的菜單信息,以下所示是對菜單不一樣的類型,賦值給不一樣的屬性的構造函數。
///<summary>
/// 參數化構造函數
///</summary>
///<param name="name">按鈕名稱</param>
///<param name="buttonType">菜單按鈕類型</param>
///<param name="value">按鈕的鍵值(Click),或者鏈接URL(View)</param>
public MenuInfo(string name, ButtonType buttonType, string value)
{
this.name = name;
this.type = buttonType.ToString();
if (buttonType == ButtonType.click)
{
this.key = value;
}
elseif(buttonType == ButtonType.view)
{
this.url = value;
}
}
好了,還有另一個問題,子菜單也就是屬性sub_button是無關緊要的東西,有的話,須要指定Name屬性,並添加它的sub_button集合對象就能夠了,那麼咱們在增長一個構造子菜單的對象信息的構造函數。
///<summary>
/// 參數化構造函數,用於構造子菜單
///</summary>
///<param name="name">按鈕名稱</param>
///<param name="sub_button">子菜單集合</param>
public MenuInfo(string name, IEnumerable<MenuInfo> sub_button)
{
this.name = name;
this.sub_button = new List<MenuInfo>();
this.sub_button.AddRange(sub_button);
}
因爲只指定Name和sub_button的屬性內容,其餘內容爲null的話,天然構造出來的Json就沒有包含它們,很是完美!
爲了獲取菜單的信息,咱們還須要定義兩個實體對象,以下所示。
///<summary>
/// 菜單的Json字符串對象
///</summary>
publicclass MenuJson
{
public List<MenuInfo> button { get; set; }
public MenuJson()
{
button = new List<MenuInfo>();
}
}
///<summary>
/// 菜單列表的Json對象
///</summary>
publicclass MenuListJson
{
public MenuJson menu { get; set; }
}
咱們從微信的定義裏面,能夠看到,咱們經過API能夠獲取菜單信息、建立菜單、刪除菜單,那麼咱們來定義它們的接口以下。
///<summary>
/// 菜單的相關操做
///</summary>
publicinterface IMenuApi
{
///<summary>
/// 獲取菜單數據
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<returns></returns>
MenuJson GetMenu(string accessToken);
///<summary>
/// 建立菜單
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="menuJson">菜單對象</param>
///<returns></returns>
CommonResult CreateMenu(string accessToken, MenuJson menuJson);
///<summary>
/// 刪除菜單
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<returns></returns>
CommonResult DeleteMenu(string accessToken);
}
具體的獲取菜單信息的實現以下。
///<summary>
/// 獲取菜單數據
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<returns></returns>
public MenuJson GetMenu(string accessToken)
{
MenuJson menu = null;
var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}", accessToken);
MenuListJson list = JsonHelper<MenuListJson>.ConvertJson(url);
if (list != null)
{
menu = list.menu;
}
return menu;
}
這裏就是把返回的Json數據,統一轉換爲咱們須要的實體信息了,一步到位。
調用代碼以下所示。
privatevoid btnGetMenuJson_Click(object sender, EventArgs e)
{
IMenuApi menuBLL = new MenuApi();
MenuJson menu = menuBLL.GetMenu(token);
if (menu != null)
{
Console.WriteLine(menu.ToJson());
}
}
建立和刪除菜單對象的操做實現以下所示。
///<summary>
/// 建立菜單
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="menuJson">菜單對象</param>
///<returns></returns>
public CommonResult CreateMenu(string accessToken, MenuJson menuJson)
{
var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}", accessToken);
string postData = menuJson.ToJson();
return Helper.GetExecuteResult(url, postData);
}
///<summary>
/// 刪除菜單
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<returns></returns>
public CommonResult DeleteMenu(string accessToken)
{
var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}", accessToken);
return Helper.GetExecuteResult(url);
}
看到這裏,有些人可能會問,實體類你簡化了,那麼建立菜單是否是挺麻煩的,特別是構造對應的信息應該如何操做呢?前面不是介紹了不一樣的構造函數了嗎,經過他們簡單就搞定了,不用記下太多的實體類及它們的繼承關係來處理菜單信息。
privatevoid btnCreateMenu_Click(object sender, EventArgs e)
{
MenuInfo productInfo = new MenuInfo("軟件產品", new MenuInfo[] {
new MenuInfo("病人資料管理系統", ButtonType.click, "patient"),
new MenuInfo("客戶關係管理系統", ButtonType.click, "crm"),
new MenuInfo("酒店管理系統", ButtonType.click, "hotel"),
new MenuInfo("送水管理系統", ButtonType.click, "water")
});
MenuInfo frameworkInfo = new MenuInfo("框架產品", new MenuInfo[] {
new MenuInfo("Win開發框架", ButtonType.click, "win"),
new MenuInfo("WCF開發框架", ButtonType.click, "wcf"),
new MenuInfo("混合式框架", ButtonType.click, "mix"),
new MenuInfo("Web開發框架", ButtonType.click, "web"),
new MenuInfo("代碼生成工具", ButtonType.click, "database2sharp")
});
MenuInfo relatedInfo = new MenuInfo("相關連接", new MenuInfo[] {
new MenuInfo("公司介紹", ButtonType.click, "Event_Company"),
new MenuInfo("官方網站", ButtonType.view, "http://www.iqidi.com"),
new MenuInfo("提點建議", ButtonType.click, "Event_Suggestion"),
new MenuInfo("聯繫客服", ButtonType.click, "Event_Contact"),
new MenuInfo("發郵件", ButtonType.view, "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=S31yfX15fn8LOjplKCQm")
});
MenuJson menuJson = new MenuJson();
menuJson.button.AddRange(new MenuInfo[] { productInfo, frameworkInfo, relatedInfo });
//Console.WriteLine(menuJson.ToJson());
if (MessageUtil.ShowYesNoAndWarning("您確認要建立菜單嗎") == System.Windows.Forms.DialogResult.Yes)
{
IMenuApi menuBLL = new MenuApi();
CommonResult result = menuBLL.CreateMenu(token, menuJson);
Console.WriteLine("建立菜單:" + (result.Success ? "成功" : "失敗:" + result.ErrorMessage));
}
}
這個就是我微信門戶裏面的菜單操做了,具體效果能夠關注個人微信門戶:廣州愛奇迪,也能夠掃描下面二維碼進行關注瞭解。
菜單的效果以下:
最近一直在弄微信的集成功能開發,發現微信給認證帳戶開通了一個多客服的功能,對於客戶的諮詢,能夠切換至客服處理的方式,並且能夠添加多個客服進 行處理,這個在客戶諮詢比較多的時候,是一個不錯的營銷功能。微信多客服的功能,可以在很大程度上利用客服員工資源,及時迅速對客戶諮詢信息進行處理,爲 企業帶來更多的機會和市場。
默認這個多客服的功能,須要在微信公衆平臺中的服務中心進行主動開通,默認是不開通的,爲了體驗這個功能,我這裏把多客服功能進行開通。
微信的多客服功能,對於客服的響應操做,既能夠在電腦的客戶端上進行操做,也能夠在微信多客服助手進行信息處理,二者都能對客戶的信息進行迴應、結束會話等操做。
開通微信多客服功能後,就須要添加一些處理客戶信息的客服工號了。
多客服帳號採用「工號@微信號」的形式進行登陸,請您在登陸窗口依照下圖形式輸入賬號信息。
在電腦客戶端上使用
在手機客戶端上進行多客服的使用,就是關注一個帳號,信息經過轉發到這裏進行處理。關注公衆號」多客服助手「就搞定了。
經過上面兩種途徑,可以很好處理客戶的相關信息,其實也就是相似電話坐席的方式,讓不一樣的客服員工,對來訪的客戶進行處理。
在微信的多客服開發介紹中,內容介紹的比較少,以下所示。
在新的微信協議中,開發模式也能夠接入客服系統。 開發者若是須要使用客服系統,須要在接收到用戶發送的消息時,返回一個MsgType爲transfer_customer_service的消息,微信 服務器在收到這條消息時,會把用戶此次發送的和之後一段時間內發送的消息轉發客服系統。返回的消息舉例以下。
<xml>
<ToUserName><![CDATA[touser]]></ToUserName>
<FromUserName><![CDATA[fromuser]]></FromUserName>
<CreateTime>1399197672</CreateTime>
<MsgType><![CDATA[transfer_customer_service]]></MsgType>
</xml>
而在開發的時候,咱們通常把它封裝爲一個實體類信息,以下所示。主要就是指定消息類型,和翻轉傳入傳出對象就能夠了。
///<summary>
/// 客服消息
///</summary>
[System.Xml.Serialization.XmlRoot(ElementName = "xml")]
publicclass ResponseCustomer : BaseMessage
{
public ResponseCustomer()
{
this.MsgType = ResponseMsgType.transfer_customer_service.ToString().ToLower();
}
public ResponseCustomer(BaseMessage info) : this()
{
this.FromUserName = info.ToUserName;
this.ToUserName = info.FromUserName;
}
}
而後調用處理的時候,代碼以下所示。
ResponseCustomer customInfo = new ResponseCustomer(info);
xml = customInfo.ToXml();
如我在客戶應答處理裏面,客戶迴應0,我就切換進入客服模式,這樣客戶後續全部的輸入內容,均不會觸發微信門戶裏面的解析,而轉發到客服模式,讓客服的工號能夠和客戶進行交談了。
//處理 0 指令, 人工客服
if (string.IsNullOrEmpty(xml) && eventKey.Trim() == "0")
{
xml = base.DealEvent(eventInfo, "event_customservice");
}
而在DealEvent裏面,根據這個條件進行處理就能夠了。
//人工客服
if (eventKey == "event_customservice")
{
ResponseCustomer customInfo = new ResponseCustomer(info);
xml = customInfo.ToXml();
}
經過使用多客服的客戶端,這樣處理消息交互起來很是方便,能得到客戶的對話信息了,在電腦客戶端上,看到的界面以下所示。
手機上的談話截圖以下所示。
這樣就可以經過多途徑,及時響應客戶的信息了。
若是感興趣或者體驗相關的客服應答功能,能夠關注個人微信瞭解下。具體效果能夠關注個人微信門戶:廣州愛奇迪,也能夠掃描下面二維碼進行關注瞭解。
最近對微信接口進行深刻的研究,經過把底層接口一步步進行封裝後,逐步升級到自動化配置、自動化應答,以及後臺處理界面的優化和完善上,力求搭建一個較爲完善、適用的微信門戶應用管理系統。
微信門戶應用管理系統,採用基於MVC+EasyUI的路線,因爲多數域名服務器上都只能支持.NET4.0,因此以MVC3,C#4.0做爲開發基礎,基本上可以部署在任何.NET服務器上。
在微信門戶系統裏面,實現下面這些功能操做:
1)實現菜單的動態配置及更新到服務器上;
2)動態定義事件和響應消息,實現對不一樣行業,不一樣需求的菜單動做響應;
3)動態的應答指令配置處理,實現整套應答鏈的消息處理;
4)獲取訂閱用戶和用戶分組信息,並能夠實現用戶分組信息的維護等操做;
5)管理並更新多媒體文件、圖文消息等內容,方便爲客戶推送消息作準備。
6)使用向選定訂閱用戶或者分組進行消息的羣發功能。
在系統中管理菜單,並經過把菜單提交到服務器上,實現菜單的動態配置和生成,可以爲咱們系統適應各類的須要,實現靈活的處理。
微信菜單的添加界面以下所示。
微信菜單的修改界面以下所示
微信菜單定義是存儲在數據庫裏面,若是須要提交到微信服務器上並生效,則須要調用微信API接口進行處理,我在頁面的Controller控制器裏增長一個提交到服務器的處理方法。
在微信服務帳號的門戶上,菜單的表現效果以下所示。
對於動態生成的菜單,大多數狀況下是用做Click的方式,也就是須要定義每一個菜單的事件響應操做,咱們使用微信的話,能夠了解到,微信的處理事件,通常能夠響應用戶文本消息、圖片消息、圖文消息等內容,常規下,通常使用文本消息或者圖文消息居多。
爲了進一步實現響應內容的重用,咱們把菜單的事件定義和內容定義進行分開管理,事件定義能夠使用多個文本消息,也能夠使用多個圖文消息進行組合,這樣能夠實現更加靈活的使用環境。
添加事件定義以下所示
事件的響應內容編碼,能夠選擇輸入或者從「編輯」按鈕中選擇,當選擇「編輯」按鈕進行選擇的時候,系統彈出一個對話框供用戶對事件的響應內容編碼選擇。
完成選擇後,回到原來的新增界面,將會看到返回的記錄就是咱們選擇的記錄。
微信事件的編輯界面以下所示,相似新增界面的內容。
上面說到,菜單的事件經過關聯事件編碼進行處理,而事件自己能夠組合多個消息內容,所以消息內容是響應客戶操做的最小單元,它們能夠是一條文本消息、圖文消息,也能夠是多條消息的組合(同類型的話)。
爲了方便管理,我把消息分爲了圖文、指令、文本類型,若是須要,還能夠根據須要把它細化爲其餘類型的消息。
消息內容的添加界面以下所示。
文本消息的手機上界面效果以下所示。
這裏無論是文本消息仍是圖文消息,咱們統一以圖文消息的定義來定義消息,若是是文本消息,咱們只須要獲取描述內容做爲消息的主體便可。
圖文消息的編輯界面以下所示,主要就是填寫完整的內容和圖片,以及頁面詳細的連接便可。
上面的這個客戶關係管理系統的消息,在手機上顯示的界面效果以下所示,單擊連接,能夠切換到消息跳轉連接地址的。
應答指令的維護,有點相似於事件的管理,主要就是定義一些用到的指令,方便構建應答系統的響應鏈,從而實現一步步的操做指令。
在後臺設置好應答指令後,系統就能根據應答指令鏈進行處理了。首先咱們須要提供一個進入應答鏈的提示界面,以下所示。
但咱們在菜單選擇應答系統後,系統返回一個文本提示界面,以下所示。
這個界面裏面提示了一些按鍵,包括幾個固定的按鍵和一些業務按鍵,輸入簡單的1~6能夠對選擇進行響應。
咱們看到上面的界面,輸入指令1後,系統進入下一層的應答指令,而後又列出幾個可供輸入的按鍵和內容提示。
當咱們繼續輸入業務按鍵1後,響應的是一個圖文消息,也是關於按鍵的詳細說明。
這個時候,咱們也還能夠輸入*號按鍵,返回上一級菜單的。
輸入0則轉入了客服對話模式,後續您發的任何消息,將會轉發到多客服系統裏面了。
當用戶發送消息後,客服助手就能及時收到消息並處理和客戶的應答了。
爲了更有效管理訂閱用戶以及分組信息,咱們能夠從微信服務器上獲取相關的信息,供咱們瞭解關注的用戶信息,也能夠爲後續的羣發消息作準備。
訂閱用戶的管理以下所示,默承認以經過用戶的地區進行查看,地區根據:國家-省份-城市這樣的級別進行展開。單擊同步數據,能夠把服務器上的用戶數據下載到本地進行更新或者寫入。
訂閱用戶,還能夠根據分組進行查看
雙擊能夠查看訂閱用戶信息,查看訂閱用戶的詳細信息界面以下所示。
建立分組的界面以下所示。
編輯分組信息界面以下所示。
當對分組進行編輯保存後,系統會記住那些修改過的,同步的時候,把本地新增的內容,在服務器上建立分組;把修改的的分組名稱,在服務器上進行修改,而後進行同步列表處理。
多媒體管理是指把本地文件上傳到微信服務器上進行保存,方便信息的發送等操做。微信要求,某些信息,必須是先上傳到服務器上,而後才能使用它的媒體ID進行發送的。
文件成功上傳到服務器後,在列表裏面的「文件上傳標識,就是一串BASE64的編碼數據,同時有一個上傳的時間戳(由於微信服務器只保留了3天的媒體數據,超過時限的數據會被自動刪除。
同時,在列表的上面,有兩個重要的功能:上傳選定的記錄,從新上傳過時的記錄。方便咱們對本身多媒體文件的從新更新操做。
添加界面操做以下所示,其中引入了附件上傳的控件進行文件的操做,很是方便。同時上傳成功的文件,會在列表中列出。
多媒體文件能夠是下面幾種方式:圖片、語音、視頻、縮略圖。
保存後的數據記錄,文件上傳標識和時間戳都是空的,咱們若是要使用,必須把他們上傳到微信的服務器上,而後根據它的MediaId進行信息的發送,上傳選定的記錄操做界面以下所示。
多媒體文件順利上傳後,記錄的信息以下所示。
圖文消息分爲單圖文消息和多圖文消息兩種,單圖文消息以下所示。
多圖文消息以下所示:
和多媒體數據管理同樣,圖文消息也是經過一樣的方式進行管理,先上傳到服務器,而後在進行消息的發送操做,多媒體消息同樣有時間方面的限制要求,具體在咱們的微信門戶平臺裏面管理界面以下所示。
添加圖文消息界面以下所示,保存後,能夠在編輯界面中的「其餘圖文列表」裏面,繼續添加多圖文的消息內容。
在添加界面中,選擇圖文消息的縮略圖,都是經過選定指定的,已經上傳到服務器上圖片或者縮略圖資源才能夠的。
添加後的多圖文列表,能夠進行查看管理。
保存記錄後,而後繼續上傳,上傳後的記錄界面以下所示,成功後返回一個上傳後的服務器標識和時間戳,不然提示錯誤。
爲了方便記錄客戶的輸入和發送信息,咱們在微信門戶管理平臺裏面記錄用戶的輸入數據,具體會話消息管理界面以下所示。
咱們能夠雙擊最近48小時內的任何一條記錄,能夠給關注的客戶進行消息的發送操做,若是消息發送成功,用戶在手機的微信帳號裏面就能收到相關的發送消息了。
爲了對客戶進行相應的營銷操做,有時候咱們須要對指定的羣主或者人員進行消息的羣發,讓客戶常常性的瞭解咱們產品的信息和活動。
因爲羣發消息,除了文本消息,能夠直接編輯發送外,其餘數據,必需要求是上傳到服務器的多媒體文件或者圖文消息內容,所以前面的多媒體管理和圖文消 息管理,就是主要爲了羣發消息的目的引入的。有了上面的多媒體和多圖文信息,咱們從平臺裏面選擇記錄便可進行發送,從而省卻麻煩的連帶工做,實現高效的信 息羣發操做。
羣發的消息,能夠按羣發分組進行查看,也能夠按照消息類型進行查看,使得咱們管理起來根據方便。
添加圖文消息,能夠選擇文本消息、圖文消息、圖片消息等內容,根據不一樣的內容,界面提供不一樣的選擇操做。
消息的羣發類型分爲兩種,一種是根據分組,那麼從平臺裏面選擇對應的分組便可;一種是根據用戶的OpenID進行發送,提供給用戶輸入。主要的操做界面以下所示。
微信公衆號(包括服務號和訂閱號)均可以對菜單進行自定義設置,咱們爲了方便管理,通常先把菜單數據在本地管理維護,須要更新的時候,把它們更新到 微信服務器上就能夠了。本文基於這個方式,介紹個人微信門戶平臺管理系統中菜單提交到微信服務器上的操做。微信門戶應用管理系統,採用基於 MVC+EasyUI的路線,因爲多數域名服務器上都只能支持.NET4.0,因此以MVC3,C#4.0做爲開發基礎,基本上可以部署在任何.NET服 務器上。
微信公衆號的菜單咱們能夠經過網站進行本地的管理,維護好它們之間的層級關係,因爲微信對自定義的菜單要求比較嚴格,如下是微信對自定義菜單的要求:
目前自定義菜單最多包括3個一級菜單,每一個一級菜單最多包含5個二級菜單。一級菜單最多4個漢字,二級菜單最多7個漢字,多出來的部分將會以「...」代替。
所以咱們本身根據約定,不要越界便可,不然提交菜單到服務器,可能會返回一些錯誤,這些細節,咱們在建立本地菜單管理的時候,注意一下就能夠了。我在早期的一篇文章也介紹了自定義菜單的一些內容,須要能夠進行回顧一下《C#開發微信門戶及應用(6)--微信門戶菜單的管理操做》,本篇主要是介紹在個人平臺管理系統裏面,調用前面介紹的菜單接口API,實現菜單提交到服務器的操做。
根據微信的自定義菜單要求,我在管理系統裏面,對微信的菜單幾個基礎性的界面設計以下。
主菜單管理界面以下所示。
添加菜單的界面設計以下所示
微信菜單的修改界面以下所示
微信菜單定義是存儲在數據庫裏面,若是須要提交到微信服務器上並生效,則須要調用微信API接口進行處理,我在頁面的Controller控制器裏增長一個提交到服務器的處理方法。
上面幾個界面,主要就是根據微信菜單的屬性,對菜單進行維護管理,咱們最終的目的是把它們放到服務器上去,供咱們處理客戶的相關事件操做的。
提交菜單的操做,咱們在MVC的View頁面裏面,使用JQuery的Ajax提交便可(前提是咱們在控制器裏面添加相應的處理,後面介紹),界面腳本代碼以下所示。
//綁定提交按鈕的的點擊事件
function BindSubmitEvent() {
$("#btnSubmit").click(function () {
$.messager.confirm("提交菜單確認", "您確認須要提交菜單到微信服務器嗎?", function (action) {
if (action) {
//提交數據
$.ajax({
url: '/Menu/UpdateWeixinMenu',
type: 'post',
dataType: 'json',
success: function (data) {
if (data.Success) {
$.messager.alert("提示", "提交微信菜單成功");
}
else {
$.messager.alert("提示", "提交微信菜單失敗:" + data.ErrorMessage);
}
},
data: ''
});
}
});
});
}
上面紅色的代碼,就是咱們在MVC的控制器裏面定義的方法,咱們只須要經過POST方法,對控制器方法調用,就能實現菜單提交到微信服務器上,至於具體裏面的細節,咱們能夠把它挪到控制器或者更底層進行處理就是了,頁面不須要涉及太多的邏輯就是了。
上面那個Menu控制器的UpdateWeixinMenu的方法代碼以下所示(主要就是根據我前面介紹過的開發模型進行處理就是了)。
/// <summary>
///更新微信菜單
/// </summary>
/// <returns></returns>
public ActionResult UpdateWeixinMenu()
{
string token = base.GetAccessToken();
MenuListJson menuJson = GetWeixinMenu();
IMenuApi menuApi = new MenuApi();
CommonResult result = menuApi.CreateMenu(token, menuJson);
return ToJsonContent(result);
}
上面的幾個方法這裏逐一介紹一下。GetAccessToken主要就是得到當前操做的訪問令牌,這裏的操做能夠用緩存進行緩存,不然頻繁的獲取AccessToken,達到天天指定的次數後,當天就不能再用了。
GetWeixinMenu方法,主要就是爲了方便,對獲取構造微信的自定義菜單數據進行了一個函數封裝,具體代碼以下所示。
///<summary>
/// 生成微信菜單的Json數據
///</summary>
///<returns></returns>
private MenuListJson GetWeixinMenu()
{
MenuListJson menuJson = new MenuListJson();
List<MenuNodeInfo> menuList = BLLFactory<Menu>.Instance.GetTree();
foreach (MenuNodeInfo info in menuList)
{
ButtonType type = (info.Type == "click") ? ButtonType.click : ButtonType.view;
string value = (type == ButtonType.click) ? info.Key : info.Url;
MenuJson weiInfo = new MenuJson(info.Name, type, value);
AddSubMenuButton(weiInfo, info.Children);
menuJson.button.Add(weiInfo);
}
return menuJson;
}
privatevoid AddSubMenuButton(MenuJson menu, List<MenuNodeInfo> menuList)
{
if (menuList.Count >0)
{
menu.sub_button = new List<MenuJson>();
}
foreach (MenuNodeInfo info in menuList)
{
ButtonType type = (info.Type == "click") ? ButtonType.click : ButtonType.view;
string value = (type == ButtonType.click) ? info.Key : info.Url;
MenuJson weiInfo = new MenuJson(info.Name, type, value);
menu.sub_button.Add(weiInfo);
AddSubMenuButton(weiInfo, info.Children);
}
}
上面的代碼,就是把本地存儲的MenuNodeInfo數據,經過遞歸遍歷的方 式,轉換爲微信的自定義菜單實體MenuJson,這樣咱們調用API就很是方便了,這個函數主要負責構造對應的實體信息就是了。至於調用微信API提交 菜單的事情,仍是讓API本身親自處理爲好,他們的代碼以下所示(也就是上面函數的部分代碼)。
IMenuApi menuApi = new MenuApi();
CommonResult result = menuApi.CreateMenu(token, menuJson);
return ToJsonContent(result);
最終的結果是返回一個通用的結果CommonResult,這個結果對象,很是方便腳本的處理,若是有錯誤,則提示錯誤,不然也方便判斷布爾值,也就是上面的頁面代碼腳本。
success: function (data) {
if (data.Success) {
$.messager.alert("提示", "提交微信菜單成功");
}
else {
$.messager.alert("提示", "提交微信菜單失敗:" + data.ErrorMessage);
}
},
經過以上幾部分的代碼,咱們就能夠實現前臺MVC的視圖界面,調用後臺封裝好的微信API,實現菜單的提交處理了。
若是感興趣或者體驗相關的客服應答功能,能夠關注個人微信瞭解下。具體效果能夠關注個人微信門戶:廣州愛奇迪,也能夠掃描下面二維碼進行關注瞭解。
在前面幾篇文章中,逐步從原有微信的API封裝的基礎上過渡到微信應用平臺管理系統裏面,逐步介紹管理系統中的微信數據的界面設計,以及相關的處理 操做過程的邏輯和代碼,但願從更高一個層次,向你們介紹微信的應用開發過程。本篇主要介紹在管理系統中,如何實現微信用戶分組信息的同步操做。
其實微信可以風風火火的緣由,主要就是由於有用戶信息,因此同步並管理好微信帳號的關注用戶數據是很是重要的。有了微信用戶的數據,你 能夠和你任何應用系統對接,實現系統-手機客戶端的數據整合,還能夠對用戶進行營銷管理,如發送用戶感興趣的產品消息、服務消息等,可以很好擴大企業的影 響力和市場行爲。
在較早以前的一篇隨筆《C#開發微信門戶及應用(5)--用戶分組信息管理》, 我曾經介紹了微信分組的各類底層的API封裝操做,裏面主要就是對微信提供API的.NET高級分組,對全部的信息交換,經過實體性進行數據交換,使得我 們調用API來處理微信的各類事務更加方便,從而爲微信應用平臺的管理奠基基礎。其中這篇文章介紹了全部微信分組管理的API封裝過程,用戶分組管理,包 含下面幾個方面的內容:
1)建立分組
2) 查詢全部分組
3) 查詢用戶所在分組
4) 修改分組名
5) 移動用戶分組
針對以上微信分組的操做,咱們能夠在微信的應用管理系統裏面,設計一個模塊,用來管理微信的分組數據,在這個模塊裏面,能夠建立分組,修改分組,查 看分組等基礎操做,還能夠實現同步微信分組的操做,同步操做,主要就是把新增的分組信息添加到微信裏面,修改的分組也在微信中實現修改功能,刪除目前微信 不支持,因此不用管了。最後,咱們能夠在此從微信服務器上,把修改後的數據同步下來,同步的時候爲了不對咱們提交不成功的數據,咱們須要對修改過的記錄 作好標識,這個就是我對整個同步操做的邏輯處理了。
在管理系統裏面,對微信分組的列表管理界面設計以下所示。
建立分組的時候,咱們只須要添加一個分組名稱就能夠了,界面設計也簡單,可是咱們把建立的ID統一設計爲-1,做爲未同步的新增標識。
編輯分組信息界面以下所示。當對分組進行編輯保存後,系統會記住那些修改過的分組就是了。
爲了更好實現分組同步的管理,我把分組的操做代碼,封裝在一個MVC的控制器的方法裏面,頁面代碼經過Ajax調用就能夠實現同步操做了,同步成功,或者失敗,都會提示用戶,讓咱們對其結果進行了解。
同步的時候,把本地新增的內容,在服務器上建立分組;把修改的的分組名稱,在服務器上進行修改,而後進行同步列表處理,同步操做前,列表界面可能以下所示,有新增記錄ID=-1的,也有修改後,記錄修改標誌的。
用戶分組的同步按鈕操做,是調用一個腳本代碼就能夠了,具體代碼以下所示。
//綁定提交按鈕的的點擊事件
function BindSyncDataEvent() {
$("#btnSyncData").click(function () {
$.messager.confirm("提交確認", "您確認須要和微信服務器同步分組信息嗎?", function (action) {
if (action) {
//提交數據
$("#loading").show();
$.ajax({
url: '/Group/SyncGroup',
type: 'post',
dataType: 'json',
success: function (data) {
if (data.Success) {
$("#grid").datagrid("reload");
$.messager.alert("提示", "同步成功");
}
else {
$.messager.alert("提示", "同步失敗:" + data.ErrorMessage);
}
},
data: ''
});
$("#loading").fadeOut(500);
}
});
});
}
其中上面紅色部分就是經過Jquery調用的MVC的控制器方法,具體函數代碼以下所示。
///<summary>
/// 同步服務器的分組信息
///</summary>
///<returns></returns>
public ActionResult SyncGroup()
{
string accessToken = GetAccessToken();
CommonResult result = BLLFactory<Group>.Instance.SyncGroup(accessToken);
return ToJsonContent(result);
}
從上面,咱們沒有看到太多的邏輯,爲了方便我對他們進行了進一步的封裝,把它放到了業務邏輯層進行處理了。具體咱們看看它的代碼邏輯吧,這裏爲了全部的數據庫操做更加快捷和完整,使用了事務的操做,我把相關的代碼貼出來,方便你們瞭解邏輯。
///<summary>
/// 同步服務器的分組信息
///</summary>
///<returns></returns>
public CommonResult SyncGroup(string accessToken)
{
CommonResult result = new CommonResult();
try
{
IUserApi api = new UserApi();
using (DbTransaction trans = baseDal.CreateTransaction())
{
//先把本地標誌groupId = -1未上傳的記錄上傳到服務器,而後進行本地更新
string condition = string.Format("GroupID = '-1' ");
List<GroupInfo> unSubmitList = base.Find(condition);
foreach (GroupInfo info in unSubmitList)
{
GroupJson groupJson = api.CreateGroup(accessToken, info.Name);
if (groupJson != null)
{
info.GroupID = groupJson.id;
baseDal.Update(info, info.ID, trans);
}
}
//把標誌爲修改狀態的記錄,在服務器上修改
condition = string.Format("GroupID >=0 and Modified =1 ");
List<GroupInfo> unModifyList = base.Find(condition);
foreach (GroupInfo info in unModifyList)
{
CommonResult modifyed = api.UpdateGroupName(accessToken, info.GroupID, info.Name);
if (modifyed != null&& modifyed.Success)
{
info.Modified = 0;//重置標誌
baseDal.Update(info, info.ID, trans);
}
}
//刪除具備刪除標誌的分組
//condition = string.Format("GroupID >=100 and Deleted=1 ");
//List<GroupInfo> unDeletedList = base.Find(condition);
//foreach (GroupInfo info in unDeletedList)
//{
// CommonResult deleted = api.DeleteGroup(accessToken, info.GroupID, info.Name);
// if (deleted != null && deleted.Success)
// {
// baseDal.Delete(info.ID, trans);
// }
//}
List<GroupJson> list = api.GetGroupList(accessToken);
foreach (GroupJson info in list)
{
UpdateGroup(info, trans);
}
try
{
trans.Commit();
result.Success = true;
}
catch
{
trans.Rollback();
throw;
}
}
}
catch (Exception ex)
{
result.ErrorMessage = ex.Message;
}
return result;
}
在Jquery同步的時候,咱們爲了不等待時間太久而沒法判斷程序是否正常在工做,最好增長一個忙碌的提示操做,由於咱們使用了Ajax調用,因此咱們能夠統一設置Ajax的忙碌和完成狀態,具體設置代碼以下所示。
//用來統一請求忙碌顯示的設置
$.ajaxSetup({
beforeSend: function () {
$("#loading").show();
},
complete: function () {
$("#loading").hide();
}
});
若是感興趣或者體驗相關的微信功能,能夠關注個人微信瞭解下。具體效果能夠關注個人微信門戶:廣州愛奇迪,也能夠掃描下面二維碼進行關注瞭解。
在前面一系列文章中,咱們能夠看到微信自定義菜單的重要性,能夠說微信公衆號帳號中,菜單是用戶的第一印象,咱們要規劃好這些菜單的內容,佈局等信 息。根據微信菜單的定義,咱們能夠看到,通常菜單主要分爲兩種,一種是普通的Url菜單(類型爲View的菜單),一種是事件菜單(類型爲Click的菜 單),通常狀況下,微信的Url菜單,是沒法得到用戶的任何信息的,但微信用戶信息很是重要,所以也提供了另一種方式(相似重定向的方式)來給咱們使 用,本篇主要介紹這種從新定向的方式菜單的使用,以使咱們可以儘量和用戶進行交互。
微信對自定義菜單的要求:目前自定義菜單最多包括3個一級菜單,每一個一級菜單最多包含5個二級菜單。一級菜單最多4個漢字,二級菜單最多7個漢字,多出來的部分將會以「...」代替。
根據菜單的分類,咱們能夠把它經過圖形進行分類展現:
我對各類微信公衆號進行了解,發現多數帳號採用的都是普通的View類型的菜單連接方式,經過它們連接到本身的微網站上,但也有一些作的好的,如省 立中山圖書館,就能經過重定向的方式,提供一個綁定圖書館用戶和微信OpenID的入口,綁定後,用戶就能夠查看借閱的書籍,而後能夠經過一鍵續借功能實 現圖書的快速續借功能。
對於這種重定向類型的Url菜單事件,微信的說明以下:
若是用戶在微信中(Web微信除外)訪問公衆號的第三方網頁,公衆號開發者能夠經過此接口獲取當前用戶基本信息(包括暱稱、性別、城市、國家)。利用用戶信息,能夠實現體驗優化、用戶來源統計、賬號綁定、用戶身份鑑權等功能。請 注意,「獲取用戶基本信息接口是在用戶和公衆號產生消息交互時,才能根據用戶OpenID獲取用戶基本信息,而網頁受權的方式獲取用戶基本信息,則無需消 息交互,只是用戶進入到公衆號的網頁,就可彈出請求用戶受權的界面,用戶受權後,就可得到其基本信息(此過程甚至不須要用戶已經關注公衆號。)」
上面說了,重定向類型的菜單分爲了兩種,其實他們也僅僅是參數Scope類型的不一樣,其餘部分也仍是同樣的。
爲了展現,咱們在假設用戶單擊菜單的時候,切換到http://www.iqidi.com/testwx.ashx這個頁面,並帶過來當前用戶的OpenID等參數信息
對於scope=snsapi_base方式的連接以下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3d81fc2886d86526&redirect_uri=http%3A%2F%2Fwww.iqidi.com%2Ftestwx.ashx&response_type=code&scope=snsapi_base&state=123#wechat_redirect
而對於scope=snsapi_userinfo方式的連接以下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3d81fc2886d86526&redirect_uri=http%3A%2F%2Fwww.iqidi.com%2Ftestwx.ashx&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect
不過他們給手機客戶端的體驗是不一樣的,第一種能夠平滑切換,可是第二種會彈出一個對話框供用戶確認才能繼續。
爲了演示上面兩種獲取數據的不一樣,我把他們傳過來的code的值,用戶換取OpenID後進行用戶信息的解析,他們二者的結果都是同樣了。具體測試界面以下所示。
其中TestWX.ashx的頁面後臺代碼以下所示:
///<summary>
/// TestWX 的摘要說明
///</summary>
publicclass TestWX : IHttpHandler
{
string appId = ""; //換成你的信息
string appSecret = ""; //換成你的信息
publicvoid ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string content = "";
if (context.Request != null&& context.Request.Url != null)
{
NameValueCollection list = HttpUtility.ParseQueryString(context.Request.Url.Query);
foreach (string key in list.AllKeys)
{
content += string.Format("{0}:{1} \r\n", key, list[key]);
}
}
string code = context.Request.QueryString["code"] ?? "";
if (!string.IsNullOrEmpty(code))
{
IBasicApi api = new BasicApi();
try
{
AppConfig config = new AppConfig();
appId = config.AppConfigGet("AppId");//從配置中獲取微信程序ID
appSecret = config.AppConfigGet("AppSecret");//從配置中獲取微信程序祕鑰
AccessTokenResult result = api.GetAccessToken(appId, appSecret, code);
if (result != null)
{
content += string.Format("openid:{0}\r\n", result.openid);
string token = api.GetAccessToken(appId, appSecret);
IUserApi userApi = new UserApi();
UserJson userDetail = userApi.GetUserDetail(token, result.openid);
if (userDetail != null)
{
content += string.Format("nickname:{0} sex:{1}\r\n", userDetail.nickname, userDetail.sex);
content += string.Format("Location:{0} {1} {2} {3}\r\n", userDetail.country, userDetail.province, userDetail.city, userDetail.language);
content += string.Format("HeadUrl:{0} \r\n", userDetail.headimgurl);
content += string.Format("subscribe:{0},{1}\r\n", (userDetail.subscribe == 1) ? "已訂閱" : "未訂閱", userDetail.subscribe_time.GetDateTime());
}
}
}
catch { }
}
context.Response.Write(content);
}
在上面的代碼中,我主要分爲幾步,一個是打印當前用戶重定向過來的連接的參數信息,代碼以下。
NameValueCollection list = HttpUtility.ParseQueryString(context.Request.Url.Query);
foreach (string key in list.AllKeys)
{
content += string.Format("{0}:{1} \r\n", key, list[key]);
}
而後獲取到Code參數後,經過API接口,獲取AccessTokenResult的數據,這裏面有用戶的OpenID
AccessTokenResult result = api.GetAccessToken(appId, appSecret, code);
當正常調用後,咱們把用戶標識的OpenID進一步進行解析,調用API獲取用戶的詳細信息,具體代碼以下所示。
UserJson userDetail = userApi.GetUserDetail(token, result.openid);
當咱們把用戶的相關信息獲取到了,就能夠作各類用戶信息的展現了,以下代碼所示。
if (userDetail != null)
{
content += string.Format("nickname:{0} sex:{1}\r\n", userDetail.nickname, userDetail.sex);
content += string.Format("Location:{0} {1} {2} {3}\r\n", userDetail.country, userDetail.province, userDetail.city, userDetail.language);
content += string.Format("HeadUrl:{0} \r\n", userDetail.headimgurl);
content += string.Format("subscribe:{0},{1}\r\n", (userDetail.subscribe == 1) ? "已訂閱" : "未訂閱", userDetail.subscribe_time.GetDateTime());
}
這種菜單就是須要指定域名,在微信後臺中進行設置,重定向的連接必須屬於這個域名之中,不然不會轉到你但願的連接。
這個方式,讓咱們的微信應用程序後臺能夠得到用戶的標識、用戶詳細信息等,咱們就能夠用來綁定和用戶相關的業務信息了,如上面提到的圖書館借閱信 息,送水客戶的信息,客戶的積分信息,或者能夠和後臺帳號進行關聯實現更加複雜的應用等。用戶的身份信息如此重要,若是結合到咱們的CRM系統、業務管理 系統,就能夠發揮用戶信息應用的做用了。
以上就是我對這個類型菜單連接的應用瞭解,具體還須要進一步深化其應用,但願和你們共同探討這方面的應用場景。
咱們知道,微信最開始就是作語音聊天而使得其更加流行的,所以語音的識別處理天然也就成爲微信交流的一個重要途徑,微信的開發接口,也提供了對語音 的消息請求處理。本文主要介紹如何利用語音的識別,對C#開發的微信門戶應用的整個事件鏈的處理操做,使得在咱們的微信帳號裏面,更加方便和多元化對用戶 的輸入進行處理。
微信的API這麼定義語音的識別的:開通語音識別功能,用戶每次發送語音給公衆號時,微信會在推送的語音消息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>
<MsgId>1234567890123456</MsgId>
</xml>
參數 |
描述 |
ToUserName |
開發者微信號 |
FromUserName |
發送方賬號(一個OpenID) |
CreateTime |
消息建立時間 (整型) |
MsgType |
語音爲voice |
MediaId |
語音消息媒體id,能夠調用多媒體文件下載接口拉取數據。 |
Format |
語音格式,如amr,speex等 |
MsgID |
消息id,64位整型 |
根據以上微信接口的定義,咱們能夠定義一個實體類來對消息的傳遞進行處理,以下所示。
///<summary>
/// 接收的語音消息
///</summary>
[System.Xml.Serialization.XmlRoot(ElementName = "xml")]
publicclass RequestVoice : BaseMessage
{
public RequestVoice()
{
this.MsgType = RequestMsgType.Voice.ToString().ToLower();
}
///<summary>
/// 語音格式,如amr,speex等
///</summary>
publicstring Format { get; set; }
///<summary>
/// 語音消息媒體id,能夠調用多媒體文件下載接口拉取數據。
///</summary>
publicstring MediaId { get; set; }
///<summary>
/// 消息ID
///</summary>
public Int64 MsgId { get; set; }
///<summary>
/// 語音識別結果,UTF8編碼
///</summary>
publicstringRecognition { get; set; }
}
咱們看到,這裏咱們最感興趣的是語音的識別結果,也就是Recognition的字段,這個就是微信服務器自動根據用戶的語音轉換過來的內容,我測試過,識別率仍是很是高的。
這個實體類,在整個微信應用的消息傳遞中的關係以下所示:
明確了上面的語音對象實體,咱們就能夠看看它們之間是如何處理的。
微信消息的處理邏輯以下圖所示。
其中咱們來看看語音的處理操做,個人代碼處理邏輯以下所示。
///<summary>
/// 對語音請求信息進行處理
///</summary>
///<param name="info">語音請求信息實體</param>
///<returns></returns>
publicstring HandleVoice(Entity.RequestVoice info)
{
string xml = "";
// 開通語音識別功能,用戶每次發送語音給公衆號時,
// 微信會在推送的語音消息XML數據包中,增長一個Recongnition字段。
if (!string.IsNullOrEmpty(info.Recognition))
{
TextDispatch dispatch = new TextDispatch();
xml = dispatch.HandleVoiceText(info, info.Recognition);
}
else
{
xml = "";
}
return xml;
}
在這裏,我先看看,是否得到了微信的語音識別結果,若是得到,那麼這個時候,就是和處理用戶文本輸入的操做差很少了,所以把它轉給TextDispatch的處理類進行處理。
其中這裏面的處理邏輯以下所示。
首先我根據識別結果,尋找是否用戶讀出了微信門戶的菜單名稱,若是根據語音結果找到對應的菜單記錄,那麼咱們執行菜單事件(若是是URL的View 類型菜單,咱們沒辦法重定向到指定的連接,所以給出一個連接文本提示,給用戶單擊進入;若是沒有找到菜單記錄,那麼咱們就把語音識別結果做爲通常的事件進 行處理,若是事件邏輯沒有處理,那麼咱們最後給出一個默認的語音應答提示結果就能夠了。
具體的處理代碼以下所示。
///<summary>
/// 若是用戶用語音讀出菜單的內容,那麼咱們應該先根據菜單對應的事件觸發,最後再交給普通事件處理
///</summary>
///<param name="info"></param>
///<returns></returns>
publicstring HandleVoiceText(BaseMessage info, string voiceText)
{
string xml = "";
MenuInfo menuInfo = BLLFactory<Menu>.Instance.FindByName(voiceText);
if (menuInfo != null)
{
#region 若是找到菜單對象的處理
if (menuInfo.Type == "click")
{
//模擬單擊事件
RequestEventClick eventInfo = new RequestEventClick();
eventInfo.CreateTime = info.CreateTime;
eventInfo.EventKey = menuInfo.Key;
eventInfo.FromUserName = info.FromUserName;
eventInfo.ToUserName = info.ToUserName;
xml = base.DealEvent(eventInfo, eventInfo.EventKey);
}
else
{
//因爲沒法自動切換到鏈接,
//轉換爲鏈接文本供用戶進入
string content = string.Format("請單擊連接進入<a href=\"{0}\">{1}</a> ", menuInfo.Url, menuInfo.Name);
ResponseText textInfo = new ResponseText(info);
textInfo.Content = content;
xml = textInfo.ToXml();
}
#endregion
}
else
{
//交給事件機制處理
if (string.IsNullOrEmpty(xml))
{
xml = HandleText(info, voiceText);
}
}
//最後若是沒有處理到,那麼提示用戶的語音內容
if (string.IsNullOrEmpty(xml))
{
ResponseText textInfo = new ResponseText(info);
textInfo.Content = string.Format("很是抱歉,您輸入的語音內容沒有找到對應的處理方式。您的語音內容爲:{0}", voiceText);
xml = textInfo.ToXml();
}
return xml;
}
微信門戶測試界面效果以下所示。
爲了方便對客戶會話的記錄,個人微信門戶後臺,會記錄用戶的語音輸入內容,以下所示。
固然,微信後臺的管理界面,也可以查到相應的語音記錄,界面以下所示。
以上就是我對微信語音的消息定義和事件處理的邏輯,其實語音是一個重要的輸入,若是正確的識別內容,比手工輸入的效果更好,給用戶提供另一種高效的輸入和事件處理操做。
這樣的處理模式,可以使得咱們整個微信門戶框架,無論是對於用戶的語音輸入,仍是文本輸入,仍是菜單事件的處理,均可以融爲一體,實現更加完美的銜接。
本文繼續上一篇《C#開發微信門戶及應用(12)-使用語音處理》, 繼續介紹微信的相關應用。咱們知道,地理位置信息能夠用來作不少相關的應用,除了咱們能夠知道用戶所在的位置,還能夠關聯出一些地理位置的應用,如天氣, 熱映影片,附近景點,附近影院,交通事件等等,反正全部和地理位置相關的信息,咱們均可以根據須要作一些擴展應用。本文主要介紹利用地理位置信息,如何構 建使用這些應用的操做。
在使用前,咱們先來看看微信的接口,爲咱們定義了那些關於與地理位置的信息。其實地理位置的信息,微信分爲了兩個方面,一個是接收用戶的地理位置請求,一個是用戶容許上報地理位置操做,定時發送的地理位置信息。
本文主要介紹基於第一種,用戶上報地理位置後,如何處理的相關應用。
地理位置的上報操做,就是在輸入的地方,選擇+號進行添加地理位置,而後選擇當前或者指定的地理位置地圖,具體操做以下所示。
地理位置消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1351776360</CreateTime>
<MsgType><![CDATA[location]]></MsgType>
<Location_X>23.134521</Location_X>
<Location_Y>113.358803</Location_Y>
<Scale>20</Scale>
<Label><![CDATA[位置信息]]></Label>
<MsgId>1234567890123456</MsgId>
</xml>
參數 |
描述 |
ToUserName |
開發者微信號 |
FromUserName |
發送方賬號(一個OpenID) |
CreateTime |
消息建立時間 (整型) |
MsgType |
location |
Location_X |
地理位置維度 |
Location_Y |
地理位置經度 |
Scale |
地圖縮放大小 |
Label |
地理位置信息 |
MsgId |
消息id,64位整型 |
有了上面的地理位置信息,咱們在程序裏面,須要在消息傳遞過來的時候,定義一個實體類信息,承載相關的地理位置信息,方便咱們進一步的處理操做。
///<summary>
/// 接收的地理位置消息
///</summary>
[System.Xml.Serialization.XmlRoot(ElementName = "xml")]
publicclass RequestLocation : BaseMessage
{
public RequestLocation()
{
this.MsgType = RequestMsgType.Location.ToString().ToLower();
}
///<summary>
/// 消息ID
///</summary>
public Int64 MsgId { get; set; }
///<summary>
/// 地理位置維度
///</summary>
publicdecimal Location_X { get; set; }
///<summary>
/// 地理位置經度
///</summary>
publicdecimal Location_Y { get; set; }
///<summary>
/// 地圖縮放大小
///</summary>
publicint Scale { get; set; }
///<summary>
/// 地理位置信息
///</summary>
publicstring Label { get; set; }
}
有了這些信息,咱們在信息傳遞的時候,就能很好獲得用戶的相關數據了。
若是僅僅爲了返回給用戶,告訴用戶目前的地理位置信息,能夠用下面的操做就能夠了。
///<summary>
/// 對地理位置請求信息進行處理
///</summary>
///<param name="info">地理位置請求信息實體</param>
///<returns></returns>
publicstring HandleLocation(Entity.RequestLocation info)
{
string xml = "";
ResponseText txtinfo = new ResponseText(info);
txtinfo.Content = string.Format("您發送的地理位置是:{0}", info.Label);
xml = txtinfo.ToXml();
return xml;
}
不過上面的信息,顯然不符合咱們擴展應用的要求,所以咱們進一步進行完善裏面對地理位置信息處理的操做。咱們進一步把關於地理位置的操做,放到事件處理模塊裏面進行處理,處理代碼以下所示。
///<summary>
/// 對地理位置請求信息進行處理
///</summary>
///<param name="info">地理位置請求信息實體</param>
///<returns></returns>
publicstring HandleLocation(Entity.RequestLocation info)
{
string xml = "";
EventDispatch dispatch = new EventDispatch();
xml = dispatch.DealLocation(info, info.Label, info.Location_Y, info.Location_X);
return xml;
}
在處理的時候,咱們須要先保存用戶的地理位置信息,把它存儲到用戶的上下文記錄裏面。這樣咱們在處理指令的時候,把它獲取到,而後傳遞給相關的方法就能夠實現地理位置的擴展應用了。
//保存經緯度
string location = string.Format("{0},{1}", lat, lon);
bool result = BLLFactory<UserSet>.Instance.UpdateUserInput(info.FromUserName, location);
首先對用戶地理位置的請求,我根據數據庫配置給出了一個用戶選擇的指令提示,以下所示。
爲了對地理位置請求的處理,我定義了一個用於處理這個操做的指令操做
這樣整個地理位置的指令操做,就在應答鏈裏面進行很好的跳轉管理了。那麼爲了實現天氣、放映影片、附近影院、旅遊線路、交通事件等方面的擴展應用,咱們應該如何操做呢?
咱們知道,百度或者騰訊都提供了一些開放平臺,給咱們進行各類方式的使用。那麼咱們這裏以使用百度LBS平臺應用來構建一些模塊。
這上面都有不少相關的接口供使用,咱們能夠根據其提供的數據格式進行封裝,而後進行調用處理就能夠了。
剛纔說了,我配置了一些指令,用來構建相關的應用,指令的最後是一些事件代碼的定義,咱們對這些末端的事件代碼進行處理,就能夠給用戶返回相關的信息了,整體的操做代碼以下所示。
///<summary>
/// 其餘插件操做,如天氣,景點、電影影訊、交通等
///</summary>
///<param name="info">基礎消息</param>
///<param name="eventKey">事件標識</param>
///<returns></returns>
publicstring DealPlugin(BaseMessage info, string eventKey)
{
//LogTextHelper.Info(eventKey);
string userInput = BLLFactory<UserSet>.Instance.GetUserInput(info.FromUserName);
string xml = "";
switch (eventKey)
{
case"event-void-wether":
xml = new WeatherPlugin().Response(info, userInput);
break;
case"event-void-movie":
xml = new MoviePlugin().Response(info, userInput);
break;
case"event-void-cinema":
xml = new CinemaPlugin().Response(info, userInput);
break;
case"event-void-travel":
xml = new TravelPlugin().Response(info, userInput);
break;
case"event-void-traffic":
xml = new TrafficEventPlugin().Response(info, userInput);
break;
default:
break;
}
return xml;
}
這裏以天氣爲例,說明該如何調用百度的接口的,首先咱們封裝一下相關的接口調用。
///<summary>
/// 根據參數調用百度接口,獲取相關的結果數據
///</summary>
///<param name="location">地理位置</param>
///<param name="ak">API調用鍵</param>
///<returns></returns>
public BaiduWeatherResult Execute(string location, string ak)
{
location = HttpUtility.UrlEncode(location);
var url = string.Format("http://api.map.baidu.com/telematics/v3/weather?location={0}&output=json&ak={1}", location, ak);
BaiduWeatherResult result = BaiduJsonHelper<BaiduWeatherResult>.ConvertJson(url);
return result;
}
其中的BaiduWeatherResult 是我根據調用返回的Json結果,構建的一個實體類,用來存儲返回的內容。具體代碼以下所示。
///<summary>
/// 天氣請求結果Json對象
///</summary>
publicclass BaiduWeatherResult : BaiduResult
{
///<summary>
/// 天氣預報信息
///</summary>
public List<BaiduWeatherData> results = new List<BaiduWeatherData>();
}
///<summary>
/// 城市的天氣信息
///</summary>
publicclass BaiduWeatherData
{
///<summary>
/// 當前城市
///</summary>
publicstring currentCity { get; set; }
///<summary>
/// 天氣預報信息
///</summary>
public List<BaiduWeatherJson> weather_data = new List<BaiduWeatherJson>();
}
///<summary>
/// 天氣預報的單條記錄Json信息
///</summary>
publicclass BaiduWeatherJson
{
///<summary>
/// 天氣預報時間
///</summary>
publicstring date { get; set; }
///<summary>
/// 白天的天氣預報圖片url
///</summary>
publicstring dayPictureUrl { get; set; }
///<summary>
/// 晚上的天氣預報圖片url
///</summary>
publicstring nightPictureUrl { get; set; }
///<summary>
/// 天氣情況
///</summary>
publicstring weather { get; set; }
///<summary>
/// 風力
///</summary>
publicstring wind { get; set; }
///<summary>
/// 溫度
///</summary>
publicstring temperature { get; set; }
}
爲了構建返回給客戶的圖文數據,咱們須要構建一個News對象,而後生成XML數據返回給服務器進行處理便可。
///<summary>
/// 響應用戶請求,並返回相應的XML數據
///</summary>
///<param name="info">微信基礎信息</param>
///<param name="location">地理位置:經緯度座標或者地名</param>
///<returns></returns>
publicstring Response(BaseMessage info, string location)
{
string xml = "";
//"廣州" 或者 "116.305145,39.982368"
if (!string.IsNullOrEmpty(location))
{
BaiduWeatherResult result = Execute(location, baiduAK);
if (result != null&& result.results.Count >0)
{
BaiduWeatherData data = result.results[0];
if (data != null)
{
ArticleEntity first = new ArticleEntity();
first.Title = string.Format("{0} 天氣預報", data.currentCity);
ResponseNews news = new ResponseNews(info);
news.Articles.Add(first);
int i = 0;
foreach (BaiduWeatherJson json in data.weather_data)
{
ArticleEntity article = new ArticleEntity();
article.Title = string.Format("{0}\n{1} {2} {3}", json.date, json.weather, json.wind, json.temperature);
if (i++ == 0)
{
article.PicUrl = IsDayTime() ? json.dayPictureUrl : json.nightPictureUrl;
}
else
{
article.PicUrl = json.dayPictureUrl;
}
news.Articles.Add(article);
}
xml = news.ToXml();
}
}
}
return xml;
}
這樣就很好實現了總體的功能了,具體界面功能能夠訪問個人微信(廣州愛奇迪)進行了解,下面是功能截圖供參考。
我曾經在系列文章中的《C#開發微信門戶及應用(11)--微信菜單的多種表現方式介紹》 中介紹了微信菜單裏面的重定向操做,經過這個重定向操做,咱們能夠獲取一個code值,而後獲取用戶的openID,進而就能獲取到更多的用戶信息,這個 在會員信息的場景裏面用的不少,本篇介紹在網站中迅速配置這樣的菜單連接,並介紹如何在後臺獲取相關的用戶信息,實現頁面數據個性化的展示操做。
咱們知道,微信的自定義菜單分爲兩大類,分別對應Click類型和View類型的,而重定向屬於View類型的一種,以下所示。
微信重定向的菜單,就是經過傳入一個地址參數,讓微信服務器進行跳轉,它的主要規則以下所示。
對於scope=snsapi_base方式的連接以下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3d81fc2886d86526&redirect_uri=http%3A%2F%2Fwww.iqidi.com%2Ftestwx.ashx&response_type=code&scope=snsapi_base&state=123#wechat_redirect
而對於scope=snsapi_userinfo方式的連接以下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3d81fc2886d86526&redirect_uri=http%3A%2F%2Fwww.iqidi.com%2Ftestwx.ashx&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect
這兩個菜單連接主要就是對咱們給定的連接地址進行UrlEncode處理,而後把它賦值給參數redirect_uri實現的。
因爲連接地址比較長,若是每次須要在配置菜單的時候,都複製過來修改,很是不方便,咱們能夠在自定義菜單的配置界面裏面,增長一個按鈕功能,對內容進行處理,以便實現咱們須要的地址轉換,個人門戶應用平臺對自定義菜單的操做就是基於這個思路實現。
默認咱們只須要填寫一個須要重定向的url地址就能夠了,以下所示。
若是須要配置成重定向的菜單連接地址,那麼調用【轉換重定向菜單】按鈕操做,使用腳本函數進行轉換就能夠了,轉換後的結果以下所示。
原來就是利用後臺的javascript實現參數的URL轉碼,還須要獲取後臺的AppId,這樣才能構形成完整的地址鏈接。
前面說了,第一是須要實現URL轉碼,第二是獲取後臺的AppId,而後生成一個完整的URL就能夠了。爲了不你們的重複研究,我把這部分代碼貼出來一塊兒學習下。
在使用前,咱們還須要注意一個問題,就是重定向到指定頁面後,這個頁面會帶有一個code的參數,這個參數很是重要,咱們須要獲取出來,固然也是經過javascript來獲取對應的code參數了。
這個邏輯能夠用一個腳本函數來實現,以下所示
function getUrlVars(){
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
定義了這個函數後,咱們在重定向的頁面裏面,能夠獲取code參數的操做以下所示。
var code = getUrlVars()["code"];
先放下這些,咱們先來討論如何把連接地址轉換爲須要的連接地址操做。
咱們爲了實現連接地址的互相轉換(爲了方便),咱們能夠判斷連接地址是否含有qq的域名就能夠了。
if (url.indexOf("https://open.weixin.qq.com/connect/oauth2/authorize?") == 0) {
var redirect_uri = getUrlVars(url)["redirect_uri"];
if (redirect_uri != "") {
var newUrl = decodeURIComponent(redirect_uri);
$("#" + ctrlName).val(newUrl);
}
}
而若是是咱們輸入的正常連接,那麼就應該把它轉換爲重定向的連接地址,以下所示。
else {
var newUrl = encodeURIComponent(url);
var reNewUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=@ViewBag.appid&redirect_uri=" + newUrl + "&response_type=code&scope=snsapi_base&state=123#wechat_redirect";
$("#" + ctrlName).val(reNewUrl);
}
其中重定向連接須要帶有一個當前微信開發用戶的appId,這個不是固定的,是不一樣的開發人員都不同的東西,這裏使用了MVC的動態對象進行綁定:@ViewBag.appid。
在對應的MenuController控制器裏面,給它賦值就能夠了。
///<summary>
/// 默認的視圖控制方法
///</summary>
///<returns></returns>
publicoverride ActionResult Index()
{
ViewBag.appid = GetAppId();
return View();
}
這樣配置後的重定向菜單地址列表就以下所示了,咱們打開對應的記錄詳細頁面,能夠經過頁面裏面的功能按鈕,隨時對重定向菜單的地址進行轉換,方便了解詳細的連接內容。
配置了上面的連接地址後,咱們須要在網站裏面增長這樣的一個頁面進行處理用戶的信息,通常狀況下,咱們多是爲了方便用戶查看本身的微信基礎信息, 也爲了給用戶綁定用戶我的數據使用的用途的,如用戶能夠綁定手機、Email郵箱等操做,還能夠綁定和業務系統相關的用戶名。這樣用戶就能夠快速註冊會員 或者和後臺的系統進行關聯了。
我設計的兩個用戶信息展現界面以下所示。
這兩個界面主要使用了Jquery Mobile的相關內容,對界面進行了處理,整個模塊結合了短信驗證碼的方式,對用戶的手機進行驗證處理,這樣可以更高效的實現信息準確的綁定操做,當 然,還能夠結合外部系統,綁定用戶的帳號密碼,這樣用戶能夠在微信進入微網站平臺進行購物、數據維護、業務管理等操做了,其實一旦綁定外部系統的ID,也 就是提供了一個快速進行外部系統的入口了。
具體的內容在下一篇繼續介紹了。
前面介紹了不少篇關於使用C#開發微信門戶及應用的文章,基本上把當時微信能作的接口都封裝差很少了,微信框架也積累了很多模塊和用戶,最近發現微 信公衆平臺增長了很多內容,特別是在自定義菜單裏面增長了掃一掃、發圖片、發地理位置功能,這幾個功能模塊很重要,想一想之前想在微信公衆號裏面增長一個掃 描二維碼的功能,都作不了,如今能夠了,還能夠拍照上傳等功能,本文主要介紹基於我前面的框架系列文章,進一步介紹如何集成和使用這些新增功能。
用戶點擊按鈕後,微信客戶端將調起掃一掃工具,完成掃碼操做後顯示掃描結果(若是是URL,將進入URL),且會將掃碼的結果傳給開發者,開發者能夠下發消息。
用戶點擊按鈕後,微信客戶端將調起掃一掃工具,完成掃碼操做後,將掃碼的結果傳給開發者,同時收起掃一掃工具,而後彈出「消息接收中」提示框,隨後可能會收到開發者下發的消息。
用戶點擊按鈕後,微信客戶端將調起系統相機,完成拍照操做後,將拍攝的相片發送給開發者,並推送事件給開發者,同時收起系統相機,隨後可能會收到開發者下發的消息。
用戶點擊按鈕後,微信客戶端將彈出選擇器供用戶選擇「拍照」或者「從手機相冊選擇」。用戶選擇後即走其餘兩種流程。
用戶點擊按鈕後,微信客戶端將調起微信相冊,完成選擇操做後,將選擇的相片發送給開發者的服務器,並推送事件給開發者,同時收起相冊,隨後可能會收到開發者下發的消息。
用戶點擊按鈕後,微信客戶端將調起地理位置選擇工具,完成選擇操做後,將選擇的地理位置發送給開發者的服務器,同時收起位置選擇工具,隨後可能會收到開發者下發的消息。
但請注意,以上新增能力,均僅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用戶,舊版本微信用戶點擊後將沒有迴應,開發者也不能正常接收到事件推送。
微信不只增長了這些功能模塊的支持,還考慮到咱們開發人員的方便,增長了一個叫作「menutest"的公衆號,方便咱們測試。咱們在公衆號搜索「menutest",而後關注它便可進行測試幾個新增功能了。
「menutest"的公衆號名稱是」自定義菜單拓展測試「,我關注它並進行了測試,二維碼、圖片、地理位置都很OK,自己可以響應這些事件,而且圖片、地理位置自身還能出現一個對應的事件,以下所示。
圖片發送能夠分爲拍照、拍照和相冊、微信相冊三類,感受後面兩個有點相似,但有這些功能都很不錯的。
前面說了,微信提供這些功能,能夠在菜單裏面進行集成,也就是菜單的類型由原來CLICK/VIEW兩種,變爲如今8種類型,增長2個掃碼操做、3種圖片操做、1種地理位置操做。
所以把菜單的枚舉類型擴展一下,以下所示。
///<summary>
/// 菜單按鈕類型
///</summary>
publicenum ButtonType
{
///<summary>
/// 點擊
///</summary>
click,
///<summary>
/// Url
///</summary>
view,
///<summary>
/// 掃碼推事件的事件推送
///</summary>
scancode_push,
///<summary>
/// 掃碼推事件且彈出「消息接收中」提示框的事件推送
///</summary>
scancode_waitmsg,
///<summary>
/// 彈出系統拍照發圖的事件推送
///</summary>
pic_sysphoto,
///<summary>
/// 彈出拍照或者相冊發圖的事件推送
///</summary>
pic_photo_or_album,
///<summary>
/// 彈出微信相冊發圖器的事件推送
///</summary>
pic_weixin,
///<summary>
/// 彈出地理位置選擇器的事件推送
///</summary>
location_select
}
而後在Winform裏面調用建立菜單操做代碼以下所示:
privatevoid btnCreateMenu_Click(object sender, EventArgs e)
{
MenuJson productInfo = new MenuJson("新功能測試", new MenuJson[] {
new MenuJson("掃碼推事件", ButtonType.scancode_push, "scancode_push")
,new MenuJson("系統拍照發圖", ButtonType.pic_sysphoto, "pic_sysphoto")
, new MenuJson("拍照相冊發圖", ButtonType.pic_photo_or_album, "pic_photo_or_album")
, new MenuJson("微信相冊發圖", ButtonType.pic_weixin, "pic_weixin")
, new MenuJson("地理位置選擇", ButtonType.location_select, "location_select")
});
MenuJson frameworkInfo = new MenuJson("框架產品", new MenuJson[] {
new MenuJson("Win開發框架", ButtonType.click, "win"),
new MenuJson("WCF開發框架", ButtonType.click, "wcf"),
new MenuJson("混合式框架", ButtonType.click, "mix"),
new MenuJson("Web開發框架", ButtonType.click, "web")
,new MenuJson("代碼生成工具", ButtonType.click, "database2sharp")
});
MenuJson relatedInfo = new MenuJson("相關連接", new MenuJson[] {
new MenuJson("公司介紹", ButtonType.click, "event_company"),
new MenuJson("官方網站", ButtonType.view, "http://www.iqidi.com"),
new MenuJson("聯繫咱們", ButtonType.click, "event_contact"),
new MenuJson("應答系統", ButtonType.click, "set-1"),
new MenuJson("人工客服", ButtonType.click, "event_customservice")
});
MenuListJson menuJson = new MenuListJson();
menuJson.button.AddRange(new MenuJson[] { productInfo, frameworkInfo, relatedInfo });
if (MessageUtil.ShowYesNoAndWarning("您確認要建立菜單嗎") == System.Windows.Forms.DialogResult.Yes)
{
IMenuApi menuBLL = new MenuApi();
CommonResult result = menuBLL.CreateMenu(token, menuJson);
Console.WriteLine("建立菜單:" + (result.Success ? "成功" : "失敗:" + result.ErrorMessage));
}
}
固然,通常狀況下咱們都是在Web後臺系統進行的,維護菜單都是在本身微信平臺上進行菜單管理,而後一次性提交到微信服務器便可。
而在Web後臺,只須要把數據庫的數據變化爲Json數據提交便可,操做和上面的相似。
///<summary>
///更新微信菜單
///</summary>
///<returns></returns>
public ActionResult UpdateWeixinMenu()
{
string token = base.GetAccessToken();
MenuListJson menuJson = GetWeixinMenu();
IMenuApi menuApi = new MenuApi();
CommonResult result = menuApi.CreateMenu(token, menuJson);
return ToJsonContent(result);
}
前面講了,有了最新的功能,咱們就能夠實現掃一掃功能,從而能夠掃描條形碼,二維碼的功能。有了條形碼、二維碼的快速和識別,咱們就能開發一些如條碼查詢、商品處理等功能了。
這裏咱們介紹如何在個人微信開發框架裏面整合這個掃一掃的功能處理操做。
前面已經增長了一些新功能的測試菜單,咱們要作的就是響應這些事件處理,而後對他們進行應答處理就能夠了。
下面是根據事件進行的一些API跳轉處理,咱們同時定義了幾個相關的實體類用來處理他們的信息,如RequestEventScancodePush、RequestEventScancodeWaitmsg、RequestEventPicSysphoto等等。
RequestEventScancodeWaitmsg實體類的代碼以下所示,其餘的相似處理。
///<summary>
/// 掃碼推事件且彈出「消息接收中」提示框的事件推送
///</summary>
[System.Xml.Serialization.XmlRoot(ElementName = "xml")]
publicclass RequestEventScancodeWaitmsg : BaseEvent
{
public RequestEventScancodeWaitmsg()
{
this.MsgType = RequestMsgType.Event.ToString().ToLower();
this.Event = RequestEvent.scancode_waitmsg.ToString();
this.ScanCodeInfo = new ScanCodeInfo();
}
///<summary>
/// 事件KEY值,由開發者在建立菜單時設定
///</summary>
publicstring EventKey { get; set; }
///<summary>
/// 掃描信息
///</summary>
public ScanCodeInfo ScanCodeInfo { get; set; }
}
而根據實體類強類型的處理接口流轉操做以下所示。
case RequestEvent.scancode_push:
{
//掃碼推事件的事件推送
RequestEventScancodePush info = XmlConvertor.XmlToObject(postStr, typeof(RequestEventScancodePush)) as RequestEventScancodePush;
if (info != null)
{
responseContent = actionBLL.HandleEventScancodePush(info);
}
}
break;
case RequestEvent.scancode_waitmsg:
{
//掃碼推事件且彈出「消息接收中」提示框的事件推送
RequestEventScancodeWaitmsg info = XmlConvertor.XmlToObject(postStr, typeof(RequestEventScancodeWaitmsg)) as RequestEventScancodeWaitmsg;
if (info != null)
{
responseContent = actionBLL.HandleEventScancodeWaitmsg(info);
}
}
break;
case RequestEvent.pic_sysphoto:
{
//彈出系統拍照發圖的事件推送
RequestEventPicSysphoto info = XmlConvertor.XmlToObject(postStr, typeof(RequestEventPicSysphoto)) as RequestEventPicSysphoto;
if (info != null)
{
responseContent = actionBLL.HandleEventPicSysphoto(info);
}
}
break;
..................
處理掃描結果並返回的最終代碼以下所示。
///<summary>
/// 掃碼推事件且彈出「消息接收中」提示框的事件推送的處理
///</summary>
///<param name="info">掃描信息</param>
///<returns></returns>
publicstring HandleEventScancodeWaitmsg(RequestEventScancodeWaitmsg info)
{
ResponseText response = new ResponseText(info);
response.Content = string.Format("您的信息爲:{0},能夠結合後臺進行數據查詢。", info.ScanCodeInfo.ScanResult);
return response.ToXml();
}
最後咱們測試掃描一個條形碼,能夠看到返回的結果界面操做以下所示。
前面介紹了一些新菜單功能模塊的集成,我我的對這種掃一掃菜單功能很是讚揚,這也是微信逐步整合更多硬件資源和接口處理的趨向,不過在集成使用的時 候,發現公衆號偶爾出現閃退的狀況,還有就是這些新功能雖而後臺可以實現數據的處理和接收,可是有一些不能返回應答消息,很鬱悶。也許隨着版本研發的加 快,這些功能很快獲得完善和解決。
另外微信開放平臺也投入使用了,好些認證也是300元一年,不過暫時沒有其應用的場景,我只是用到了它來獲取微信帳號的unionid的功能,其餘功能慢慢了解吧。
還有就是微信的企業號也已經出來了,並且我也已經申請認證經過,它的開發用戶的API也有很多,有空繼續研究並整合到微信開發框架裏面吧。
在本系列隨筆的前面,主要就是介紹微信公衆號的門戶應用開發,最近把整個微信框架進行了擴展補充,增長了最新的企業號的API封裝和開發,後續主要介紹如何利用C#進行微信企業號的開發工做,本篇做爲微信企業號的開發的起步篇,介紹微信企業號的配置和使用。
企業號是繼公衆號、訂閱號的另一種微信類型,它主要是面對企業的。企業號是微信爲企業客戶提供的移動應用入口。能夠幫助企業創建員工、上下游供應 鏈與企業 IT 系統間的鏈接。利用 企業號 ,企業或第三方合做夥伴能夠幫助企業快速、低成本的實現高質量的移動輕應用,實現生產、管理、協做、運營的 移動化 。
我的以爲企業號最大的亮點是能夠不限數量的消息發送,也就是能夠在企業員工之間暢通交流。相對於公衆號和訂閱號,發送消息的謹慎程度,微信企業號可 謂給人眼前一亮的感受。不過微信企業號是須要內部創建好通信錄,關注者須要匹配通信錄的微信號、郵箱、電話號碼任一個經過才能夠關注,也就是能夠防止其餘 外來人員的自由關注了,另外若是爲了安全考慮,還能夠設置二次驗證,也就是一個審覈過程。
企業號的認證和公衆號同樣,須要提供相關的企業資質文件,而且認證每一年都要收取費用,不然可能有人員和功能的一些限制。以爲微信真是想着方法賺錢, 目前已有的收費模式有,訂閱號、公衆號、企業號、開放平臺,好像都有認證收費的了,並且微信小店也還須要收2萬的押金,一切都是錢呀。
好了,其餘很少說,微信的註冊地址是:https://qy.weixin.qq.com,一個郵箱不能同時註冊微信公衆號和微信企業號。
對於企業開通企業號並開始使用須要四步
1) 企業到微信官網( http://qy.weixin.qq.com )申請開通;
2) 開通後,企業在企業號管理後臺導入成員,發佈二維碼;
3) 企業調用企業號 api 與企業自有系統對接開發;
4) 員工關注,收到微信信息,在微信中與企業交互
註冊好企業號,就能夠經過微信掃一掃,掃描企業二維碼進行登陸了,掃描的時候,須要微信進行確認,才能夠繼續輸入密碼進行登陸,操做界面以下所示(左邊是手機截圖,右邊是網頁截圖)。
登陸後咱們就能夠看到對應的電腦端的管理界面了。
若是開發過微信公衆號,那麼咱們就知道,若是須要在微信服務器和網站服務器之間創建鏈接關係,實現消息的轉發和處理,那麼就應該設置一個回調模式,須要配置好相關的參數。而後在本身 網站服務器裏面創建一個處理微信服務器消息的入口。
進入配置後,咱們須要修改相關的URL、Token、EncodingAESKey等參數,主要是URL,這個就是和公衆號的入口處理同樣的,須要咱們發佈到網站服務器上的處理入口。
Token和AESKey能夠根據提示動態生成一個便可,AESKey好像必須是23位的,因此這個通常是讓它本身生成的,這個主要用來加密解密使用的。
URL、Token、EncodingAESKey三個參數說明。
1)URL是企業應用接收企業號推送請求的訪問協議和地址,支持http或https協議。
2)Token可由企業任意填寫,用於生成簽名。
3)EncodingAESKey用於消息體的加密,是AES密鑰的Base64編碼。
驗證URL、Token以及加密的詳細處理請參考後續 「接收消息時的加解密處理」 的部分。
我公司的企業號配置後的界面以下所示。
這個URL裏面指向的頁面功能,須要對數據進行解析並返回給微信服務器,所以咱們須要在服務器上預先部署好這個處理功能入口。
除了上面的幾個函數,還有一個CorpID的參數須要使用,咱們能夠在後臺主界面-設置裏面查看到。
而後咱們爲了方便網站後臺使用,咱們和公衆號的配置同樣,把它放到了Web.Config裏面,以下所示。
前面介紹了幾個配置項,須要在回調頁面裏面使用的,本小節繼續介紹如何實現企業號信息的回發,使之經過回調測試的操做。
因爲回調測試的數據是經過Get方式發送的,所以咱們的處理邏輯代碼以下所示,和公衆號的相似處理,只是實現部分不太同樣而已。
///<summary>
/// 企業號回調信息接口。統一接收並處理信息的入口。
///</summary>
publicclass corpapi : IHttpHandler
{
///<summary>
/// 處理企業號的信息
///</summary>
///<param name="context"></param>
publicvoid ProcessRequest(HttpContext context)
{
string postString = string.Empty;
if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST")
{
using (Stream stream = HttpContext.Current.Request.InputStream)
{
Byte[] postBytes = new Byte[stream.Length];
stream.Read(postBytes, 0, (Int32)stream.Length);
postString = Encoding.UTF8.GetString(postBytes);
}
if (!string.IsNullOrEmpty(postString))
{
Execute(postString);
}
}
else
{
Auth();
}
}
///<summary>
/// 成爲開發者的第一步,驗證並相應服務器的數據
///</summary>
privatevoid Auth()
{
#region 獲取關鍵參數
string token = ConfigurationManager.AppSettings["CorpToken"];//從配置文件獲取Token
if (string.IsNullOrEmpty(token))
{
LogTextHelper.Error(string.Format("CorpToken 配置項沒有配置!"));
}
string encodingAESKey = ConfigurationManager.AppSettings["EncodingAESKey"];//從配置文件獲取EncodingAESKey
if (string.IsNullOrEmpty(encodingAESKey))
{
LogTextHelper.Error(string.Format("EncodingAESKey 配置項沒有配置!"));
}
string corpId = ConfigurationManager.AppSettings["CorpId"];//從配置文件獲取corpId
if (string.IsNullOrEmpty(corpId))
{
LogTextHelper.Error(string.Format("CorpId 配置項沒有配置!"));
}
#endregion
string echoString = HttpContext.Current.Request.QueryString["echoStr"];
string signature = HttpContext.Current.Request.QueryString["msg_signature"];//企業號的 msg_signature
string timestamp = HttpContext.Current.Request.QueryString["timestamp"];
string nonce = HttpContext.Current.Request.QueryString["nonce"];
string decryptEchoString = "";
if (new CorpBasicApi().CheckSignature(token, signature, timestamp, nonce, corpId, encodingAESKey, echoString, ref decryptEchoString))
{
if (!string.IsNullOrEmpty(decryptEchoString))
{
HttpContext.Current.Response.Write(decryptEchoString);
HttpContext.Current.Response.End();
}
}
}
具體的處理代碼以下所示,裏面的一個加解密處理的類是微信企業號附錄裏面提供的,我使用了C#版本的SDK而已。
///<summary>
/// 企業號基礎操做API實現
///</summary>
publicclass CorpBasicApi : ICorpBasicApi
{
///<summary>
/// 驗證企業號簽名
///</summary>
///<param name="token">企業號配置的Token</param>
///<param name="signature">簽名內容</param>
///<param name="timestamp">時間戳</param>
///<param name="nonce">nonce參數</param>
///<param name="corpId">企業號ID標識</param>
///<param name="encodingAESKey">加密鍵</param>
///<param name="echostr">內容字符串</param>
///<param name="retEchostr">返回的字符串</param>
///<returns></returns>
publicbool CheckSignature(string token, string signature, string timestamp, string nonce, string corpId, string encodingAESKey, string echostr, refstring retEchostr)
{
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId);
int result = wxcpt.VerifyURL(signature, timestamp, nonce, echostr, ref retEchostr);
if (result != 0)
{
LogTextHelper.Error("ERR: VerifyURL fail, ret: " + result);
returnfalse;
}
returntrue;
//ret==0表示驗證成功,retEchostr參數表示明文,用戶須要將retEchostr做爲get請求的返回參數,返回給企業號。
// HttpUtils.SetResponse(retEchostr);
}
前面一篇隨筆企業號的一些基礎信息,以及介紹如何配置企業號的回調方式實現和企業號服務器進行溝通的橋樑。本篇主要仍是繼續介紹企業號的開發工做的開展,介紹微信企業號通信錄管理開發功能,介紹其中組織機構裏面如何獲取和管理部門的信息等內容。
首先咱們能夠在企業號的管理後臺裏面建立一個組織機構,裏面建立一些部門和人員列表,方便咱們開發和使用。
例如建立一個廣州愛奇迪的根結構,而後在其中在建立一些組織機構,以下圖所示。
而後給組織結構根節點「廣州愛奇迪」增長一個管理員權限,之後再開發接口裏面也就能夠使用這個管理員所屬的權限Secret值進行調用了。
CorpID是企業號的標識,每一個企業號擁有一個惟一的CorpID;Secret是管理組憑證密鑰。
系統管理員可經過管理端的權限管理功能建立管理組,分配管理組對應用、通信錄、接口的訪問權限。完成後,管理組便可得到惟一的secret。系統管理員可經過權限管理查看全部管理組的secret,其餘管理員可經過設置中的開發者憑據查看。
個人企業號的建立者和「廣州愛奇迪」組織結構的管理員是不一樣的,因爲Secret是管理組憑證密鑰,所以管理者負責不一樣的組織機構管理的話,本身的管理Secret值可能就不一樣了。若是咱們須要調用接口,就須要用到這個屬於本身權限級別的Secret值,以下圖所示。
若是不是企業號的建立者,那麼可能不能修改裏面的一些權限分配,只能查看。
和公衆號同樣,咱們調用企業號API的第一步也是須要先獲取訪問的票據AccessToken。這個票據是全局性的,有必定的時效和頻率控制,所以須要適當的進行緩存,不能每次調用都去刷新獲取。
企業號獲取訪問票據的主要的邏輯代碼以下所示,其主要的就是須要使用管理者的Secret值去獲取對應的口令,這樣它就可以知道管理的是那個組織結構的了。
///<summary>
/// 獲取每次操做微信API的Token訪問令牌
///</summary>
///<param name="corpid">企業Id</param>
///<param name="corpsecret">管理組的憑證密鑰</param>
///<returns></returns>
publicstring GetAccessTokenNoCache(string corpid, string corpsecret)
{
var url = string.Format("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={0}&corpsecret={1}",
corpid, corpsecret);
HttpHelper helper = new HttpHelper();
string result = helper.GetHtml(url);
string regex = "\"access_token\":\"(?<token>.*?)\"";
string token = CRegex.GetText(result, regex, "token");
return token;
}
微信企業號的說明以下所示:
當企業應用調用企業號接口時,企業號後臺爲根據這次訪問的AccessToken,校驗訪問的合法性以及所對應的管理組的管理權限以返回相應的結果。
注:你應該審慎配置管理組的權限,夠用即好,權限過大會增長誤操做可能性及信息安全隱患。
AccessToken是企業號的全局惟一票據,調用接口時需攜帶AccessToken。AccessToken須要用CorpID和Secret來換取,不一樣的Secret會返回不一樣的AccessToken。正 常狀況下AccessToken有效期爲7200秒,有效期內重複獲取返回相同結果,並自動續期。因爲獲取access_token的api調用次數很是 有限,建議企業全局存儲與更新access_token,頻繁刷新access_token會致使api調用受限,影響自身業務。
有了第一節裏面的訪問票據,咱們就能夠利用API來作不少事情了,包括組織結構的獲取、建立、刪除等等功能。
建立部門的官方接口定義以下所示。
Https請求方式: POST
https://qyapi.weixin.qq.com/cgi-bin/department/create?access_token=ACCESS_TOKEN
請求包結構體爲:
{
"name": "郵箱產品組",
"parentid": "1"
}
參數 |
必須 |
說明 |
access_token |
是 |
調用接口憑證 |
name |
是 |
部門名稱。長度限制爲1~64個字符 |
parentid |
是 |
父親部門id。根部門id爲1 |
{
"errcode": 0,
"errmsg": "created",
"id": 2
}
根據上面的一些相似的接口定義說明,咱們先來定義下組織機構部門數據的維護接口,而後在逐步實現和調用。
#region 部門管理
///<summary>
/// 建立部門。
/// 管理員須擁有「操做通信錄」的接口權限,以及父部門的管理權限。
///</summary>
CorpDeptCreateJson CreateDept(string accessToken, string name, string parentId);
///<summary>
/// 更新部門。
/// 管理員須擁有「操做通信錄」的接口權限,以及該部門的管理權限。
///</summary>
CommonResult DeleteDept(string accessToken, int id);
///<summary>
/// 刪除部門.
/// 管理員須擁有「操做通信錄」的接口權限,以及該部門的管理權限。
///</summary>
CorpDeptListJson ListDept(string accessToken);
///<summary>
/// 獲取部門列表.
/// 管理員須擁有’獲取部門列表’的接口權限,以及對部門的查看權限。
///</summary>
CommonResult UpdateDept(string accessToken, int id, string name);
#endregion
如建立部門的接口實現以下所示,主要就是構建URL和POST的數據包,而後統一調用並獲取返回數據,轉換爲具體的Json對象實體便可。其餘接口的實現方式相似,不在贅述。
///<summary>
/// 建立部門。
/// 管理員須擁有「操做通信錄」的接口權限,以及父部門的管理權限。
///</summary>
public CorpDeptCreateJson CreateDept(string accessToken, string name, string parentId)
{
string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/department/create?access_token={0}";
var data = new
{
name = name,
parentId = parentId
};
var url = string.Format(urlFormat, accessToken);
var postData = data.ToJson();
CorpDeptCreateJson result = CorpJsonHelper<CorpDeptCreateJson>.ConvertJson(url, postData);
return result;
}
CorpDeptCreateJson 對象實體類的定義以下所示,咱們主要是根據返回結果進行定義的。
///<summary>
/// 建立部門的返回結果
///</summary>
publicclass CorpDeptCreateJson : BaseJsonResult
{
///<summary>
/// 返回的錯誤消息
///</summary>
public CorpReturnCode errcode { get; set; }
///<summary>
/// 對返回碼的文本描述內容
///</summary>
publicstring errmsg { get; set; }
///<summary>
/// 建立的部門id。
///</summary>
publicint id { get; set; }
}
上面小節介紹瞭如何封裝部門管理的API,那麼咱們封裝好了對應的接口和接口實現,怎麼樣在實際環境裏面進行調用處理的呢,爲了方便我建立一個小的Winform程序來測試對應API的功能,以下所示。
下面咱們來介紹一下調用的代碼和效果展現。
privatevoid btnCreateDeleteDept_Click(object sender, EventArgs e)
{
ICorpAddressBookApi bll = new CorpAddressBookApi();
string name = "測試部門";
CorpDeptCreateJson json = bll.CreateDept(token, name, "2");
if (json != null)
{
Console.WriteLine("建立了部門:{0}, ID:{1}", name, json.id);
//更新部門信息
name = "測試部門修更名稱";
CommonResult result = bll.UpdateDept(token, json.id, name);
if(result != null)
{
Console.WriteLine("修改部門名稱:{0} {1}", (result.Success ? "成功" : "失敗"), result.ErrorMessage);
}
//刪除部門
result = bll.DeleteDept(token, json.id);
if (result != null)
{
Console.WriteLine("刪除部門名稱:{0} {1}", (result.Success ? "成功" : "失敗"), result.ErrorMessage);
}
}
}
///<summary>
/// 獲取部門列表
///</summary>
privatevoid btnListDept_Click(object sender, EventArgs e)
{
ICorpAddressBookApi bll = new CorpAddressBookApi();
CorpDeptListJson list = bll.ListDept(token);
foreach (CorpDeptJson info in list.department)
{
string tips = string.Format("{0}:{1}", info.name, info.id);
Console.WriteLine(tips);
}
}
在上篇隨筆《C#開發微信門戶及應用(17)-微信企業號的通信錄管理開發之部門管理》介紹了通信錄的部門的相關操做管理,通信錄管理包括部門管理、成員管理、標籤管理三個部分,本篇主要介紹成員的管理操做,包括建立、刪除、更新、獲取、獲取部門成員幾個操做要點。
爲了方便,咱們能夠建立一個部門組織結構,這是開發的前提,由於咱們通信錄管理,也是基於一個組織機構下的,如上篇介紹的組織結構層次同樣。我這裏建立一個廣州愛奇迪的根結構,而後在其中在建立一些組織機構,以下圖所示。
在後臺能夠經過功能操做添加人員,本篇主要介紹如何調用微信企業號API進行人員管理的操做。
建立人員的API定義以下所示。
Https請求方式: POST
https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token=ACCESS_TOKEN
請求包結構體爲:
{
"userid": "zhangsan",
"name": "張三",
"department": [1, 2],
"position": "產品經理",
"mobile": "15913215421",
"gender": 1,
"tel": "62394",
"email": "zhangsan@gzdev.com",
"weixinid": "zhangsan4dev"
}
參數 |
必須 |
說明 |
access_token |
是 |
調用接口憑證 |
userid |
是 |
員工UserID。對應管理端的賬號,企業內必須惟一。長度爲1~64個字符 |
name |
是 |
成員名稱。長度爲1~64個字符 |
department |
否 |
成員所屬部門id列表。注意,每一個部門的直屬員工上限爲1000個 |
position |
否 |
職位信息。長度爲0~64個字符 |
mobile |
否 |
手機號碼。企業內必須惟一,mobile/weixinid/email三者不能同時爲空 |
gender |
否 |
性別。gender=0表示男,=1表示女。默認gender=0 |
tel |
否 |
辦公電話。長度爲0~64個字符 |
|
否 |
郵箱。長度爲0~64個字符。企業內必須惟一 |
weixinid |
否 |
微信號。企業內必須惟一 |
管理員須擁有「操做通信錄」的接口權限,以及指定部門的管理權限。
{
"errcode": 0,
"errmsg": "created"
}
咱們在C#裏面,須要定義對應給的接口,而後根據須要構造對應的傳遞實體信息。
這裏我把人員管理的接口所有定義好,接口定義以下所示。
#region 部門成員管理
///<summary>
/// 建立成員
///</summary>
CommonResult CreateUser(string accessToken, CorpUserJson user);
///<summary>
/// 更新成員
///</summary>
CommonResult UpdateUser(string accessToken, CorpUserUpdateJson user);
///<summary>
/// 刪除成員
///</summary>
CommonResult DeleteUser(string accessToken, string userid);
///<summary>
/// 根據成員id獲取成員信息
///</summary>
CorpUserGetJson GetUser(string accessToken, string userid);
///<summary>
/// 獲取部門成員
///</summary>
CorpUserListJson GetDeptUser(string accessToken, int department_id, int fetch_child = 0, int status = 0);
#endregion
而後根據信息定義,建立一個承載人員信息的CorpUserJson實體對象,建立人員的實現操做代碼以下所示。
///<summary>
/// 建立成員
///</summary>
public CommonResult CreateUser(string accessToken, CorpUserJson user)
{
string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token={0}";
var data = new
{
userid = user.userid,
name = user.name,
department = user.department,
position = user.position,
mobile = user.mobile,
gender = user.gender,
tel = user.tel,
email = user.email,
weixinid = user.weixinid
};
var url = string.Format(urlFormat, accessToken);
var postData = data.ToJson();
return Helper.GetCorpExecuteResult(url, postData);
}
成員的數據更新和建立操做相似,它的企業號定義以下所示。
Https請求方式: POST
https://qyapi.weixin.qq.com/cgi-bin/user/update?access_token=ACCESS_TOKEN
請求包示例以下(若是非必須的字段未指定,則不更新該字段以前的設置值):
{
"userid": "zhangsan",
"name": "李四",
"department": [1],
"position": "後臺工程師",
"mobile": "15913215421",
"gender": 1,
"tel": "62394",
"email": "zhangsan@gzdev.com",
"weixinid": "lisifordev",
"enable": 1
}
因爲它的操做數據相似,所以它的實現代碼也差很少,以下所示就是。
///<summary>
/// 更新成員
///</summary>
public CommonResult UpdateUser(string accessToken, CorpUserUpdateJson user)
{
string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/user/update?access_token={0}";
//string postData = user.ToJson();
var data = new
{
userid = user.userid,
name = user.name,
department = user.department,
position = user.position,
mobile = user.mobile,
gender = user.gender,
tel = user.tel,
email = user.email,
weixinid = user.weixinid,
enable = user.enable
};
var url = string.Format(urlFormat, accessToken);
var postData = data.ToJson();
return Helper.GetCorpExecuteResult(url, postData);
}
這些操做和上面的相似,不在贅述,主要就是根據須要定義他們對應的返回數據信息,而後解析Json數據便可轉換爲對應的實體。
Https請求方式: GET
https://qyapi.weixin.qq.com/cgi-bin/user/delete?access_token=ACCESS_TOKEN&userid=lisi
參數 |
必須 |
說明 |
access_token |
是 |
調用接口憑證 |
userid |
是 |
員工UserID。對應管理端的賬號 |
{
"errcode": 0,
"errmsg": "deleted"
}
Https請求方式: GET
https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=lisi
參數 |
必須 |
說明 |
access_token |
是 |
調用接口憑證 |
userid |
是 |
員工UserID |
{
"errcode": 0,
"errmsg": "ok",
"userid": "zhangsan",
"name": "李四",
"department": [1, 2],
"position": "後臺工程師",
"mobile": "15913215421",
"gender": 1,
"tel": "62394",
"email": "zhangsan@gzdev.com",
"weixinid": "lisifordev",
"avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
"status": 1
}
Https請求方式: GET
參數 |
必須 |
說明 |
access_token |
是 |
調用接口憑證 |
department_id |
是 |
獲取的部門id |
fetch_child |
否 |
1/0:是否遞歸獲取子部門下面的成員 |
status |
否 |
0獲取所有員工,1獲取已關注成員列表,2獲取禁用成員列表,4獲取未關注成員列表。status可疊加 |
管理員須擁有’獲取部門成員’的接口權限,以及指定部門的查看權限。
{
"errcode": 0,
"errmsg": "ok",
"userlist": [
{
"userid": "zhangsan",
"name": "李四"
}
]
}
這個返回值咱們定義一個實體對象用來存儲數據便可。
///<summary>
/// 獲取部門成員返回的數據
///</summary>
publicclass CorpUserListJson : BaseJsonResult
{
public CorpUserListJson()
{
this.userlist = new List<CorpUserSimpleJson>();
}
///<summary>
/// 返回的錯誤消息
///</summary>
public CorpReturnCode errcode { get; set; }
///<summary>
/// 對返回碼的文本描述內容
///</summary>
publicstring errmsg { get; set; }
///<summary>
/// 成員列表
///</summary>
public List<CorpUserSimpleJson> userlist { get; set; }
}
上面介紹了一些企業號的接口定義和我對API的C#封裝接口和部分實現代碼,實現了功能後,咱們就能夠在代碼中對它進行測試,確信是否正常使用。
///<summary>
/// 人員管理綜合性操做(建立、修改、獲取信息、刪除)
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
privatevoid btnCorpUser_Click(object sender, EventArgs e)
{
CorpUserJson user = new CorpUserJson();
user.userid = "test";
user.name ="測試用戶";
user.department = new List<int>(){2};
user.email = "test@163.com";
ICorpAddressBookApi bll = new CorpAddressBookApi();
CommonResult result = bll.CreateUser(token, user);
if (result != null)
{
Console.WriteLine("建立成員:{0} {1} {2}", user.name, (result.Success ? "成功" : "失敗"), result.ErrorMessage);
string name = "修改測試";
user.name = name;
CorpUserUpdateJson userUpdate = new CorpUserUpdateJson(user);
result = bll.UpdateUser(token, userUpdate);
if (result != null)
{
Console.WriteLine("修更名稱:{0} {1} {2}", name, (result.Success ? "成功" : "失敗"), result.ErrorMessage);
}
CorpUserGetJson userGet = bll.GetUser(token, user.userid);
if (userGet != null)
{
Console.WriteLine("成員名稱:{0} ({1} {2})", userGet.name, user.userid, user.email);
}
result = bll.DeleteUser(token, user.userid);
if (result != null)
{
Console.WriteLine("刪除成員:{0} {1} {2}", name, (result.Success ? "成功" : "失敗"), result.ErrorMessage);
}
}
}
獲取部門人員的操做代碼以下所示。
///<summary>
/// 獲取部門人員
///</summary>
privatevoid btnCorpUserList_Click(object sender, EventArgs e)
{
int deptId = 1;
ICorpAddressBookApi bll = new CorpAddressBookApi();
CorpUserListJson result = bll.GetDeptUser(token, deptId);
if (result != null)
{
foreach(CorpUserSimpleJson item in result.userlist)
{
Console.WriteLine("成員名稱:{0} {1}", item.name, item.userid);
}
}
}
人員的管理,相對來講比較簡單,主要是在必定的部門下建立人員,而後也能夠給標籤增長相應的人員,基本上就是這些了,不過必定須要確保有相應的權限進行操做。
咱們知道,企業號主要是面向企業需求而生的,所以內部消息的交流顯得很是重要,並且發送、回覆消息數量應該很可觀,對於大企業尤爲如此,所以能夠 結合企業號實現內部消息的交流。企業號具備關注安全、消息無限制等特色,很適合企業內部的環境。本文主要介紹如何利用企業號實現文本、圖片、文件、語音、 視頻、圖文消息等消息的發送操做。
對於企業號,有如下一些特色:
1)關注更安全
–只有企業通信錄的成員才能關注企業號,分級管理員、保密消息等各類特性確保企業內部信息的安全。
企業能夠設置自行驗證關注者身份,進行二次安全驗證,保證企業信息使用和傳遞安全。
若員工離職,企業管理員可在通信錄中刪除該成員,該成員即自動取消關注企業號,同時微信中的企業號歷史記錄也會被清除。
2)應用可配置
–企業可自行在企業號中可配置多個服務號,能夠鏈接不一樣的企業應用系統,只有受權的企業成員才能使用相應的服務號。
3)消息無限制
–發送消息無限制,並提供完善的的管理接口及微信原生能力,以適應企業複雜、個性化的應用場景。
企業能夠主動發消息給員工,消息量不受限制。
4)使用更便捷
–企業號在微信中有統一的消息入口,用戶能夠更方便地管理企業號消息。微信通信錄也能夠直接訪問企業號中的應用。
目前企業號的內容能夠用下面的分層圖來展現,分別包含素材管理、被動響應消息、通信錄管理、自定義菜單等內容,詳細能夠看下面圖示。
企業號和公衆號同樣,能夠分爲消息處理和事件處理,下面是他們兩種類型的處理操做,也就發送的消息有文本消息、圖片消息、文件消息、視頻消息、語音消息、地理文字消息、圖文和多媒體消息等。
事件處理主要就是關注、取消關注事件,以及菜單click類型和view類型兩種操做,還有就是地理位置上報事件等。
兩種類型的處理圖以下所示。
在企業的管理後臺,和公衆號同樣,能夠看到對應信息交流記錄,包括文字、圖片、地理位置等等,以下所示。
因爲消息分爲幾種類型,包括文本(Text)、圖片(Image)、文件(File)、語音(Voice)、視頻(Video)、圖文消息等(News)、MpNews等。
所以咱們須要分別對它們進行必定的定義和封裝處理,以下是它們的信息對象設計圖。
企業號發送消息的官方定義以下:
企業能夠主動發消息給員工,消息量不受限制。
調用接口時,使用Https協議、JSON數據包格式,數據包不需作加密處理。
目前支持文本、圖片、語音、視頻、文件、圖文等消息類型。除了news類型,其它類型的消息可在發送時加上保密選項,保密消息會被打上水印,而且只有接收者才能閱讀。
咱們以發送的文本消息爲例進行說明,它的定義以下所示。
{
"touser": "UserID1|UserID2|UserID3",
"toparty": " PartyID1 | PartyID2 ",
"totag": " TagID1 | TagID2 ",
"msgtype": "text",
"agentid": "1",
"text": {
"content": "Holiday Request For Pony(http://xxxxx)"
},
"safe":"0"
}
參數 |
必須 |
說明 |
touser |
否 |
UserID列表(消息接收者,多個接收者用‘|’分隔)。特殊狀況:指定爲@all,則向關注該企業應用的所有成員發送 |
toparty |
否 |
PartyID列表,多個接受者用‘|’分隔。當touser爲@all時忽略本參數 |
totag |
否 |
TagID列表,多個接受者用‘|’分隔。當touser爲@all時忽略本參數 |
msgtype |
是 |
消息類型,此時固定爲:text |
agentid |
是 |
企業應用的id,整型。可在應用的設置頁面查看 |
content |
是 |
消息內容 |
safe |
否 |
表示是不是保密消息,0表示否,1表示是,默認0 |
其中每種消息都會包含如下消息所示,也就是它們共同的屬性:
touser": "UserID1|UserID2|UserID3",
"toparty": " PartyID1 | PartyID2 ",
"totag": " TagID1 | TagID2 ",
"msgtype": "text",
"agentid": "1",
所以咱們能夠定義一個基類用來方便承載這些共同的信息。
///<summary>
/// 企業號發送消息的基礎消息內容
///</summary>
publicclass CorpSendBase
{
///<summary>
/// UserID列表(消息接收者,多個接收者用‘|’分隔)。特殊狀況:指定爲@all,則向關注該企業應用的所有成員發送
///</summary>
publicstring touser { get; set; }
///<summary>
/// PartyID列表,多個接受者用‘|’分隔。當touser爲@all時忽略本參數
///</summary>
publicstring toparty { get; set; }
///<summary>
/// TagID列表,多個接受者用‘|’分隔。當touser爲@all時忽略本參數
///</summary>
publicstring totag { get; set; }
///<summary>
/// 消息類型
///</summary>
publicstring msgtype { get; set; }
///<summary>
/// 企業應用的id,整型。可在應用的設置頁面查看
///</summary>
publicstring agentid { get; set; }
///<summary>
/// 表示是不是保密消息,0表示否,1表示是,默認0
///</summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
publicstring safe { get; set; }
}
而後其餘消息逐一繼承這個基類便可,以下所示。
最終會構成下面這個繼承關係圖。
定義好相關的發送對象後,咱們就能夠定義它的統一發送接口了,以下所示。
///<summary>
/// 企業號消息管理接口定義
///</summary>
publicinterface ICorpMessageApi
{
///<summary>
/// 發送消息。
/// 須要管理員對應用有使用權限,對收件人touser、toparty、totag有查看權限,不然本次調用失敗。
///</summary>
///<param name="accessToken"></param>
///<returns></returns>
CommonResult SendMessage(string accessToken, CorpSendBase data);
}
最終,文本等類型的消息會根據接口定義進行實現,實現代碼以下所示。注意,發送過程不須要調用加密類進行加密。
///<summary>
/// 企業號消息管理實現類
///</summary>
publicclass CorpMessageApi : ICorpMessageApi
{
///<summary>
/// 發送消息。
/// 須要管理員對應用有使用權限,對收件人touser、toparty、totag有查看權限,不然本次調用失敗。
///</summary>
///<param name="accessToken"></param>
///<returns></returns>
public CommonResult SendMessage(string accessToken, CorpSendBase data)
{
CommonResult result = new CommonResult();
string urlFormat = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={0}";
var url = string.Format(urlFormat, accessToken);
var postData = data.ToJson();
//數據不用加密發送
CorpSendResult sendResult = CorpJsonHelper<CorpSendResult>.ConvertJson(url, postData);
if (sendResult != null)
{
result.Success = (sendResult.errcode == CorpReturnCode.請求成功);
result.ErrorMessage = string.Format("invaliduser:{0},invalidparty:{1},invalidtag:{2}",
sendResult.invaliduser, sendResult.invalidparty, sendResult.invalidtag);
}
return result;
}
}
定義好相應的發送對象後,咱們就能夠進行統一的消息發送操做,包括文本、圖片、文件、語音等等類型的消息,注意有些消息是須要上傳到服務器上,而後在根據mediaId進行發送出去的。
發送文本和圖片的操做代碼以下所示。
privatevoid btnSendText_Click(object sender, EventArgs e)
{
//發送文本內容
ICorpMessageApi bll = new CorpMessageApi();
CorpSendText text = new CorpSendText("API 中文測試(http://www.iqidi.com)");
text.touser = "wuhuacong";
text.toparty = "4";//部門ID
text.totag = "0";
text.safe = "0";
text.agentid = "0";
CommonResult result = bll.SendMessage(token, text);
if (result != null)
{
Console.WriteLine("發送消息:{0} {1} {2}", text.text.content, (result.Success ? "成功" : "失敗"), result.ErrorMessage);
}
}
privatevoid btnSendImage_Click(object sender, EventArgs e)
{
btnUpload_Click(sender, e);
if (!string.IsNullOrEmpty(image_mediaId))
{
//發送圖片內容
ICorpMessageApi bll = new CorpMessageApi();
CorpSendImage image = new CorpSendImage(image_mediaId);
CommonResult result = bll.SendMessage(token, image);
if (result != null)
{
Console.WriteLine("發送圖片消息:{0} {1} {2}", image_mediaId, (result.Success ? "成功" : "失敗"), result.ErrorMessage);
}
}
}
最後在微信企業號上截圖效果以下所示,包括了文本測試、文件測試、圖文測試、語音測試均正常。
前面幾篇陸續介紹了不少微信企業號的相關操做,企業號和公衆號同樣均可以自定義菜單,所以他們也能夠經過API進行菜單的建立、獲取列表、刪除的操做,所以本篇繼續探討這個主體,介紹企業號的菜單管理操做。
菜單在不少狀況下,可以給咱們提供一個快速入口,也能夠用來獲取用戶信息的主要入口,經過OAuth2驗證接口,以及自定義的重定向菜單,咱們就能夠獲取對應的用戶ID,而後進一步獲取到用戶的相關數據,能夠顯示給客戶。
菜單的事件處理以下所示,包括了單擊和跳轉兩個操做,將來企業號可能會增長一些和公衆號同樣的掃碼操做,拍照操做等功能的,目前只有兩個。
官方的菜單定義接口包含了下面三種操做,菜單建立、列表獲取和菜單刪除,這點和公衆號操做幾乎同樣了。
咱們定義菜單,包括定義它的一些屬性,包含有name, type, key,url,以及一個指向自身引用的子菜單引用,所以菜單就能夠循環構造多個層次,雖然嚴格意義上來說,企業號的菜單和公衆號菜單同樣,一級三個,二級最多五個,並且沒有三級菜單了。
實體類的UML圖示以下所示。
菜單管理的建立操做,官方定義以下所示。
Https請求方式: POST
https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN&agentid=1
請求包以下:
{
"button":[
{
"type":"click",
"name":"今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"name":"菜單",
"sub_button":[
{
"type":"view",
"name":"搜索",
"url":"http://www.soso.com/"
},
{
"type":"click",
"name":"贊一下咱們",
"key":"V1001_GOOD"
}
]
}
]
}
參數 |
必須 |
說明 |
access_token |
是 |
調用接口憑證 |
agentid |
是 |
企業應用的id,整型。可在應用的設置頁面查看 |
button |
是 |
一級菜單數組,個數應爲1~3個 |
sub_button |
否 |
二級菜單數組,個數應爲1~5個 |
type |
是 |
菜單的響應動做類型,目前有click、view兩種類型 |
name |
是 |
菜單標題,不超過16個字節,子菜單不超過40個字節 |
key |
click類型必須 |
菜單KEY值,用於消息接口推送,不超過128字節 |
url |
view類型必須 |
網頁連接,員工點擊菜單可打開連接,不超過256字節 |
管理員須擁有應用的管理權限,而且應用必須設置在回調模式。
返回結果
{
"errcode":0,
"errmsg":"ok"
}
根據上面官方的定義語義,咱們菜單管理的C#管理接口定義以下所示。
///<summary>
/// 企業號菜單管理接口定義
///</summary>
publicinterface ICorpMenuApi
{
///<summary>
/// 獲取菜單數據
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<returns></returns>
MenuListJson GetMenu(string accessToken, string agentid);
///<summary>
/// 建立菜單
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="menuJson">菜單對象</param>
///<returns></returns>
CommonResult CreateMenu(string accessToken, MenuListJson menuJson, string agentid);
///<summary>
/// 刪除菜單
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<returns></returns>
CommonResult DeleteMenu(string accessToken, string agentid);
}
咱們以建立菜單的實現爲例來介紹微信企業號菜單的操做,其餘的操做相似處理,都是返回一個公共的消息類,方便處理和讀取,代碼以下所示。
///<summary>
/// 建立菜單
///</summary>
///<param name="accessToken">調用接口憑證</param>
///<param name="menuJson">菜單對象</param>
///<returns></returns>
public CommonResult CreateMenu(string accessToken, MenuListJson menuJson, string agentid)
{
var url = string.Format("https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token={0}&agentid={1}", accessToken, agentid);
string postData = menuJson.ToJson();
return Helper.GetCorpExecuteResult(url, postData);
}
調用的代碼和效果圖以下所示。
privatevoid btnMenuCreate_Click(object sender, EventArgs e)
{
MenuJson productInfo = new MenuJson("產品介紹", new MenuJson[] {
new MenuJson("軟件產品介紹", ButtonType.click, "event-software")
, new MenuJson("框架源碼產品", ButtonType.click, "event-source")
, new MenuJson("軟件定製開發", ButtonType.click, "event-develop")
});
MenuJson frameworkInfo = new MenuJson("框架產品", new MenuJson[] {
new MenuJson("Win開發框架", ButtonType.click, "win"),
new MenuJson("WCF開發框架", ButtonType.click, "wcf"),
new MenuJson("混合式框架", ButtonType.click, "mix"),
new MenuJson("Web開發框架", ButtonType.click, "web")
,new MenuJson("代碼生成工具", ButtonType.click, "database2sharp")
});
MenuJson relatedInfo = new MenuJson("相關連接", new MenuJson[] {
new MenuJson("公司介紹", ButtonType.click, "event_company"),
new MenuJson("官方網站", ButtonType.view, "http://www.iqidi.com"),
new MenuJson("聯繫咱們", ButtonType.click, "event_contact"),
new MenuJson("應答系統", ButtonType.click, "set-1"),
new MenuJson("發郵件", ButtonType.view, "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=S31yfX15fn8LOjplKCQm")
});
MenuListJson menuJson = new MenuListJson();
menuJson.button.AddRange(new MenuJson[] { productInfo, frameworkInfo, relatedInfo });
//Console.WriteLine(menuJson.ToJson());
if (MessageUtil.ShowYesNoAndWarning("您確認要建立菜單嗎") == System.Windows.Forms.DialogResult.Yes)
{
ICorpMenuApi bll = new CorpMenuApi();
CommonResult result = bll.CreateMenu(token, menuJson, agentid);
Console.WriteLine("建立菜單:" + (result.Success ? "成功" : "失敗:" + result.ErrorMessage));
}
}
privatevoid btnMenuGet_Click(object sender, EventArgs e)
{
ICorpMenuApi bll = new CorpMenuApi();
MenuListJson menu = bll.GetMenu(token, agentid);
if (menu != null)
{
Console.WriteLine(menu.ToJson());
}
}
調用代碼的測試輸出以下所示。