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

简介: 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:%#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)
  }
}


相关文章
|
8天前
|
人工智能 JavaScript 定位技术
微信的接口都有哪些?
【10月更文挑战第17天】微信的接口都有哪些?
85 43
|
22天前
|
JSON 小程序 应用服务中间件
微信的接口wxLogin()的返回值都有什么?
【10月更文挑战第4天】微信的接口wxLogin()的返回值都有什么?
96 1
|
3月前
|
缓存 弹性计算 API
用 Go 快速开发一个 RESTful API 服务
用 Go 快速开发一个 RESTful API 服务
|
14天前
|
JSON 前端开发 API
使用微信JS-SDK调用发票接口的完整开发指南
本文介绍了如何使用微信JS-SDK的`chooseInvoiceTitle`接口来调用微信的发票功能。通过微信发票接口,用户可以选择开具个人或单位发票,并获取相关发票信息,如抬头、税号、公司地址等。在文中,详细描述了JS-SDK的初始化、发票接口的调用方式,并提供了完整的代码示例。文章还介绍了如何处理返回的发票信息,帮助开发者快速集成微信发票功能。
58 2
|
3月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
120 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
3月前
|
小程序 数据安全/隐私保护
Taro@3.x+Vue@3.x+TS开发微信小程序,网络请求封装
在 `src/http` 目录下创建 `request.ts` 文件,并配置 Taro 的网络请求方法 `Taro.request`,支持多种 HTTP 方法并处理数据加密。
Taro@3.x+Vue@3.x+TS开发微信小程序,网络请求封装
|
3月前
|
小程序 JavaScript Java
微信小程序+SpringBoot接入后台服务,接口数据来自后端
这篇文章介绍了如何将微信小程序与SpringBoot后端服务进行数据交互,包括后端接口的编写、小程序获取接口数据的方法,以及数据在小程序中的展示。同时,还涉及到了使用Vue搭建后台管理系统,方便数据的查看和管理。
微信小程序+SpringBoot接入后台服务,接口数据来自后端
|
3月前
|
算法 NoSQL 中间件
go语言后端开发学习(六) ——基于雪花算法生成用户ID
本文介绍了分布式ID生成中的Snowflake(雪花)算法。为解决用户ID安全性与唯一性问题,Snowflake算法生成的ID具备全局唯一性、递增性、高可用性和高性能性等特点。64位ID由符号位(固定为0)、41位时间戳、10位标识位(含数据中心与机器ID)及12位序列号组成。面对ID重复风险,可通过预分配、动态或统一分配标识位解决。Go语言实现示例展示了如何使用第三方包`sonyflake`生成ID,确保不同节点产生的ID始终唯一。
go语言后端开发学习(六) ——基于雪花算法生成用户ID
|
3月前
|
JSON 缓存 监控
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
Viper 是一个强大的 Go 语言配置管理库,适用于各类应用,包括 Twelve-Factor Apps。相比仅支持 `.ini` 格式的 `go-ini`,Viper 支持更多配置格式如 JSON、TOML、YAML
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
|
3月前
|
Go
使用 Go 发送微信群消息
使用 Go 发送微信群消息