当前位置:网站首页>Making wechat robot with go (I) sending messages
Making wechat robot with go (I) sending messages
2022-07-26 22:42:00 【apprentice.】
I'm studying these days Go, I also wrote several articles about reading Gin Back end project code blog . But programming this , Be sure to practice , Otherwise, it's all talk on paper . So I want to write some code to practice my hand . reasoning , I don't know what I can write to practice . And then it occurred to me , I've used it before Python Be a wechat chat robot ( Blog portal ), At that time, the code was not put git On , Later, the server was reset, causing the code to disappear . Now I just don't know what project to do to practice , It can be used Go It also realizes a set of wechat chat robots .
Do as you say , Follow the blog you wrote before , Look at the time Python Code for . Switch to Go Optimized and realized .

0. Review the process
According to the previous Python The robot that writes automatically sends messages knows , To send a message, you need three parameters :company_id、secret、angent_id. How to get these three parameters , Refer to the portal at the beginning of the article . The whole process of sending messages is First, through company_id and secret To call the interface to get token, Re pass token and angent_id To send to the corresponding interface post request , You can put the post The information in the request body is sent to wechat .
1. Project basic configuration
Due to the current demand for Go I'm not particularly proficient in learning the project layout , And for the basic part of the project, if you start from scratch , It takes a lot of time . So I use open source gin The method of secondary development of the project , To realize this robot .
I was studying the other day Gin when , I found an old brother who sealed a Gin The scaffold , It can be used out of the box . Project address : github Portal . Inside, read the configuration file , Write routing , Many operations such as connecting to the database have been realized . Therefore, we can carry out secondary development based on this project , Be a wechat robot .
Putting the project clone After the down , You can take a look at the layout of the whole project first , The main business core codes are placed in internal below . If we want to realize a function of actively sending messages to wechat , So much said is to write a method to send messages , Let the backend call this method .
To develop wechat robot based on this project , First, configure the three parameters . In the project , For various parameters, it is in config.yaml Middle configuration , Because the configuration of these three parameters can be added to this configuration file :
Then in the code config/autoload Add a new weCaht.go file , Receive the configuration in the configuration file .
package autoload
type WeChatConfig struct {
AgentId string `ini:"wechat" yaml:"agent_id"`
Secret string `ini:"wechat" yaml:"secret"`
CompanyId string `ini:"wechat" yaml:"company_id"`
}
var WeChat = WeChatConfig{
}
also , Add this configuration to the configuration collection of the project . stay config/config.go Add the following code to :
This operation , You can read the configuration file through code . In other packages , The corresponding values can be accessed in the following ways
config.Config.WeChat.CompanyId //yaml Medium company_id Field
2. Redis encapsulation
Because I want to send messages to wechat , First, get token, And the official introduction of this token The effective duration of is 2 Hours . Before Python In the project , Is directly to the token Written to the file , Read through file . In this project , I want to use it directly redis To store . Because use redis To store it , You can set key Value duration , After this time, it will be cleared automatically , This is much more convenient .
And we are based on this gin-layout In the project , Have been to redis Made a layer of encapsulation , Specific code can be viewed data/redis.go, Mainly by exposing a Rdb The structure of the body , To operate redis
At present, we use redis, Only the corresponding set and get Method . So I'm interested in redis Another layer of encapsulation . Exposure only set,get,del Method .
First of all, will Rdb Change the variable name to lowercase , This means no exposure , Then add the following code to this file
func SetRedis(key string, value string, t int64) bool {
expire := time.Duration(t) * time.Second
if err := rdb.Set(ctx, key, value, expire).Err(); err != nil {
return false
}
return true
}
func GetRedis(key string) string {
result, err := rdb.Get(ctx, key).Result()
if err != nil {
return ""
}
return result
}
func DelRedis(key string) bool {
_, err := rdb.Del(ctx, key).Result()
if err != nil {
return false
}
return true
}
such , Use later redis When , Just call data.SetRedis(xxx) that will do .
Then modify the configuration file , Enable redis, According to the actual redis Configure to write .
3. Message body encapsulation
Finally, send it to wechat server post When asked , The corresponding request body format is as follows :
{
"touser": "@all",
"msgtype": "text",
"agentid": "xxxxx",
"text": {
"content": "xxxx"}
}
therefore , Next, you can make a package for this structure . stay model It's a bag , Create a new one send_msg.go file
package model
type wcSendcontent struct {
Content string `json:"content"`
}
type WcSendMsg struct {
ToUser string `json:"touser"`
MsgType string `json:"msgtype"`
AgentId string `json:"agentid"`
Text wcSendcontent `json:"text"`
}
func (t *WcSendMsg) SetMessage(message string) {
t.Text.Content = message
}
Targeted here message Information , Specifically exposed a method to set .
4. Core code
In setting up redis, After the message body is encapsulated , You can write the core code . Mainly through sending http request , obtain token, Re pass token send out post Request to send a message . We can do it in service Create a new one under the package weChat.go The file of , Build a new one inside SendWeChat Method to send messages .
package service
import (
"bytes"
"encoding/json"
"errors"
"fmt"
c "github.com/wannanbigpig/gin-layout/config"
"github.com/wannanbigpig/gin-layout/data"
"github.com/wannanbigpig/gin-layout/internal/model"
log "github.com/wannanbigpig/gin-layout/internal/pkg/logger"
"github.com/wannanbigpig/gin-layout/pkg/utils"
"go.uber.org/zap"
)
/** * @description: Send messages to enterprises and micro enterprises * @param {string} message The message content * @param {string} msgType Message type * @return {*} */
func SendWeChat(message string, msgType string) error {
redis_key := "access_token"
// Try from redis Read from token
accessToken := data.GetRedis(redis_key)
http := &utils.HttpRequest{
}
// if redis Medium token Has expired , Then re request api obtain token
if accessToken == "" {
log.Logger.Info("access token is null, will recall")
getTokenUrl := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s",
c.Config.WeChat.CompanyId, c.Config.WeChat.Secret)
log.Logger.Info("token_url", zap.String("url", getTokenUrl))
http.Request("GET", getTokenUrl, nil)
ret := make(map[string]interface{
})
if err := http.ParseJson(&ret); err != nil {
return err
}
marshal, _ := json.Marshal(ret)
log.Logger.Info(string(marshal))
accessToken = fmt.Sprintf("%v", ret["access_token"])
// write in redis The period of validity 2 Hours
data.SetRedis(redis_key, accessToken, 7200)
}
msg := &model.WcSendMsg{
ToUser: "@all",
MsgType: msgType,
AgentId: c.Config.WeChat.AgentId,
}
msg.SetMessage(message)
sendMsgUrl := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%v", accessToken)
log.Logger.Info("sendMsgUrl = " + string(sendMsgUrl))
header := map[string]string{
"Content-Type": "application/json"}
bytesData, _ := json.Marshal(msg)
http.Request("POST", sendMsgUrl, bytes.NewReader(bytesData), header)
log.Logger.Info("bytes data = " + string(bytesData))
ret := make(map[string]interface{
})
err := http.ParseJson(&ret)
if err != nil {
return err
}
if ret["errcode"].(float64) != 0 {
errmsg := fmt.Sprintf("%v", ret["errmsg"])
return errors.New(errmsg)
}
return nil
}
As you can see from the code above , The first is through redis To get token, If not, request api obtain token, And write it to redis in , Valid for 2 Hours . Then generate a previously encapsulated message structure , take AgentId and message After filling , By sending post request , The purpose of sending messages has been achieved .
5. Local testing
If you want to verify this method , You can provide an external interface , Call the method of sending messages after accessing this interface .
Can be in controller Create a new one in the directory weChat.go, Implement a get Requested method , Get... In the request msg Parameters , Then call the method of sending enterprise and micro enterprise just implemented .
package wechat
import (
"github.com/gin-gonic/gin"
"github.com/wannanbigpig/gin-layout/internal/pkg/error_code"
log "github.com/wannanbigpig/gin-layout/internal/pkg/logger"
r "github.com/wannanbigpig/gin-layout/internal/pkg/response"
"github.com/wannanbigpig/gin-layout/internal/service"
)
func SendMsg(c *gin.Context) {
msg, ok := c.GetQuery("msg")
if !ok {
msg = "please input message"
}
log.Logger.Info("send wechat message: " + msg)
err := service.SendWeChat(msg, "text")
if err != nil {
r.Resp().FailCode(c, error_code.FAILURE, err.Error())
return
}
r.Success(c, "success")
}
After writing , Bind this method to the route . stay routers Create a new one under the package weChatRouter.go file
package routers
import (
"github.com/gin-gonic/gin"
w "github.com/wannanbigpig/gin-layout/internal/controller/wechat"
)
func setWeChatRouter(r *gin.Engine) {
// version 1
v1 := r.Group("wechat")
{
v1.GET("/send", w.SendMsg)
}
}
such , You can use wechat/send Of url To request this interface . Finally, call the method of this binding route , stay routers/router.go Add a line of code to 
Then start the project , For example, send a msg=Hello,Golang Request
curl --location --request GET "http://${IP}:${PORT}/wechat/send?msg=Hello,Golang"
Execute this command , You can get the screenshot at the beginning of this article .
Of course , This api The interface is mainly for us to verify , When the actual project runs , It is suggested not to do this . Because this interface has no authentication measures , If it is exposed , Then others can also arbitrarily call this interface to send messages to your enterprise .
边栏推荐
- VCs compilation and simulation process
- IDEA的那些环境配置及插件
- Embedded sig | distributed soft bus
- Xu Li, CEO of Shangtang Technology: the company's valuation has exceeded $7billion, so we are not in a hurry to go public
- DAO 的发展状态
- 动态规划之线性DP
- 推动ARM服务器芯片替代X86,华为、飞腾扛起国产化大旗!
- APP信息侦察&夜神模拟器Burp抓包配置
- Development status of Dao
- 顺序表实现
猜你喜欢

