使用golang快速开发微信公众平台(三):定制菜单

u012210379 · · 1372 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

搞定使用golang快速开发微信公众平台(二):获取accessToken后,我们可以开始着手自定义菜单


这里写图片描述

自定义菜单简单粗暴,post请求里塞入要定义的菜单即可。

开始搓代码

func PushWxMenuCreate(accessToken string, menuJsonBytes []byte) error {

    postReq, err := http.NewRequest("POST",
        strings.Join([]string{"https://api.weixin.qq.com/cgi-bin/menu/create", "?access_token=", accessToken}, ""),
        bytes.NewReader(menuJsonBytes))

    if err != nil {
        fmt.Println("向微信发送菜单建立请求失败", err)
        logUtils.GetLog().Error("向微信发送菜单建立请求失败", err)
        return err
    }

    postReq.Header.Set("Content-Type", "application/json; encoding=utf-8")

    client := &http.Client{}
    resp, err := client.Do(postReq)
    if err != nil {
        fmt.Println("client向微信发送菜单建立请求失败", err)
        logUtils.GetLog().Error("client向微信发送菜单建立请求失败", err)
        return err
    } else {
        fmt.Println("向微信发送菜单建立成功")
    }
    defer resp.Body.Close()

    return nil
}

func createWxMenu(o orm.Ormer) {

    //btn1 := models.Btn{Name: "进入商城", Url: "http://www.baidu.com/", Btype: "view"}
    //btn2 := models.Btn{Name: "会员中心", Key: "molan_user_center", Btype: "click"}
    //btn3 := models.Btn{Name: "我的", Url: "http://www.baidu.com/user_view", Btype: "view"}
    //
    //btns := []models.Btn{btn1, btn2, btn3}
    //wxMenu := models.WxMenu{Button: btns}
    //menuJsonBytes, err := json.Marshal(wxMenu)

    menuStr := `{
            "button": [
            {
                "name": "进入商城",
                "type": "view",
                "url": "http://www.baidu.com/"
            },
            {

                "name":"管理中心",
                 "sub_button":[
                        {
                        "name": "用户中心",
                        "type": "click",
                        "key": "molan_user_center"
                        },
                        {
                        "name": "公告",
                        "type": "click",
                        "key": "molan_institution"
                        }]
            },
            {
                "name": "资料修改",
                "type": "view",
                "url": "http://www.baidu.com/user_view"
            }
            ]
        }`

    //if err == nil {

    //fmt.Println("生成的菜单json--->", menuStr)

    at := models.WxAccessToken{Id: 1}
    o.ReadOrCreate(&at, "id")
    //发送建立菜单的post请求
    WxPlatUtil.PushWxMenuCreate(at.AccessToken, []byte(menuStr))
    //} else {
    //  logUtils.GetLog().Error("微信菜单json转换错误", err)
    //}
}

使用struct来生成json收到了惨不忍睹的效果,于是我干脆粗暴的把json直接写出来传进去。。。

用户在点击菜单的时候,会把响应信息以post请求的方式发送到我们在服务器配置中填写的URL中去,即使用beego快速开发微信公众平台(一):开启服务器配置中的 /wx_connect。而这一点文档压根不提,如果你是上来就做的支付功能,做到这一步一定会问候文档作者的八辈祖宗。

好在我们机智的把支付功能放在了后面,并未对咱们的思路造成混乱,所以接下来还是无压力的。

当用户点击菜单,微信服务器会post过来一个xml,类似这样:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[VIEW]]></Event>
<EventKey><![CDATA[www.qq.com]]></EventKey>
<MenuId>MENUID</MenuId>
</xml>

我们可以找到是发给谁的(ToUserName) 哪个用户触发的(FromUserName) 通过什么方式触发的(Event EventKey),解析这个xml就行

都闪开 我要搓代码了:

WxConnect.go


