以文本方式查看主题 - Foxtable(狐表) (http://foxtable.com/bbs/index.asp) -- 专家坐堂 (http://foxtable.com/bbs/list.asp?boardid=2) ---- 二、Foxtable、微信公众平台与Asp.net开发实践之二:用Foxtable设计公众号的菜单 (http://foxtable.com/bbs/dispbbs.asp?boardid=2&id=77773) |
|||||||||||||||||||
-- 作者:Hyphen -- 发布时间:2015/11/25 10:19:00 -- 二、Foxtable、微信公众平台与Asp.net开发实践之二:用Foxtable设计公众号的菜单 如有任何错漏和好的建议可以在汇总帖回帖说明 ,不胜感谢。
如果有什么开发上的疑问,请另开一帖提问,本帖不回。 示例在汇总贴
要设计菜单,首先要明白微信菜单的组成。
这是由于启用了上面第一章实践中我们保存的服务器配置,启用了配置后,微信默认大部分的功能都由开发者接口来提供,为了避免冲突,公众号管理页面一些功能会屏蔽不能在管理页面使用。我们这里主要做的就是开发实践,所以页面管理就不做介绍了。
打开微信开发文档,可以看到以下一段说明
所以我们设计的菜单就要符合游戏制定者的规则。
微信菜单有10种类型的菜单,以click和view类型为主,其它的相对用的比较少。
微信菜单接口传输的一般都是JSON数据包,所以我们需要在程序中进行转换,代码直接使用了Newtonsoft.Json库。
下面我们就来一步步做一个可以使用的菜单:
1. 创建微信管理项目并设计数据表
打开Foxtable开发版,创建一个项目,项目名称“微信管理”,点击创建表,分别创建2个表【微信公众号菜单】和【菜单响应类型】:
|
|||||||||||||||||||
-- 作者:Hyphen -- 发布时间:2015/11/25 10:19:00 -- 继续
把开发文档中的10种菜单类型导入表【菜单响应类型】。
2. 设计菜单管理窗口
打开窗口管理增加一个窗口“微信公众号菜单设置”,设计一个类似以下界面的窗口,可以增加、修改和删除微信菜单。
窗口左边为一棵树,直观显示菜单的层次,设置一个函数ReflashTree,更改菜单后刷新树结构: Dim canUse As Boolean = args(0) Dim trvMenu As WinForm.TreeView = Forms("微信公众号菜单设置").Controls("trvMenu") trvMenu.CreateTree("微信公众号菜单","路径","\\",IIF(canUse,"是否停用 = 0",""),"排序")
For Each n As WinForm.TreeNode In trvMenu.Nodes If n.Level = 0 n.Ic Else n.Ic End If Next trvMenu.ExpandAll()
右边下侧是菜单表的副本,上侧是一些编辑框。
其中菜单响应类型下拉框内容来自“菜单响应类型”表,
这里的设计是点击新增和修改后,编辑完内容,需要点击保存,才保存到数据库中。
根据微信接口的一些要求和限制,保存逻辑中做了一些相应的校验,详细校验逻辑见附件示例。
3. 提交菜单到微信
3.1 微信接口的调用
开发文档中创建菜单的接口是:
http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
可以看得出来,微信要求使用POST的方式请求接口。
再看看接口参数,需要传递一个access_token,那么这个access_token又是怎么来的,到开发文档找找,文档是这么说的
获取access_token接口调用请求说明:
http请求方式: GET access_token接口的请求方式是GET,参数有3个
调用access_token接口的返回值是这样的
{"access_token":"ACCESS_TOKEN","expires_in":7200}
grant_type是固定的内容,我们不用管;appid和secret就是微信管理平台开发者中心的开发者ID,都可以取的到,每个公众号的开发者ID都是唯一的。
到这里我们明白了几点:
a、所有的接口都需要使用access_token,所以每次调用接口都需要获取access_token b、access_token并不是每次都重新需要获取,有一定的有效期,目前是2小时(7200秒),不然每天2000次的调用限制很快就会用完,所以需要做缓存处理 c、access_token依赖于开发者ID生成,所以请妥善保管好自己的开发者ID,避免被别人利用 d、微信的接口用的https协议,请求方式get和post都用到了,所以可以在代码中进行包装一下,进行代码重用 e、微信接口收发的都是Json数据包,所以设计上最好是适应这种特点
下面就根据这几点做一些接口调用前的准备工作
3.2 打开全局代码增加一些实体数据类
主要是一些实体类,方便在Json字符串和对象之间做转换,注意各类中定义的属性和Json中的名称要一致,而且大小写也要一致,比如微信接口的返回值是这样的:{"errcode":40013,"errmsg":"invalid appid"}; 那么可以定义一个能够获取返回值的类如下 \'与微信接口交互的Json对象接口 Public Class JsonDatabase \' 微信接口请求错误返回的错误码 Public errcode As ReturnCode = ReturnCode.请求成功 \' 微信接口请求错误返回的错误描述 Public errmsg As String Public Overridable Function CheckError() As Boolean Return errcode = ReturnCode.请求成功 End Function End Class
其它的实体类的定义请自行查看示例的全局代码,就不一一贴出来了。
[此贴子已经被作者于2015/11/25 10:27:15编辑过]
|
|||||||||||||||||||
-- 作者:Hyphen -- 发布时间:2015/11/25 10:20:00 -- 继续
3.3 打开内部函数,增加一些函数 a、定义GET函数:HttpGet Dim url As String = args(0) Dim encoding As System.Text.Encoding Dim wc As New System.Net.WebClient() wc.Encoding = encoding Return wc.DownloadString(url) b、定义POST函数:HttpPost \'定义POST函数 Dim url As String = Args(0) \'post的接口地址 Dim postStream As System.IO.Stream = Args(1) \'向接口POST的数据流 Dim encoding As System.Text.Encoding = System.Text.Encoding.GetEncoding("utf-8")\'编码格式 Dim sresult As String Dim request As System.Net.HttpWebRequest = DirectCast(System.Net.WebRequest.Create(url), System.Net.HttpWebRequest) request.Method = "POST" request.Timeout = Vars("TimeOut") \'设置标头 request.ContentType = "application/x-www-form-urlencoded" request.ContentLength = IIf(Not postStream Is Nothing, postStream.Length, 0) request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" request.KeepAlive = True request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36" \'向接口POST数据 If (Not postStream Is Nothing) Then postStream.Position = 0 Dim requestStream As System.IO.Stream = request.GetRequestStream Dim buffer4 As Byte() = New Byte(&H400 - 1) {} Dim num3 As Integer = postStream.Read(buffer4, 0, buffer4.Length) Do While (num3 <> 0) requestStream.Write(buffer4, 0, num3) num3 = postStream.Read(buffer4, 0, buffer4.Length) Loop postStream.Close() End If \'获取接口的返回值 Dim response As System.Net.HttpWebResponse = DirectCast(request.GetResponse, System.Net.HttpWebResponse) Using stream3 As System.IO.Stream = response.GetResponseStream Using reader As System.IO.StreamReader = New System.IO.StreamReader(stream3, encoding) sresult = reader.ReadToEnd End Using End Using Return sresult
c、定义获取AccessToken的函数: 在全局代码中定义一个AccessToken缓存对象 Public _accesstokencache As new AccessTokenCacheData 在项目事件AfterOpenProject中赋值开发者ID \'定义开发者ID,实际应用时,可以加密字符串,放到配置文件中 _accesstokencache.AppId= "AppId" \'填写自己的AppId _accesstokencache.AppSecret = "AppSecret" \'填写自己的AppSecret 创建一个函数,从微信接口获取AccessToken:GetNewAccessToken Dim appid As String = _accesstokencache.AppId Dim secret As String = _accesstokencache.AppSecret Dim grant_type As String = "client_credential" Dim url As String = String.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type={0}&appid={1}&secret={2}", grant_type, appid, secret) Dim json As String = Functions.Execute("HttpGet",url) Return ConvertHelper.FromJson(Of AccessTokenData)(json) 为了实现缓存,定义另外一个获取AccessToken的函数:GetAccessToken \'如果没有过期 If Not _accesstokencache.IsExpire Then Functions.Execute("LogText","请求AccessToken:" & _accesstokencache.AccessTokenData.access_token) Return _accesstokencache.AccessTokenData End If \'过期就获取新的AccessToken Dim accesstoken = Functions.Execute("GetNewAccessToken") \'第一次请求不成功,重复一次 If accesstoken.errcode <> ReturnCode.请求成功 Then accesstoken = Functions.Execute("GetNewAccessToken") End If If accesstoken.errcode = ReturnCode.请求成功 Then _accesstokencache.AccessTokenData = accesstoken End If Functions.Execute("LogText","请求AccessToken:" & accesstoken.access_token) Return accesstoken [此贴子已经被作者于2015/11/25 11:01:42编辑过]
|
|||||||||||||||||||
-- 作者:Hyphen -- 发布时间:2015/11/25 10:20:00 -- 继续 d、定义创建微信接口菜单Json数据包函数:GetMenuJson 菜单并不复杂,先取一级菜单,判断有子菜单,则增加子菜单,并返回一个完整的菜单对象,然后序列化为Json字符串。当然各位看客有兴趣的话也可以自己写代码拼凑json字符串,就不用定义全局代码中那么多实体类了,。 Dim drs As List(Of DataRow) drs = DataTables("微信公众号菜单").Sel ect("是否停用 = 0 and (所属一级菜单 is null or 所属一级菜单 = \'\')","排序") If drs.Count > 0 Then Dim menu As new MmsgMenuGroup Dim button As object Dim submenudrs As List(Of DataRow) Dim subbutton As MmsgMenuBase For i As Integer = 0 To drs.Count -1 submenudrs = DataTables("微信公众号菜单").Sel ect("是否停用 = 0 and 所属一级菜单 = \'" & drs(i)("name") & "\'","排序") If submenudrs.Count > 0 Then button = new MmsgSubMenuButton button.name = drs(i)("name") For j As Integer = 0 To submenudrs.Count -1 subbutton = Functions.Execute("GetMmsgMenu",submenudrs(j)("type")) ConvertHelper.FromDataRow(submenudrs(j),subbutton ) button.sub_button.Add(subbutton) Next Else button = MmsgMenuHelper.GetMmsgMenu(drs(i)("type")) ConvertHelper.FromDataRow(drs(i),button) End If menu.button.Add(button ) Next Return ConvertHelper.ToJson(menu) End If Return Nothing
3.4 创建微信菜单 好了,万事具备,只欠东风。如果已经定义好了菜单,那么可以调用一下GetMenuJson函数,看Json数据是否正常。打开命令窗口,输入:Output.Show(Functions.Execute("GetMenuJson")),执行,返回值如下:
这里只测试了click和view类型菜单,其它类型没有测试,等后面的篇章再做实践。 打开“微信公众号菜单设置窗口”,在按钮事件中编辑代码: If MessageBox.Show("提交后会覆盖原有的菜单,确定要提交?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then Dim menujsonstring As String = Functions.Execute("GetMenuJson") \' 获取菜单Json Dim accesstoken = Functions.Execute("GetAccessToken") \'获取AccessToken \'定义接口url Dim url = String.Format("https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}", accesstoken.access_token) \'把菜单Json序列化到内存流 Using ms As New System.IO.MemoryStream() Dim bytes = ConvertHelper.EncodingToBytes(menujsonstring, System.Text.Encoding.UTF8) ms.Write(bytes, 0, bytes.Length) ms.Seek(0, System.IO.SeekOrigin.Begin) Dim jsonString = Functions.Execute("HttpPost",url, ms) \'通过POST向接口传输菜单数据,并取得返回结果 Dim mresult = ConvertHelper.FromJson(Of MmsgResult)(jsonString) If mresult.errcode = ReturnCode.请求成功 Then Functions.Execute("LogText","成功创建菜单!") msgbox("成功创建菜单!") Else Functions.Execute("LogText","创建菜单失败!错误代码: " & mresult.errcode & ";错误原因:" & mresult.errmsg) msgbox("创建菜单失败!错误代码: " & mresult.errcode & ";错误原因:" & mresult.errmsg) End If End Using End If 到这里,我们就完成实现了在Foxtable项目中通过微信接口创建公众号菜单的功能,关键点在于接口的调用和菜单Json的生成。 [此贴子已经被作者于2015/11/25 10:36:25编辑过]
|
|||||||||||||||||||
-- 作者:aduydgd -- 发布时间:2015/11/25 10:41:00 -- 好,不错, |
|||||||||||||||||||
-- 作者:李睿涵 -- 发布时间:2015/11/25 10:43:00 -- 好是好,看不懂。 |
|||||||||||||||||||
-- 作者:133198609 -- 发布时间:2015/11/25 10:47:00 -- 这个,也太强大了吧 |
|||||||||||||||||||
-- 作者:blackzhu -- 发布时间:2015/11/25 10:49:00 -- 看不懂 太好了就不行了 为啥你创建表的界面跟我们不一样? |
|||||||||||||||||||
-- 作者:狐狸爸爸 -- 发布时间:2015/11/25 10:52:00 -- 以下是引用blackzhu在2015/11/25 10:49:00的发言:
看不懂 太好了就不行了 为啥你创建表的界面跟我们不一样?
最终我们会提供完整的方案和实例。 如果你有公众号,照着做就行了。 [此贴子已经被作者于2015/11/25 10:53:45编辑过]
|
|||||||||||||||||||
-- 作者:blackzhu -- 发布时间:2015/11/25 10:55:00 -- 等待中 |