温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

微信公众号开发之如何实现自动消息回复和自定义菜单

发布时间:2021-09-10 11:46:37 来源:亿速云 阅读:210 作者:小新 栏目:移动开发

这篇文章主要为大家展示了“微信公众号开发之如何实现自动消息回复和自定义菜单 ”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“微信公众号开发之如何实现自动消息回复和自定义菜单 ”这篇文章吧。

消息回复

处理请求,并响应

1)关注

也可参考官网文档:https://mp.weixin.qq.com/wiki

当微信用户关注公众账号时,可以给其适当的提示。可以是欢迎词,可以是帮助提示。示例代码如下:

 class EventHandler : IHandler     {        /// <summary>         /// 请求的xml        /// </summary>         private string RequestXml { get; set; }        /// <summary>         /// 构造函数        /// </summary>         /// <param name="requestXml"></param>         public EventHandler(string requestXml)         {            this.RequestXml = requestXml;         }        /// <summary>         /// 处理请求        /// </summary>         /// <returns></returns>         public string HandleRequest()         {            string response = string.Empty;             EventMessage em = EventMessage.LoadFromXml(RequestXml);            if (em.Event.Equals("subscribe",StringComparison.OrdinalIgnoreCase))             {                //回复欢迎消息                 TextMessage tm = new TextMessage();                 tm.ToUserName = em.FromUserName;                 tm.FromUserName = em.ToUserName;                 tm.CreateTime = Common.GetNowTime();                 tm.Content = "欢迎您关注我们,我是服务小二,有事您开口~\n\n";                 response = tm.GenerateContent();             }            return response;         }     }

官方给出的介绍是这样的

关注/取消关注事件

用户在关注与取消关注公众号时,微信会把这个事件推送到开发者填写的URL。方便开发者给用户下发欢迎消息或者做帐号的解绑。

微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。

关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。

假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

推送XML数据包示例:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[FromUser]]></FromUserName> <CreateTime>123456789</CreateTime> <MsgType><![CDATA[event]]></MsgType> <Event><![CDATA[subscribe]]></Event> </xml>

参数说明:

参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,subscribe(订阅)、unsubscribe(取消订阅)

也可使用微信在线接口调试工具测试是否正常:取消/关注事件接口在线调试

2)问候

简单的交流问候,比如你好、帮助等等,跟我们使用微信聊天一样,不过回应是由我们的程序响应。具体功能,可以根据自己的需要进行添加。
微信本来就是沟通的平台。这个案例,可以用于在线服务机器人,类似于淘宝的客服机器人,可是我们这个是微信版的。
其实,很简单,获取请求消息,根据关键字来匹配回应。当然这里可能要做的工作很多,如何支持智能匹配,如何支持模糊匹配等。

 /// <summary>     /// 文本信息处理类    /// </summary>     public class TextHandler : IHandler     {        /// <summary>         /// 请求的XML        /// </summary>         private string RequestXml { get; set; }        /// <summary>         /// 构造函数        /// </summary>         /// <param name="requestXml">请求的xml</param>         public TextHandler(string requestXml)         {            this.RequestXml = requestXml;         }        /// <summary>         /// 处理请求        /// </summary>         /// <returns></returns>         public string HandleRequest()         {            string response = string.Empty;             TextMessage tm = TextMessage.LoadFromXml(RequestXml);            string content = tm.Content.Trim();            if (string.IsNullOrEmpty(content))             {                 response = "您什么都没输入,没法帮您啊,%>_<%。";             }            else             {                if (content.StartsWith("tq", StringComparison.OrdinalIgnoreCase))                 {                    string cityName = content.Substring(2).Trim();                     response = WeatherHelper.GetWeather(cityName);                 }                else                 {                     response = HandleOther(content);                 }             }             tm.Content = response;            //进行发送者、接收者转换             string temp = tm.ToUserName;             tm.ToUserName = tm.FromUserName;             tm.FromUserName = temp;             response = tm.GenerateContent();            return response;         }        /// <summary>         /// 处理其他消息        /// </summary>         /// <param name="tm"></param>         /// <returns></returns>         private string HandleOther(string requestContent)         {            string response = string.Empty;            if (requestContent.Contains("你好") || requestContent.Contains("您好"))             {                 response = "您也好~";             }            else if (requestContent.Contains("傻"))             {                 response = "我不傻!哼~ ";             }            else if (requestContent.Contains("shit") || requestContent.Contains("小王八蛋"))             {                 response = "哼,你说脏话! ";             }            else if (requestContent.Contains("是谁"))             {                 response = "我是大哥大,有什么能帮您的吗?~";             }            else if (requestContent.Contains("再见"))             {                 response = "再见!";             }            else if (requestContent.Contains("bye"))             {                 response = "Bye!";             }            else if (requestContent.Contains("谢谢"))             {                 response = "不客气!嘿嘿";             }            else if (requestContent == "h" || requestContent == "H" || requestContent.Contains("帮助"))             {                 response = @"有事找警察";             }            else             {                 response = "您说的,可惜,我没明白啊,试试其他关键字吧。";             }            return response;         }     }