Matlab solution of the densest stacking and smallest circumscribed square of N circles (two-dimensional, three-dimensional, etc. circle packing problem)

Write golang simple C2 remote control based on grpc

三星Galaxy Z可折叠产品的预告片泄露:'柔性好于平面'

Use ECs and OSS to set up personal network disk

Spend 120 billion to build a "subway" to connect 4 trillion cities. What is Guangdong thinking?

A few pictures help you clarify "China's financial institution system"

Linear DP of dynamic programming

NVIDIA SMI error: NVIDIA SMI has failed because it could't communicate with the NVIDIA driver complete record

STM32 how to use serial port
![[hcip] OSPF route calculation](/img/1c/ee9eee2e723b850c401f7cddda1b27.png)
[hcip] OSPF route calculation
随机推荐
ZTE: more than 50000 5g base stations have been shipped worldwide!
【HCIP】OSPF 路由计算
Height collapse caused by floating
Luo Xu talks with Siemens wanghaibin: advanced manufacturing requires benefits from Digitalization
Plato farm is expected to further expand its ecosystem through elephant swap
The trailer of Samsung Galaxy Z foldable product leaked: 'flexibility is better than plane'
Embedded SIG | 分布式软总线
麒麟990系列为何无缘Cortex-A77和Mali G77?
Liepin questionnaire star has become a "parasite" on wechat
[IO Development Notes] smart cloud intelligent watering device practice (3) - automatic code generation and transplantation
毕业5年,从信息管理转行软件测试工程师,我的月薪终于突破了12k
面试 必备
『Mysql』汇总Mysql索引失效的常见场景
【论文阅读】LOGAN:Membership Inference Attacks Against Generative Models
Matlab solution of the densest stacking and smallest circumscribed square of N circles (two-dimensional, three-dimensional, etc. circle packing problem)
Internet celebrity spicy bars can't catch young people
DAO 的发展状态
Financial institution map
让程序在一秒或者多秒中做一件事情
what is qrc in qt