个人整理的小功能,把微信公众号开发涉及的一些常用接口做了个封装。
业余时间做了个有意思的小功能,每天早上7点准时给发天气预报,每晚8点发布一条英语说说,提醒自己不能忘记学习。
封装实现的功能有:
开发者首次接入、
创建菜单、
删除菜单、
发送模板消息、
接收公众号前端推送、
获取Token,获取关注者信息,
获取用户个人信息,
根据code获取个人信息(微信前端第三方应用页面接入授权会涉及。)
这里再介绍下微信前端第三方应用如何获取微信个人openid和个人信息的功能实现思路。
如何在微信前端开发的应用界面,获取用户openid和个人信息呢?方法还是有的,思路靠谱。
就是文档里描述的那几步授权操作,先获取code,再跳转,后台获取在传给前端。
附代码封装:
// WxReceiveCommonMsg 接收普通消息 type WxReceiveCommonMsg struct { ToUserName string //接收者 开发者 微信号 FromUserName string //发送者 发送方帐号(一个OpenID) Content string //文本内容 CreateTime int64 //创建时间 MsgType string //消息类型 MsgId int64 //消息id PicUrl string //图片url MediaId string //媒体id Event string //事件类型,VIEW EventKey string //事件KEY值,设置的跳转URL MenuId string Format string Recognition string ThumbMediaId string //缩略图媒体ID } // WxReceiveFunc (接收到消息之后,会将消息交于这个函数处理) var WxReceiveFunc func(msg WxReceiveCommonMsg) error // WxMakeSign 计算签名 func WxMakeSign(token, timestamp, nonce string) string { strs := []string{token, timestamp, nonce} sort.Strings(strs) sha := sha1.New() io.WriteString(sha, strings.Join(strs, "")) return fmt.Sprintf("%x", sha.Sum(nil)) } // WxGetAccessToken 获取微信accesstoken func WxGetAccessToken() string { url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%v&secret=%v", APPID, APPSECRET) resp, err := http.Get(url) if err != nil { fmt.Println("获取微信token失败", err) return "" } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("微信token读取失败", err) return "" } token := token{} err = json.Unmarshal(body, &token) if err != nil { fmt.Println("微信token解析json失败", err) return "" } return token.AccessToken } // WxGetUserList 获取关注者列表 func WxGetUserList(accessToken string) []gjson.Result { url := "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken + "&next_openid=" resp, err := http.Get(url) if err != nil { fmt.Println("获取关注列表失败", err) return nil } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("读取内容失败", err) return nil } flist := gjson.Get(string(body), "data.openid").Array() return flist } // WxPostTemplate 发送模板消息 func WxPostTemplate(accessToken string, reqdata string, fxurl string, templateid string, openid string) { url := "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken reqbody := "{\"touser\":\"" + openid + "\", \"template_id\":\"" + templateid + "\", \"url\":\"" + fxurl + "\", \"data\": " + reqdata + "}" fmt.Printf("WxPostTemplate:%#v\n", reqbody) resp, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(string(reqbody))) if err != nil { fmt.Println(err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println(err) return } fmt.Println(string(body)) } // ReceiveCommonMsg func ReceiveCommonMsg(msgData []byte) (WxReceiveCommonMsg, error) { fmt.Printf("received weixin msgData:\n%s\n", msgData) msg := WxReceiveCommonMsg{} err := xml.Unmarshal(msgData, &msg) if WxReceiveFunc == nil { return msg, err } err = WxReceiveFunc(msg) return msg, err } // WxCreateMenu 创建菜单 func WxCreateMenu(accessToken, menustr string) (string, error) { url := "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken fmt.Printf("WxCreateMenu:%s\n", menustr) resp, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(menustr)) if err != nil { fmt.Println(err) return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println(err) return "", err } fmt.Println(string(body)) return string(body), nil } // WxDelMenu 删除菜单 func WxDelMenu(accessToken string) (string, error) { url := "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=" + accessToken resp, err := http.Get(url) if err != nil { fmt.Println("删除菜单失败", err) return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("读取内容失败", err) return "", err } fmt.Println(string(body)) return string(body), nil } // WxGetUserInfo 根据用户openid获取基本信息 func WxGetUserInfo(accessToken, openid string) (string, error) { url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN", accessToken, openid) fmt.Println(url) resp, err := http.Get(url) if err != nil { fmt.Println("获取信息失败", err) return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("读取内容失败", err) return "", err } fmt.Println(string(body)) return string(body), nil } // WxGetOpenidByCode 微信前端页面授权之后,会给前端页面路由里带一个code func WxGetOpenidByCode(code string) (string, error) { url := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", APPID, APPSECRET, code) resp, err := http.Get(url) if err != nil { fmt.Println("获取openid失败", err) return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("读取内容失败", err) return "", err } fmt.Println(string(body)) return string(body), nil } // web API接口 // HandleWxLogin首次接入,成为开发者 func HandleWxLogin(c *gin.Context) { fmt.Printf("==>HandleWxLogin\n") echostr := c.DefaultQuery("echostr", "") if echostr != "" { fmt.Printf("==>echostr:%s\n", echostr) c.String(200, "%s", echostr) return } } // HandleWxPostRecv 处理微信公众号前端发起的消息事件 func HandleWxPostRecv(c *gin.Context) { fmt.Printf("==>HandleWxPostRecv Enter\n") data, err := c.GetRawData() if err != nil { log.Fatalln(err) } ReceiveCommonMsg(data) } // HandleWxGetOpenid func HandleWxGetOpenid(c *gin.Context) { fmt.Printf("==>HandleWxGetOpenid Enter\n") code := c.Query("code") result, err := WxGetOpenidByCode(code) if err != nil { c.JSON(http.StatusOK, gin.H{ "code": -1, "msg": "获取openid失败" + err.Error(), }) return } //WxDelMenu(accessToken) c.JSON(http.StatusOK, gin.H{ "code": 0, "msg": "成功", "data": result, }) } // HandleWxGetUserInfo 根据前端请求来的openid获取用户信息 func HandleWxGetUserInfo(c *gin.Context) { fmt.Printf("==>HandleWxGetUserInfo Enter\n") opid := c.Query("openid") fmt.Printf("openid:%s\n", opid) token := WxGetAccessToken() result, err := WxGetUserInfo(token, opid) if err != nil { c.JSON(http.StatusOK, gin.H{ "code": -1, "msg": "获取用户信息失败" + err.Error(), }) return } //WxDelMenu(accessToken) c.JSON(http.StatusOK, gin.H{ "code": 0, "msg": "成功", "data": result, }) } func init() { }
每日一句,每天发布一条英语句子,接口如下:
/** 每日一句api接口 */ package apis import ( "encoding/json" "fmt" "github.com/tidwall/gjson" "io/ioutil" "net/http" "weixin/wxapi" ) // SentTemplateID 每日一句的模板ID var SentTemplateID = "Xhh6e2zuKbTXlplpMezHLkHuNIF0X1_ScJT3K3hi4wg" // sentence 句子结构 type sentence struct { Content string `json:"content"` Note string `json:"note"` Translation string `json:"translation"` } // GetSay 获取每日一句 func GetSay() (sentence, string) { resp, err := http.Get("http://open.iciba.com/dsapi/?date") sent := sentence{} if err != nil { fmt.Println("获取每日一句失败", err) return sent, "" } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("读取内容失败", err) return sent, "" } err = json.Unmarshal(body, &sent) if err != nil { fmt.Println("每日一句解析json失败") return sent, "" } fenxiangurl := gjson.Get(string(body), "fenxiang_img").String() fmt.Println(sent) return sent, fenxiangurl } //SendEverydaySay 发送每日一句 func SendEverydaySay() { req, fxurl := GetSay() if req.Content == "" { return } accessToken := wxapi.WxGetAccessToken() if accessToken == "" { return } flist := wxapi.WxGetUserList(accessToken) if flist == nil { return } reqdata := "{\"content\":{\"value\":\"" + req.Content + "\", \"color\":\"#0000CD\"}, \"note\":{\"value\":\"" + req.Note + "\"}, \"translation\":{\"value\":\"" + req.Translation + "\"}}" for _, v := range flist { wxapi.WxPostTemplate(accessToken, reqdata, fxurl, SentTemplateID, v.Str) } }