实现效果如图所示:

微信公众号开发之如何实现自动消息回复和自定义菜单

自定义菜单

首先呢,我们要了解下微信公众号开发里面菜单有哪些类型呢?

自定义菜单接口可实现多种类型按钮,如下:

微信公众号开发之如何实现自动消息回复和自定义菜单

请注意,3到8的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。9和10,是专门给第三方平台旗下未微信认证(具体而言,是资质认证未通过)的订阅号准备的事件类型,它们是没有事件推送的,能力相对受限,其他类型的公众号不必使用。

接口调用请求说明

http请求方式:POST(请使用https协议) http://www.php.cn/

click和view的请求示例

 {     "button":[      {               "type":"click",          "name":"今日歌曲",          "key":"V1001_TODAY_MUSIC"       },       {           "name":"菜单",           "sub_button":[            {                    "type":"view",               "name":"搜索",               "url":"http://www.php.cn/"             },             {               "type":"view",               "name":"视频",               "url":"http://www.php.cn/"             },             {               "type":"click",               "name":"赞一下我们",               "key":"V1001_GOOD"             }]        }]  }

参数说明

参数是否必须说明
button一级菜单数组,个数应为1~3个
sub_button二级菜单数组,个数应为1~5个
type菜单的响应动作类型
name菜单标题,不超过16个字节,子菜单不超过60个字节
keyclick等点击类型必须菜单KEY值,用于消息接口推送,不超过128字节
urlview类型必须网页链接,用户点击菜单可打开链接,不超过1024字节
media_idmedia_id类型和view_limited类型必须调用新增永久素材接口返回的合法media_id

当然也可以使用在线调试接口调试菜单是否设置正确:我要在线调试菜单接口

详细步骤

1、首先获取access_token

access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。

公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在开发模式中获得(需要已经成为开发者,且帐号没有异常状态)。注意调用所有微信接口时均需使用https协议。

接口调用请求说明

http请求方式: GET https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

参数说明

参数是否必须说明
grant_type获取access_token填写client_credential
appid第三方用户唯一凭证
secret第三方用户唯一凭证密钥,既appsecret

返回说明

正常情况下,微信会返回下述JSON数据包给公众号:

{"access_token":"ACCESS_TOKEN","expires_in":7200}
参数说明
access_token获取到的凭证
expires_in凭证有效时间,单位:秒

错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{"errcode":40013,"errmsg":"invalid appid"}

创建自定义菜单

自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。

目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。请注意,创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来。建议测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。

3、查询菜单

使用接口创建自定义菜单后,开发者还可使用接口查询自定义菜单的结构。

请求说明

http请求方式:GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

返回说明