//type WxMenuEvent struct {
//  ToUserName   string        `xml:"ToUserName"`
//  FromUserName string        `xml:"FromUserName"`
//  CreateTime   int64        `xml:"CreateTime"`
//  MsgType      string        `xml:"MsgType"`
//  Event        string        `xml:"Event"`        //VIEW  
//  EventKey     string        `xml:"EventKey"`
//  MenuId       string        `xml:"MenuId"`
//  ScanCodeInfo *ScanCodeInfo `xml:"ScanCodeInfo"` //专属于扫码
//  Content      string `xml:"Content"`
//  Ticket      string `xml:"Ticket"`
//}
//type ScanCodeInfo struct {
//  ScanType   string `xml:"ScanType"`
//  ScanResult string `xml:"ScanResult"`
//}
//微信菜单用户点击 扫码响应
func (c *WxConnectController) Post() {

    if bytes, err := ioutil.ReadAll(c.Ctx.Request.Body); err == nil {

        //解析xml
        wxEvent := new(models.WxMenuEvent)
        if err := xml.Unmarshal(bytes, wxEvent); err == nil {

            //处理菜单点击
            dealWithMenuEvent(&wxEvent)

        } else {
            fmt.Println("微信菜单用户点击、扫码响应错误", err)
        }
    } else {
        fmt.Println("微信菜单用户点击、扫码解析body错误", err)
    }

    c.EnableRender = false
}

func dealWithMenuEvent(wxEvent **models.WxMenuEvent){
    switch wxEvent.Event {
            case "VIEW"://说明是点击底部菜单栏进入商城页面
            case "CLICK"://点击按钮
                if strings.EqualFold(wxEvent.EventKey, "molan_user_center") {
                    //点击用户中心
                } else if strings.EqualFold(wxEvent.EventKey, "molan_institution") {
                    //点击公告
                }
            case "subscribe"://扫码

            if strings.Contains(wxEvent.EventKey, "qrscene") {
                //未关注过商城 扫描他人二维码首次关注
                upperId := strings.Split(wxEvent.EventKey, "_")[1]//EventKey:qrscene_16 这个16就是upper在数据库的id 注意不是wxid

            } else {
                //关注(扫官方二维码 而不是扫个人二维码)
            }


            case "SCAN"://已关注 扫描他人二维码
            }
}

这里扫码比较恶心,eventKey可以作为识别是当前用户扫哪个用户的码,qrscene_xxxx 这个xxxx是你自己设的,大家知道就行。
到这一步,响应基本算是走完了。

但是 GRD需求总是不放过我们

老板说了:我想知道是哪个用户点了某个按钮,然后根据不同用户给予不同的响应。
这就需要用到WxMenuEvent.FromUserName,这个FromUserName是用户openID,注意这玩意不是用户的微信号。

官网是这样写的:

这里写图片描述

快闪开我憋不住了:

func FetchWxInfoAndIcon(o orm.Ormer, openid, wxUserInforUrl string) (*models.WxUserInfo, error) {

    at := models.WxAccessToken{Id: 1}
    o.ReadOrCreate(&at, "id")

    requestLine := strings.Join([]string{wxUserInforUrl,
        "?access_token=",
        at.AccessToken,
        "&openid=",
        openid,
        "&lang=zh_CN"}, "")

    resp, err := http.Get(requestLine)
    if err != nil || resp.StatusCode != http.StatusOK {
        fmt.Println("发送get请求获取 wxUserInfo 错误", err)
        logUtils.GetLog().Error("发送get请求获取 wxUserInfo 错误", err)
        return nil, err
    }

    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("发送get请求获取 wxUserInfo 读取返回body错误", err)
        logUtils.GetLog().Error("发送get请求获取 wxUserInfo 读取返回body错误", err)
        return nil, err
    }

    if bytes.Contains(body, []byte("errcode")) {

        ater := models.AccessTokenErrorResponse{}
        err = json.Unmarshal(body, &ater)

        if err != nil {
            fmt.Printf("发送get请求获取 wxUserInfo 的错误信息 %+v\n", ater)
            logUtils.GetLog().Error("发送get请求获取 wxUserInfo 的错误信息 %+v\n", ater)
            return nil,  err
        }
        return nil, fmt.Errorf("%s", ater.Errmsg)

    } else {
        atr := models.WxUserInfo{}
        err = json.Unmarshal(body, &atr)
        if err != nil {
            fmt.Println("发送get请求获取 wxUserInfo 返回数据json解析错误", err)
            logUtils.GetLog().Error("发送get请求获取 wxUserInfo 返回数据json解析错误", err)
            return nil, 0.0, err
        }
        return &atr, nil
    }
}

好了,我们现在拿到了用户的昵称头像,搞定收工


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:u012210379

查看原文:使用golang快速开发微信公众平台(三):定制菜单

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

1372 次点击  
加入收藏 微博
下一篇:go test
1 回复  |  直到 2019-07-23 15:50:15
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传