- update service/wechatoffice

master
李光春 2 years ago
parent 9ee6fe2dfa
commit d5c9af6d82

@ -1,78 +0,0 @@
package wechatoffice
import (
"go.dtapp.net/library/utils/golog"
"go.dtapp.net/library/utils/goredis"
"go.dtapp.net/library/utils/gorequest"
"gorm.io/gorm"
)
// App 微信公众号服务
type App struct {
appId string // 小程序唯一凭证,即 appId
appSecret string // 小程序唯一凭证密钥,即 appSecret
accessToken string // 接口调用凭证
jsapiTicket string // 签名凭证
redis goredis.App // 缓存数据库
db *gorm.DB // 令牌数据库
pgsql *gorm.DB // pgsql数据库
client *gorequest.App // 请求客户端
log *golog.Api // 日志服务
logTableName string // 日志表名
logStatus bool // 日志状态
}
// NewApp 实例化
func NewApp(appId, appSecret string, redis goredis.App, db *gorm.DB, pgsql *gorm.DB) *App {
app := &App{appId: appId, appSecret: appSecret, redis: redis, db: db}
app.client = gorequest.NewHttp()
if pgsql != nil {
app.pgsql = pgsql
app.logStatus = true
app.logTableName = "wechatoffice"
app.log = golog.NewApi(&golog.ApiConfig{
Db: pgsql,
TableName: app.logTableName,
})
}
return app
}
// Config 配置
func (app *App) Config(appId, appSecret string) *App {
app.appId = appId
app.appSecret = appSecret
return app
}
// 请求接口
func (app *App) request(url string, params map[string]interface{}, method string) (resp gorequest.Response, err error) {
// 创建请求
client := app.client
// 设置请求地址
client.SetUri(url)
// 设置方式
client.SetMethod(method)
// 设置格式
client.SetContentTypeJson()
// 设置参数
client.SetParams(params)
// 发起请求
request, err := client.Request()
if err != nil {
return gorequest.Response{}, err
}
// 日志
if app.logStatus == true {
go app.postgresqlLog(request)
}
return request, err
}

@ -27,10 +27,9 @@ func NewCgiBinTicketGetTicketResult(result CgiBinTicketGetTicketResponse, body [
// CgiBinTicketGetTicket 获取api_ticket
// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
func (app *App) CgiBinTicketGetTicket(Type string) *CgiBinTicketGetTicketResult {
app.accessToken = app.GetAccessToken()
func (c *Client) CgiBinTicketGetTicket(Type string) *CgiBinTicketGetTicketResult {
// request
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=%s", app.accessToken, Type), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=%s", c.getAccessToken(), Type), map[string]interface{}{}, http.MethodGet)
// 定义
var response CgiBinTicketGetTicketResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -7,16 +7,16 @@ import (
)
// GetJsapiTicketMonitor 监控api_ticket
func (app *App) GetJsapiTicketMonitor() (string, error) {
if app.redis.Db == nil {
func (c *Client) GetJsapiTicketMonitor() (string, error) {
if c.config.RedisClient.Db == nil {
return "", errors.New("驱动没有初始化")
}
result := app.DebugCgiBinTicketCheck()
result := c.DebugCgiBinTicketCheck()
if result.Result.Errcode == 0 {
return app.jsapiTicket, nil
return c.config.JsapiTicket, nil
}
app.accessToken = app.GetAccessToken()
token := app.CgiBinTicketGetTicket("jsapi")
app.redis.Db.Set(context.Background(), app.getJsapiTicketCacheKeyName(), token.Result.Ticket, time.Second*7000)
c.config.AccessToken = c.GetAccessToken()
token := c.CgiBinTicketGetTicket("jsapi")
c.config.RedisClient.Db.Set(context.Background(), c.getJsapiTicketCacheKeyName(), token.Result.Ticket, time.Second*7000)
return token.Result.Ticket, nil
}

@ -6,18 +6,18 @@ import (
)
// GetJsapiTicket 获取api_ticket
func (app *App) GetJsapiTicket() string {
if app.redis.Db == nil {
return app.jsapiTicket
func (c *Client) GetJsapiTicket() string {
if c.config.RedisClient.Db == nil {
return c.config.JsapiTicket
}
newCache := app.redis.NewSimpleStringCache(app.redis.NewStringOperation(), time.Second*7000)
newCache := c.config.RedisClient.NewSimpleStringCache(c.config.RedisClient.NewStringOperation(), time.Second*7000)
newCache.DBGetter = func() string {
token := app.CgiBinTicketGetTicket("jsapi")
token := c.CgiBinTicketGetTicket("jsapi")
return token.Result.Ticket
}
return newCache.GetCache(app.getJsapiTicketCacheKeyName())
return newCache.GetCache(c.getJsapiTicketCacheKeyName())
}
func (app *App) getJsapiTicketCacheKeyName() string {
return fmt.Sprintf("wechat_jsapi_ticket:%v", app.appId)
func (c *Client) getJsapiTicketCacheKeyName() string {
return fmt.Sprintf("wechat_jsapi_ticket:%v", c.getAppId())
}

@ -28,9 +28,9 @@ func NewCgiBinTokenResult(result CgiBinTokenResponse, body []byte, http goreques
// CgiBinToken
// 接口调用凭证
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
func (app *App) CgiBinToken() *CgiBinTokenResult {
func (c *Client) CgiBinToken() *CgiBinTokenResult {
// request
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", app.appId, app.appSecret), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", c.getAppId(), c.getAppSecret()), map[string]interface{}{}, http.MethodGet)
// 定义
var response CgiBinTokenResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -6,15 +6,15 @@ import (
"time"
)
func (app *App) GetAccessTokenMonitor() (string, error) {
if app.redis.Db == nil {
func (c *Client) GetAccessTokenMonitor() (string, error) {
if c.config.RedisClient.Db == nil {
return "", errors.New("驱动没有初始化")
}
result := app.GetCallBackIp()
result := c.GetCallBackIp()
if len(result.Result.IpList) > 0 {
return app.accessToken, nil
return c.config.AccessToken, nil
}
token := app.CgiBinToken()
app.redis.Db.Set(context.Background(), app.getAccessTokenCacheKeyName(), token.Result.AccessToken, time.Second*7000)
token := c.CgiBinToken()
c.config.RedisClient.Db.Set(context.Background(), c.getAccessTokenCacheKeyName(), token.Result.AccessToken, time.Second*7000)
return token.Result.AccessToken, nil
}

@ -5,18 +5,18 @@ import (
"time"
)
func (app *App) GetAccessToken() string {
if app.redis.Db == nil {
return app.accessToken
func (c *Client) GetAccessToken() string {
if c.config.RedisClient.Db == nil {
return c.config.AccessToken
}
newCache := app.redis.NewSimpleStringCache(app.redis.NewStringOperation(), time.Second*7000)
newCache := c.config.RedisClient.NewSimpleStringCache(c.config.RedisClient.NewStringOperation(), time.Second*7000)
newCache.DBGetter = func() string {
token := app.CgiBinToken()
token := c.CgiBinToken()
return token.Result.AccessToken
}
return newCache.GetCache(app.getAccessTokenCacheKeyName())
return newCache.GetCache(c.getAccessTokenCacheKeyName())
}
func (app *App) getAccessTokenCacheKeyName() string {
return fmt.Sprintf("wechat_access_token:%v", app.appId)
func (c *Client) getAccessTokenCacheKeyName() string {
return fmt.Sprintf("wechat_access_token:%v", c.getAppId())
}

@ -29,10 +29,9 @@ func NewCgiBinUserGetResult(result CgiBinUserGetResponse, body []byte, http gore
// CgiBinUserGet 获取用户列表
// https://developers.weixin.qq.com/doc/offiaccount/User_Management/Getting_a_User_List.html
func (app *App) CgiBinUserGet(nextOpenid string) *CgiBinUserGetResult {
app.accessToken = app.GetAccessToken()
func (c *Client) CgiBinUserGet(nextOpenid string) *CgiBinUserGetResult {
// 请求
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s", app.accessToken, nextOpenid), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s", c.getAccessToken(), nextOpenid), map[string]interface{}{}, http.MethodGet)
// 定义
var response CgiBinUserGetResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -39,10 +39,9 @@ func NewCgiBinUserInfoResult(result CgiBinUserInfoResponse, body []byte, http go
// CgiBinUserInfo 获取用户基本信息(UnionID机制)
// https://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonId
func (app *App) CgiBinUserInfo(openid string) *CgiBinUserInfoResult {
app.accessToken = app.GetAccessToken()
func (c *Client) CgiBinUserInfo(openid string) *CgiBinUserInfoResult {
// 请求
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN", app.accessToken, openid), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN", c.getAccessToken(), openid), map[string]interface{}{}, http.MethodGet)
// 定义
var response CgiBinUserInfoResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -0,0 +1,83 @@
package wechatoffice
import (
"go.dtapp.net/library/utils/dorm"
"go.dtapp.net/library/utils/golog"
"go.dtapp.net/library/utils/gorequest"
"gorm.io/gorm"
)
type ConfigClient struct {
AppId string // 小程序唯一凭证,即 appId
AppSecret string // 小程序唯一凭证密钥,即 appSecret
AccessToken string // 接口调用凭证
JsapiTicket string // 签名凭证
RedisClient *dorm.RedisClient // 缓存数据库
TokenDb *gorm.DB // 令牌数据库
PgsqlDb *gorm.DB // pgsql数据库
}
// Client 微信公众号服务
type Client struct {
client *gorequest.App // 请求客户端
log *golog.Api // 日志服务
logTableName string // 日志表名
logStatus bool // 日志状态
config *ConfigClient // 配置
}
func NewClient(config *ConfigClient) *Client {
c := &Client{config: config}
c.client = gorequest.NewHttp()
if c.config.PgsqlDb != nil {
c.logStatus = true
c.logTableName = "wechatoffice"
c.log = golog.NewApi(&golog.ApiConfig{
Db: c.config.PgsqlDb,
TableName: c.logTableName,
})
}
return c
}
// ConfigApp 配置
func (c *Client) ConfigApp(appId, appSecret string) *Client {
c.config.AppId = appId
c.config.AppSecret = appSecret
return c
}
// 请求接口
func (c *Client) request(url string, params map[string]interface{}, method string) (resp gorequest.Response, err error) {
// 创建请求
client := c.client
// 设置请求地址
client.SetUri(url)
// 设置方式
client.SetMethod(method)
// 设置格式
client.SetContentTypeJson()
// 设置参数
client.SetParams(params)
// 发起请求
request, err := client.Request()
if err != nil {
return gorequest.Response{}, err
}
// 日志
if c.logStatus == true {
go c.postgresqlLog(request)
}
return request, err
}

@ -25,10 +25,9 @@ func NewDebugCgiBinTicketCheckResult(result DebugCgiBinTicketCheckResponse, body
// DebugCgiBinTicketCheck 判断ticket是否合法
// https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
func (app *App) DebugCgiBinTicketCheck() *DebugCgiBinTicketCheckResult {
app.jsapiTicket = app.GetJsapiTicket()
func (c *Client) DebugCgiBinTicketCheck() *DebugCgiBinTicketCheckResult {
// 请求
request, err := app.request(fmt.Sprintf("https://mp.weixin.qq.com/debug/cgi-bin/ticket/check?ticket=%s", app.jsapiTicket), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://mp.weixin.qq.com/debug/cgi-bin/ticket/check?ticket=%s", c.getJsapiTicket()), map[string]interface{}{}, http.MethodGet)
// 定义
var response DebugCgiBinTicketCheckResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -1,5 +1,19 @@
package wechatoffice
func (app *App) GetAppId() string {
return app.appId
func (c *Client) getAppId() string {
return c.config.AppId
}
func (c *Client) getAppSecret() string {
return c.config.AppSecret
}
func (c *Client) getAccessToken() string {
c.config.AccessToken = c.GetAccessToken()
return c.config.AccessToken
}
func (c *Client) getJsapiTicket() string {
c.config.JsapiTicket = c.GetJsapiTicket()
return c.config.JsapiTicket
}

@ -25,10 +25,9 @@ func NewGetCallBackIpResult(result GetCallBackIpResponse, body []byte, http gore
// GetCallBackIp 获取微信callback IP地址
// callback IP即微信调用开发者服务器所使用的出口IP。
// https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_the_WeChat_server_IP_address.html#2.%20%E8%8E%B7%E5%8F%96%E5%BE%AE%E4%BF%A1callback%20IP%E5%9C%B0%E5%9D%80
func (app *App) GetCallBackIp() *GetCallBackIpResult {
app.accessToken = app.GetAccessToken()
func (c *Client) GetCallBackIp() *GetCallBackIpResult {
// 请求
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=%s", app.accessToken), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=%s", c.getAccessToken()), map[string]interface{}{}, http.MethodGet)
// 定义
var response GetCallBackIpResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -26,12 +26,11 @@ func NewMessageTemplateSendResult(result MessageTemplateSendResponse, body []byt
// MessageTemplateSend 模板消息
// https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html
func (app *App) MessageTemplateSend(notMustParams ...Params) *MessageTemplateSendResult {
app.accessToken = app.GetAccessToken()
func (c *Client) MessageTemplateSend(notMustParams ...Params) *MessageTemplateSendResult {
// 参数
params := app.NewParamsWith(notMustParams...)
params := c.NewParamsWith(notMustParams...)
// 请求
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s", app.accessToken), params, http.MethodPost)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response MessageTemplateSendResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -7,9 +7,9 @@ import (
// Oauth2 用户同意授权获取code
// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0
func (app *App) Oauth2(redirectUri, state string) string {
func (c *Client) Oauth2(redirectUri, state string) string {
param := url.Values{}
param.Add("appid", app.appId) // 公众号的唯一标识
param.Add("appid", c.getAppId()) // 公众号的唯一标识
param.Add("redirect_uri", redirectUri) // 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
param.Add("response_type", "code") // 返回类型
param.Add("scope", "snsapi_userinfo") // 应用授权作用域

@ -8,7 +8,7 @@ func NewParams() Params {
return p
}
func (app *App) NewParamsWith(params ...Params) Params {
func (c *Client) NewParamsWith(params ...Params) Params {
p := make(Params)
for _, v := range params {
p.SetParams(v)

@ -8,8 +8,8 @@ import (
)
// 记录日志
func (app *App) postgresqlLog(request gorequest.Response) {
app.log.Record(golog.ApiPostgresqlLog{
func (c *Client) postgresqlLog(request gorequest.Response) {
c.log.Record(golog.ApiPostgresqlLog{
RequestTime: golog.TimeString{Time: request.RequestTime}, //【请求】时间
RequestUri: request.RequestUri, //【请求】链接
RequestUrl: gorequest.UriParse(request.RequestUri).Url, //【请求】链接

@ -26,15 +26,15 @@ func NewShareResult(result ShareResponse, err error) *ShareResult {
return &ShareResult{Result: result, Err: err}
}
func (app *App) Share(url string) *ShareResult {
app.accessToken = app.GetAccessToken()
app.jsapiTicket = app.GetJsapiTicket()
func (c *Client) Share(url string) *ShareResult {
c.getAccessToken()
c.config.JsapiTicket = c.GetJsapiTicket()
var response ShareResponse
response.AppId = app.appId
response.AppId = c.getAppId()
response.NonceStr = gorandom.Alphanumeric(32)
response.Timestamp = time.Now().Unix()
response.Url = url
response.RawString = fmt.Sprintf("jsapi_ticket=%v&noncestr=%v&timestamp=%v&url=%v", app.jsapiTicket, response.NonceStr, response.Timestamp, response.Url)
response.RawString = fmt.Sprintf("jsapi_ticket=%v&noncestr=%v&timestamp=%v&url=%v", c.config.JsapiTicket, response.NonceStr, response.Timestamp, response.Url)
t := sha1.New()
_, err := io.WriteString(t, response.RawString)
response.Signature = fmt.Sprintf("%x", t.Sum(nil))

@ -2,7 +2,7 @@ package wechatoffice
import "errors"
func (app *App) pkcs7Unpaid(data []byte, blockSize int) ([]byte, error) {
func (c *Client) pkcs7Unpaid(data []byte, blockSize int) ([]byte, error) {
if blockSize <= 0 {
return nil, errors.New("invalid block size")
}

@ -26,9 +26,9 @@ func NewSnsJsCode2sessionResult(result SnsJsCode2sessionResponse, body []byte, h
return &SnsJsCode2sessionResult{Result: result, Body: body, Http: http, Err: err}
}
func (app *App) SnsJsCode2session(jsCode string) *SnsJsCode2sessionResult {
func (c *Client) SnsJsCode2session(jsCode string) *SnsJsCode2sessionResult {
// 请求
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", app.appId, app.appSecret, jsCode), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", c.getAppId(), c.getAppSecret(), jsCode), map[string]interface{}{}, http.MethodGet)
// 定义
var response SnsJsCode2sessionResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -28,9 +28,9 @@ func NewSnsOauth2AccessTokenResult(result SnsOauth2AccessTokenResponse, body []b
// SnsOauth2AccessToken 通过code换取网页授权access_token
// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0
func (app *App) SnsOauth2AccessToken(code string) *SnsOauth2AccessTokenResult {
func (c *Client) SnsOauth2AccessToken(code string) *SnsOauth2AccessTokenResult {
// 请求
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", app.appId, app.appSecret, code), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", c.getAppId(), c.getAppSecret(), code), map[string]interface{}{}, http.MethodGet)
// 定义
var response SnsOauth2AccessTokenResponse
err = json.Unmarshal(request.ResponseBody, &response)

@ -32,9 +32,9 @@ func NewSnsUserinfoResult(result SnsUserinfoResponse, body []byte, http goreques
// SnsUserinfo 拉取用户信息(需scope为 snsapi_userinfo)
// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0
func (app *App) SnsUserinfo(accessToken, openid string) *SnsUserinfoResult {
func (c *Client) SnsUserinfo(accessToken, openid string) *SnsUserinfoResult {
// 请求
request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN", accessToken, openid), map[string]interface{}{}, http.MethodGet)
request, err := c.request(fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN", accessToken, openid), map[string]interface{}{}, http.MethodGet)
// 定义
var response SnsUserinfoResponse
err = json.Unmarshal(request.ResponseBody, &response)

Loading…
Cancel
Save