对应创建接口,正确的Json返回结果: {"menu":{"button":[{"type":"click","name":"今日歌曲","key":"V1001_TODAY_MUSIC","sub_button":[]},{"type":"click","name":"歌手简介","key":"V1001_TODAY_SINGER","sub_button":[]},{"name":"菜单","sub_button":[{"type":"view","name":"搜索","url":"http://www.soso.com/","sub_button":[]},{"type":"view","name":"视频","url":"http://v.qq.com/","sub_button":[]},{"type":"click","name":"赞一下我们","key":"V1001_GOOD","sub_button":[]}]}]}}

4、删除菜单

使用接口创建自定义菜单后,开发者还可使用接口删除当前使用的自定义菜单。

请求说明

http请求方式:GET https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN

返回说明

对应创建接口,正确的Json返回结果: {"errcode":0,"errmsg":"ok"}

5、事件处理

用户点击自定义菜单后,如果菜单按钮设置为click类型,则微信会把此次点击事件推送给开发者,注意view类型(跳转到URL)的菜单点击不会上报。

推送XML数据包示例:

<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[FromUser]]></FromUserName> <CreateTime>123456789</CreateTime> <MsgType><![CDATA[event]]></MsgType> <Event><![CDATA[CLICK]]></Event> <EventKey><![CDATA[EVENTKEY]]></EventKey> </xml>

参数说明:

参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,CLICK
EventKey事件KEY值,与自定义菜单接口中KEY值对应

实例讲解

我们将会在上一篇的基础上,添加自定义菜单的功能

1、获取access_token

首先需要得到AppId和AppSecret

当你成为开发者后,自然能够在,开发者模式,便可看到这两个值,可以重置。

然后调用按照二.1中所示,进行操作。

注意:access_token有过期时间,如果过期,需要重新获取。

private static DateTime GetAccessToken_Time;         /// <summary>         /// 过期时间为7200秒         /// </summary>         private static int Expires_Period = 7200;         /// <summary>         ///          /// </summary>         private static string mAccessToken;         /// <summary>         ///          /// </summary>         public static string AccessToken         {             get             {                 //如果为空,或者过期,需要重新获取                 if (string.IsNullOrEmpty(mAccessToken) || HasExpired())                 {                     //获取                     mAccessToken = GetAccessToken(AppID, AppSecret);                 }                 return mAccessToken;             }         }         /// <summary>         ///          /// </summary>         /// <param name="appId"></param>         /// <param name="appSecret"></param>         /// <returns></returns>         private static string GetAccessToken(string appId, string appSecret)         {             string url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, appSecret);             string result = HttpUtility.GetData(url);             XDocument doc = XmlUtility.ParseJson(result, "root");             XElement root = doc.Root;             if (root != null)             {                 XElement access_token = root.Element("access_token");                 if (access_token != null)                 {                     GetAccessToken_Time = DateTime.Now;                     if (root.Element("expires_in")!=null)                     {                         Expires_Period = int.Parse(root.Element("expires_in").Value);                     }                     return access_token.Value;                 }                 else                 {                     GetAccessToken_Time = DateTime.MinValue;                 }             }             return null;         }         /// <summary>         /// 判断Access_token是否过期         /// </summary>         /// <returns>bool</returns>         private static bool HasExpired()         {             if (GetAccessToken_Time != null)             {                 //过期时间,允许有一定的误差,一分钟。获取时间消耗                 if (DateTime.Now > GetAccessToken_Time.AddSeconds(Expires_Period).AddSeconds(-60))                 {                     return true;                 }             }             return false;         }

2、设置菜单

菜单需根据需要,按照实际要求进行设定。

这里我们只做简单的演示。

然后还提供了友情链接,这里提供了view类型的菜单,直接可以跳转至URL页面,为跳转做个好的演示。

具体菜单如下:

{     "button": [         {             "name": "测试跳转",              "sub_button": [                 {                     "type": "view",                      "name": "搜索",                      "url": "http://www.baidu.com/"                 },                  {                     "type": "view",                      "name": "视频",                      "url": "http://v.qq.com/"                 },                  {                     "type": "click",                      "name": "赞一下我们",                      "key": "BTN_GOOD"                 }             ]         },          {             "type": "view",             "name": "设备状态",              "url": "http://vanrui.com/weixin"         },          {             "type": "click",              "name": "帮助",              "key": "BTN_HELP"         }     ] }

