在搞定使用golang快速开发微信公众平台(二):获取accessToken后,我们可以开始着手自定义菜单
开始搓代码
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": "公告","key": "molan_institution"
}]
},{
"name": "资料修改","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 := @H_339_301@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 @H_339_301@string) (*models.WxUserInfo,error) {
at := models.WxAccessToken{Id: 1}
o.ReadOrCreate(&at,"id")
requestLine := strings.@H_339_301@Join([]@H_339_301@string{wxUserInforUrl,at.AccessToken,"&openid=","&lang=zh_CN"},"")
resp,@H_339_301@err := http.Get(requestLine)
if @H_339_301@err != nil || resp.StatusCode != http.StatusOK {
fmt.Println("发送get请求获取 wxUserInfo 错误",@H_339_301@err)
logUtils.GetLog().Error("发送get请求获取 wxUserInfo 错误",@H_339_301@err)
return nil,@H_339_301@err
}
defer resp.Body.Close()
body,@H_339_301@err := IoUtil.ReadAll(resp.Body)
if @H_339_301@err != nil {
fmt.Println("发送get请求获取 wxUserInfo 读取返回body错误",@H_339_301@err)
logUtils.GetLog().Error("发送get请求获取 wxUserInfo 读取返回body错误",@H_339_301@err
}
if bytes.Contains(body,[]byte("errcode")) {
ater := models.AccessTokenErrorResponse{}
@H_339_301@err = json.Unmarshal(body,&ater)
if @H_339_301@err != nil {
fmt.Printf("发送get请求获取 wxUserInfo 的错误信息 %+v\n",ater)
logUtils.GetLog().Error("发送get请求获取 wxUserInfo 的错误信息 %+v\n",ater)
return nil,@H_339_301@err
}
return nil,fmt.Errorf("%s",ater.Errmsg)
} else {
atr := models.WxUserInfo{}
@H_339_301@err = json.Unmarshal(body,&atr)
if @H_339_301@err != nil {
fmt.Println("发送get请求获取 wxUserInfo 返回数据json解析错误",@H_339_301@err)
logUtils.GetLog().Error("发送get请求获取 wxUserInfo 返回数据json解析错误",@H_339_301@err)
return nil,0.0,@H_339_301@err
}
return &atr,nil
}
}
好了,我们现在拿到了用户的昵称头像,搞定收工