go语言微信公众号开发后台接口封装

时间:2022-07-22
本文章向大家介绍go语言微信公众号开发后台接口封装,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

个人整理的小功能,把微信公众号开发涉及的一些常用接口做了个封装。

业余时间做了个有意思的小功能,每天早上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:%#vn", 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%sn", 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:%sn", 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("==>HandleWxLoginn")
	echostr := c.DefaultQuery("echostr", "")
	if echostr != "" {
		fmt.Printf("==>echostr:%sn", echostr)
		c.String(200, "%s", echostr)
		return
	}

}

// HandleWxPostRecv 处理微信公众号前端发起的消息事件
func HandleWxPostRecv(c *gin.Context) {
	fmt.Printf("==>HandleWxPostRecv Entern")
	data, err := c.GetRawData()
	if err != nil {
		log.Fatalln(err)
	}
	ReceiveCommonMsg(data)
}

// HandleWxGetOpenid
func HandleWxGetOpenid(c *gin.Context) {
	fmt.Printf("==>HandleWxGetOpenid Entern")
	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 Entern")
	opid := c.Query("openid")
	fmt.Printf("openid:%sn", 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)
	}
}