3、管理菜单

因为菜单的变更没有那么频繁,因此通过txt文件来设置菜单,并通过管理界面来管理菜单。

主要的管理功能:

1)从文件加载菜单

2)创建菜单。即将菜单通知微信服务端,并更新至微信客户端

3)查询菜单。获取当前系统的菜单。

4)删除菜单。从微信服务器删除菜单,也可以删除后再创建。

实现代码如下:

public class MenuManager     {        /// <summary>         /// 菜单文件路径        /// </summary>         private static readonly string Menu_Data_Path = System.AppDomain.CurrentDomain.BaseDirectory + "/Data/menu.txt";        /// <summary>         /// 获取菜单        /// </summary>         public static string GetMenu()         {            string url = string.Format("http://www.php.cn/{0}", Context.AccessToken);            return HttpUtility.GetData(url);         }        /// <summary>         /// 创建菜单        /// </summary>         public static void CreateMenu(string menu)         {            string url = string.Format("http://www.php.cn/{0}", Context.AccessToken);            //string menu = FileUtility.Read(Menu_Data_Path);            HttpUtility.SendHttpRequest(url, menu);         }        /// <summary>         /// 删除菜单        /// </summary>         public static void DeleteMenu()         {            string url = string.Format("http://www.php.cn/{0}", Context.AccessToken);             HttpUtility.GetData(url);         }        /// <summary>         /// 加载菜单        /// </summary>         /// <returns></returns>         public static string LoadMenu()         {            return FileUtility.Read(Menu_Data_Path);         }     }

4、基本方法

上面的代码,其实我们对一些公共功能做了封装。如进行get请求、POST提交等操作,读取文件等。

这里我们提供进行get、Post提交的方法案例代码,如果使用,建议优化。

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Net;using System.Text;using System.Threading.Tasks;namespace WeChat.Utility {    /// <summary>     /// 帮助类    /// </summary>     class HttpUtility     {        /// <summary>         /// 发送请求        /// </summary>         /// <param name="url">Url地址</param>         /// <param name="data">数据</param>         public static string SendHttpRequest(string url, string data)         {            return SendPostHttpRequest(url, "application/x-www-form-urlencoded", data);         }        /// <summary>         ///          /// </summary>         /// <param name="url"></param>         /// <returns></returns>         public static string GetData(string url)         {            return SendGetHttpRequest(url, "application/x-www-form-urlencoded");         }        /// <summary>         /// 发送请求        /// </summary>         /// <param name="url">Url地址</param>         /// <param name="method">方法(post或get)</param>         /// <param name="method">数据类型</param>         /// <param name="requestData">数据</param>         public static string SendPostHttpRequest(string url, string contentType, string requestData)         {             WebRequest request = (WebRequest)HttpWebRequest.Create(url);             request.Method = "POST";            byte[] postBytes = null;             request.ContentType = contentType;             postBytes = Encoding.UTF8.GetBytes(requestData);             request.ContentLength = postBytes.Length;            using (Stream outstream = request.GetRequestStream())             {                 outstream.Write(postBytes, 0, postBytes.Length);             }            string result = string.Empty;            using (WebResponse response = request.GetResponse())             {                if (response != null)                 {                    using (Stream stream = response.GetResponseStream())                     {                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))                         {                             result = reader.ReadToEnd();                         }                     }                 }             }            return result;         }        /// <summary>         /// 发送请求        /// </summary>         /// <param name="url">Url地址</param>         /// <param name="method">方法(post或get)</param>         /// <param name="method">数据类型</param>         /// <param name="requestData">数据</param>         public static string SendGetHttpRequest(string url, string contentType)         {             WebRequest request = (WebRequest)HttpWebRequest.Create(url);             request.Method = "GET";             request.ContentType = contentType;            string result = string.Empty;            using (WebResponse response = request.GetResponse())             {                if (response != null)                 {                    using (Stream stream = response.GetResponseStream())                     {                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))                         {                             result = reader.ReadToEnd();                         }                     }                 }             }            return result;         }     } }
class XmlUtility     {        /// <summary>         ///          /// </summary>         /// <param name="json"></param>         /// <param name="rootName"></param>         /// <returns></returns>         public static XDocument ParseJson(string json,string rootName)         {            return JsonConvert.DeserializeXNode(json, rootName);         }     }

5、事件处理

设置了菜单,这下需要处理事件了。跟我们之前设计ASPX或者WinForm一样,都要绑定按钮的事件。这里只是通过XML消息将请求传递过来。

通过“2、设置菜单"中具体的菜单内容,我们便已经知道需要进行哪些事件处理了。对于按钮类型为view的,无须处理,它会自动跳转至指定url.

需要处理的点击事件:

1)赞一下

2)帮助

这个还要沿用上章中的事件处理器EventHandler来扩展处理。

具体的实现代码吧:

class EventHandler : IHandler     {         /// <summary>         /// 请求的xml         /// </summary>         private string RequestXml { get; set; }         /// <summary>         /// 构造函数         /// </summary>         /// <param name="requestXml"></param>         public EventHandler(string requestXml)         {             this.RequestXml = requestXml;         }         /// <summary>         /// 处理请求         /// </summary>         /// <returns></returns>         public string HandleRequest()         {             string response = string.Empty;             EventMessage em = EventMessage.LoadFromXml(RequestXml);             if (em != null)             {                 switch (em.Event.ToLower())                 {                     case ("subscribe"):                         response = SubscribeEventHandler(em);                         break;                     case "click":                         response = ClickEventHandler(em);                         break;                 }             }             return response;         }         /// <summary>         /// 关注         /// </summary>         /// <param name="em"></param>         /// <returns></returns>         private string SubscribeEventHandler(EventMessage em)         {             //回复欢迎消息             TextMessage tm = new TextMessage();             tm.ToUserName = em.FromUserName;             tm.FromUserName = em.ToUserName;             tm.CreateTime = Common.GetNowTime();             tm.Content = "欢迎您关注我们,我是服务小二,有事您说话~\n\n";             return tm.GenerateContent();         }         /// <summary>         /// 处理点击事件         /// </summary>         /// <param name="em"></param>         /// <returns></returns>         private string ClickEventHandler(EventMessage em)         {             string result = string.Empty;             if (em != null && em.EventKey != null)             {                 switch (em.EventKey.ToUpper())                 {                     case "BTN_GOOD":                         result = btnGoodClick(em);                         break;                     case "BTN_HELP":                         result = btnHelpClick(em);                         break;                 }             }             return result;         }         /// <summary>         /// 赞一下         /// </summary>         /// <param name="em"></param>         /// <returns></returns>         private string btnGoodClick(EventMessage em)         {             //回复欢迎消息             TextMessage tm = new TextMessage();             tm.ToUserName = em.FromUserName;             tm.FromUserName = em.ToUserName;             tm.CreateTime = Common.GetNowTime();             tm.Content = @"谢谢您的支持!";             return tm.GenerateContent();         }         /// <summary>         /// 帮助         /// </summary>         /// <param name="em"></param>         /// <returns></returns>         private string btnHelpClick(EventMessage em)         {             //回复欢迎消息             TextMessage tm = new TextMessage();             tm.ToUserName = em.FromUserName;             tm.FromUserName = em.ToUserName;             tm.CreateTime = Common.GetNowTime();             tm.Content = @"有事找警察~";             return tm.GenerateContent();         }
调试效果

图中点击的帮助菜单,如果大家仔细观察,会发现后面断点进入第二次了,这是因为前面提到的,微信服务器5秒未回复,就会重复尝试发3次请求,所以就会有多次进入断点的效果。

微信公众号开发之如何实现自动消息回复和自定义菜单

最终效果

微信公众号开发之如何实现自动消息回复和自定义菜单

以上是“微信公众号开发之如何实现自动消息回复和自定义菜单 ”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI