Commit b0fa14c1 by zhengqiuyun86

初始化

parent 4b323e54
package rym_util
import "fmt"
func Add() {
fmt.Println("add test1")
}
package PagePlus
import (
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
"git.168cad.top/zhengqiuyun/rym-util/a/page"
"git.168cad.top/zhengqiuyun/rym-util/a/util"
"gorm.io/gorm"
)
func Page(params []page.Param, pageNum int, pageSize int, m interface{}, data interface{}, orderBy string, db *gorm.DB) *page.Data {
var page = page.Data{}
page.PageSize = util.IfInt(pageSize == 0, 10, pageSize)
page.PageNum = util.IfInt(pageNum == 0, 1, pageNum)
tx := db.Session(&gorm.Session{PrepareStmt: true})
countTx := tx.Model(&m).Select("count(1)")
if params != nil {
for _, p := range params {
countTx.Where(p.Column+" "+p.Op+" ?", p.Value)
}
}
resultCount := countTx.Scan(&page.Total)
if resultCount.Error != nil {
exception.ThrowsErr(resultCount.Error)
}
if page.Total > 0 {
dataTx := tx.Model(&m).Offset((page.PageNum - 1) * page.PageSize).Limit(page.PageSize).Order(orderBy)
if params != nil {
for _, p := range params {
dataTx.Where(p.Column+" "+p.Op+" ?", p.Value)
}
}
resultList := dataTx.Find(&data)
if resultList.Error != nil {
exception.ThrowsErr(resultList.Error)
}
page.List = data
}
return &page
}
package conf
type Config struct {
ENV string
}
func BaseConfig(conf Config) {
ENV = conf.ENV
}
var ENV = "test"
var ServerName = "git.168cad.top/zhengqiuyun/rym-util"
var DBType = "mysql"
var EsHttpHost = "http://192.168.1.124:9200"
//mysql
var DbDSN = "root:dcrym29210924..@tcp(192.168.1.37:3306)/duocaihui_dev?charset=utf8mb4&parseTime=True&loc=Local"
//ShowSql 是否打印SQL
var ShowSql = true //是否打印SQL
var LogLevel = "Debug"
var HttpServerPort = "8080"
var WhiteListIp = [...]string{"::1", "192.168.71.127", "171.88.67.133"}
var WhiteListUri = [...]string{"/swagger", "/api/app/login/get/captcha",
"/api/app/login/register/send/sms", "/api/app/login/register",
"/api/app/login/forget/pwd/send/sms", "/api/app/login/forget/pwd",
"/api/app/login/login",
"/api/app/wx/login/bind/check", "/api/app/wx/login/bind/send/sms",
"/api/app/wx/login/bind", "/api/app/wx/login", "/pay/wx/pay/notify"}
var CheckSms = false
var SmsSendUrl = "http://192.168.1.43:9001"
var SmsVerifyUrl = "http://192.168.1.43:9001"
//LogColorful 日志是否开启彩色打印
var LogColorful = true
var LogResponseLength = 1000
var CaptchaMax = 5
package exception
import (
"errors"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"github.com/go-playground/validator/v10"
"reflect"
)
func ThrowsErr(err error) {
if err != nil {
log.Error(err.Error())
panic(err)
}
}
func ThrowsValid(err error, r interface{}) {
if err != nil {
switch err.(type) {
case validator.ValidationErrors:
e := (err).(validator.ValidationErrors)
errMsg := getError(e, r)
panic(errors.New(errMsg))
break
default:
panic(err)
break
}
}
}
// 自定义错误消息
func getError(errs validator.ValidationErrors, r interface{}) string {
s := reflect.TypeOf(r)
for _, fieldError := range errs {
filed, _ := s.FieldByName(fieldError.Field())
// 获取统一错误消息
errText := filed.Tag.Get("msg")
if errText != "" {
return errText
}
fieldName := filed.Tag.Get("json")
if fieldName == "" {
fieldName = fieldError.Field()
}
return fieldName + ":" + fieldError.Tag()
}
return ""
}
type DError struct {
Err string
}
func (e *DError) Error() string {
return e.Err
}
func ThrowsErrS(err string) {
if &err != nil && err != "" {
log.Error(err)
panic(DError{Err: err})
}
}
package catch
import (
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
"git.168cad.top/zhengqiuyun/rym-util/a/getWay"
"github.com/gin-gonic/gin"
"runtime"
"strings"
)
func ExceptionCatch(c *gin.Context) {
err := recover() //获取异常
if err != nil {
switch err.(type) {
case exception.DError:
e := (err).(exception.DError)
getWay.FailAndMsg(c, e.Error())
break
case error:
e := (err).(error)
if strings.Index(e.Error(), "duplicate key") > 0 {
getWay.FailAndMsg(c, "信息重复")
} else {
var buf [1024]byte
n := runtime.Stack(buf[:], true)
fmt.Println(string(buf[:]), n)
getWay.FailAndMsg(c, e.Error())
}
break
}
}
}
package generate
//TableInfo 需要生成的表,以逗号隔开
type TableInfo struct {
Group string //分组,将生成的文件归纳在该目录
PK string //主键信息
ModelName string //模型名,如果没有以表名Camel格式生成
IgnoreRouterPrefixL int //忽略前缀的长度
GenerateApiParams bool //是否生成dao
GenerateResponse bool //是否生成dao
GenerateDao bool //是否生成dao
GenerateService bool //是否生成service
GenerateApi bool //是否生成api
AutoGenerateID bool //是否自动生成ID
}
const DBType = "Mysql"
const CreateTime = "create_time"
const UpdateTime = "update_time"
const Handler = "handler"
//NameSpace 生成的表空间
//const NameSpace = "duocaihui_dev"
const NameSpace = "duocaihui_dev"
//Tables 需要生成的表配置
var DoTables = map[string]TableInfo{
//"u_customer":{Group:"customer", PK:"id",AutoGenerateID:true,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_account":{Group:"customer", PK:"customer_id,area_id,account_type",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_account_bill":{Group:"customer", PK:"",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_app_login_info":{Group:"customer", PK:"customer_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: false,GenerateResponse: false},
//"u_app_wx_login_info":{Group:"customer", PK:"open_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: false,GenerateResponse: false},
//"u_hardware_login_info":{Group:"customer", PK:"customer_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_id_bar":{Group:"customer", PK:"customer_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_card_offline":{Group:"customer", PK:"customer_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_app_info":{Group:"customer", PK:"customer_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_feedback":{Group:"customer", PK:"id",AutoGenerateID:true,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_recharge_apply":{Group:"customer", PK:"order_no",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_recharge":{Group:"customer", PK:"order_no",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_card_recharge":{Group:"customer", PK:"card_number",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_recharge_out":{Group:"customer", PK:"out_order_no",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_bean_give":{Group:"customer", PK:"",AutoGenerateID:true,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_bean_deduct":{Group:"customer", PK:"",AutoGenerateID:true,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_consume_prepay":{Group:"customer", PK:"order_no",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_consume_unpaid":{Group:"customer", PK:"order_no",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_consume":{Group:"customer", PK:"order_no",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_consume_equipment":{Group:"customer", PK:"order_no,side",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_area_change":{Group:"customer", PK:"id",AutoGenerateID:true,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_area_change_account_item":{Group:"customer", PK:"",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_refund_apply":{Group:"customer", PK:"apply_no",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_refund_apply_detail":{Group:"customer", PK:"",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_order_refund":{Group:"customer", PK:"order_no",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_login_record":{Group:"customer", PK:"",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"u_area_cross":{Group:"customer", PK:"customer_id,cross_area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//
//"b_service":{Group:"base", PK:"id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_payment":{Group:"base", PK:"pay_type",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_payment_business":{Group:"base", PK:"pay_type,business_type",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_operate_company":{Group:"base", PK:"id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area":{Group:"base", PK:"id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: true,GenerateApiParams: true,IgnoreRouterPrefixL: 1,GenerateResponse: true},
//"b_area_service":{Group:"base", PK:"area_id,service_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_auth":{Group:"base", PK:"area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_prepay":{Group:"base", PK:"area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_prepay_service":{Group:"base", PK:"area_id,service_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_first_recharge":{Group:"base", PK:"area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_recharge":{Group:"base", PK:"area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_recharge_item":{Group:"base", PK:"id",AutoGenerateID:true,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_recharge_pay_type":{Group:"base", PK:"area_id,pay_type",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_register_give":{Group:"base", PK:"area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: true,GenerateApiParams: true,IgnoreRouterPrefixL: 1,GenerateResponse: true},
//"b_area_order_pay":{Group:"base", PK:"area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_order_pay_type":{Group:"base", PK:"area_id,pay_type",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_refund_config":{Group:"base", PK:"area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_public_wx_mini_ad":{Group:"base", PK:"area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"b_area_cross":{Group:"base", PK:"area_id,cross_area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//
//"app_page_block":{Group:"app", PK:"block_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_page_item":{Group:"app", PK:"item_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_page_item_c_android":{Group:"app", PK:"item_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_page_item_c_ios":{Group:"app", PK:"item_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_page_item_r_area":{Group:"app", PK:"item_code,area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_page_item_h5_detail":{Group:"app", PK:"item_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_table_plaque":{Group:"app", PK:"plaque_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_table_plaque_c_android":{Group:"app", PK:"plaque_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_table_plaque_c_ios":{Group:"app", PK:"plaque_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_table_plaque_r_area":{Group:"app", PK:"plaque_code,area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_open":{Group:"app", PK:"open_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_open_c_android":{Group:"app", PK:"open_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_open_c_ios":{Group:"app", PK:"open_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_open_r_area":{Group:"app", PK:"open_code,area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_notice":{Group:"app", PK:"notice_code",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_notice_r_area":{Group:"app", PK:"notice_code,area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_version_manage":{Group:"app", PK:"id",AutoGenerateID:true,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_version_manage_r_area":{Group:"app", PK:"version_manage_id,area_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_version_manage_r_customer":{Group:"app", PK:"version_manage_id,customer_id",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//"app_ad_hide":{Group:"app", PK:"customer_type",AutoGenerateID:false,GenerateModel: true,GenerateDao: true,GenerateService: false,GenerateApi: false,GenerateApiParams: true,IgnoreRouterPrefixL: 0,GenerateResponse: true},
//
//
//"wx_pay_order": {Group: "", PK: "out_trade_no", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"wx_merchant": {Group: "", PK: "mch_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"wx_app": {Group: "", PK: "app_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"wx_pay_area": {Group: "", PK: "area_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"wx_pay_jump_mini": {Group: "", PK: "app_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"ali_app": {Group: "", PK: "app_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
"ali_merchant": {Group: "", PK: "", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"ali_pay_area": {Group: "", PK: "area_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"ali_pay_jump_mini": {Group: "", PK: "app_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"ali_pay_order": {Group: "", PK: "out_trade_no", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"allin_merchant": {Group: "", PK: "biz_user_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"allin_merchant_bank_cards": {Group: "", PK: "id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"allin_pay_area": {Group: "", PK: "area_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"allin_pay_order": {Group: "", PK: "out_trade_no", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"allin_pay_sharing_account": {Group: "", PK: "area_id,bi_user_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"wx_pay_order_refund": {Group: "", PK: "out_refund_no", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"ali_pay_order_refund": {Group: "", PK: "out_refund_no", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"allin_pay_order_draw": {Group: "", PK: "draw_no", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"wx_transfer_area": {Group: "", PK: "area_id", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"wx_transfer_order": {Group: "", PK: "out_batch_no", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
//"wx_transfer_order_detail": {Group: "", PK: "out_detail_no", AutoGenerateID: false, GenerateDao: false, GenerateService: false, GenerateApi: false, GenerateApiParams: false, IgnoreRouterPrefixL: 0, GenerateResponse: false},
}
type TypeMap map[string]string
//DbToGoPG PG数据库类型映射成go类型
var DbToGoPG = TypeMap{
"int2": "uint8",
"int4": "uint32",
"varchar": "string",
"timestamp": "time.Time",
"bool": "bool",
"bpchar": "string",
"point": "string",
"inet": "string",
"text": "string",
"_varchar": "[]string",
}
//DbToGoMySql mysql数据库类型映射成go类型
var DbToGoMySql = TypeMap{
"bigint": "int64",
"int": "int32",
"tinyint": "int8",
"varchar": "string",
"text": "string",
"datetime": "time.Time",
"timestamp": "time.Time",
}
var ModelImportMap = TypeMap{
"timestamp": "time",
"datetime": "time",
"date": "time",
}
package generate
import (
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
"github.com/deckarep/golang-set"
"github.com/iancoleman/strcase"
"io"
"os"
"regexp"
"strings"
)
type Table struct {
Name string
Description string
}
type TableField struct {
FieldName string
FieldType string
Length int16
LengthVar int32
Notnull bool
Comment string
ColumnType string
}
//ProjectName 项目名称
const ProjectName = "git.168cad.top/zhengqiuyun/rym-util"
const PathSeparator = "\\"
const BasePackage = "pay"
const ModelReplace = true
const webPackageName = "web"
const servicePackageName = "service"
const daoPackageName = "dao"
const modelPackageName = "model"
func BuildPgModels() {
var tables []Table
if DBType == "PostgreSql" {
tables = AllTables()
} else {
tables = MysqlAllTables()
}
if len(DoTables) > 0 {
for i := 0; i < len(tables); i++ {
table := tables[i]
doTable, ok := DoTables[table.Name]
if ok {
var tableFields []TableField
if conf.DBType == "PostgreSql" {
tableFields = GetTableFiledByTableName(table.Name)
} else {
tableFields = MysqlGetTableFiledByTableName(table.Name)
}
if len(tableFields) > 0 {
generateModel(&table, tableFields, doTable)
if doTable.GenerateApiParams {
generateApiParams(&table, tableFields, doTable)
}
if doTable.GenerateResponse {
generateResponse(&table, doTable)
}
if doTable.GenerateDao {
generateDao(&table, tableFields, doTable)
}
if doTable.GenerateService {
generateService(&table, tableFields, doTable)
}
if doTable.GenerateApi {
generateApi(&table, tableFields, doTable)
}
}
}
}
}
}
func getModelImport(field TableField) string {
return ModelImportMap[field.FieldType]
}
func getModelFiledType(field TableField) string {
if conf.DBType == "PostgreSql" {
return DbToGoPG[field.FieldType]
} else {
if strings.Index(field.ColumnType, "unsigned") > 0 {
return "u" + DbToGoMySql[field.FieldType]
} else {
return DbToGoMySql[field.FieldType]
}
}
}
func getModelFieldOrm(field TableField, doTable TableInfo) string {
if strings.Contains(strings.ToLower(doTable.PK), strings.ToLower(field.FieldName)) {
return `gorm:"primaryKey:` + field.FieldName + `"`
} else {
return `gorm:"column:` + field.FieldName + `"`
}
}
//获取字段json描述
func getModelFieldJson(field TableField) string {
return `json:"` + strcase.ToLowerCamel(strings.ToLower(field.FieldName)) + `,omitempty"`
}
//获取字段说明
func getModelFieldComment(field TableField) string {
if len(field.Comment) > 0 {
return "// " + field.Comment
}
return ""
}
func getModelName(tableName string, doTable TableInfo) string {
if doTable.ModelName == "" {
return strcase.ToCamel(strings.ToLower(tableName))
} else {
return doTable.ModelName
}
}
//生成Model
func generateModel(table *Table, fields []TableField, doTable TableInfo) {
modelName := getModelName(table.Name, doTable)
packageStr := "package " + modelPackageName + "\n\n"
importPs := mapset.NewSet()
content := ""
//表注释
if len(table.Description) > 0 {
content += "// " + modelName + " " + table.Description + "\n"
}
content += "type " + modelName + " struct {\n"
columnsStruct := "type " + modelName + "ColumnsStruct struct {\n"
columns := "var " + modelName + "Columns = " + modelName + "ColumnsStruct{\n"
//生成字段
for _, field := range fields {
//字段名
fieldName := strcase.ToCamel(strings.ToLower(field.FieldName))
//根据字段 获取对应的字段的类型
fieldType := getModelFiledType(field)
//根据字段 获取对应的字段的Orm 表字段信息
fieldOrm := getModelFieldOrm(field, doTable)
//根据字段 获取对应的JSON tag 信息
fieldJson := getModelFieldJson(field)
//根据字段 获取对应的备注信息
fieldComment := getModelFieldComment(field)
importP := getModelImport(field)
if importP != "" && !importPs.Contains(importP) {
importPs.Add(importP)
}
content += "\t" + fieldName + " *" + fieldType + " `" + fieldOrm + " " + fieldJson + "` " + fieldComment + "\n"
columnsStruct += "\t" + fieldName + " string\n"
columns += "\t" + fieldName + " : \"" + field.FieldName + "\",\n"
}
content += "}\n"
columnsStruct += "}\n"
columns += "}\n"
importStr := ""
if importPs.Cardinality() > 0 {
importStr = "import (\n"
for val := range importPs.Iterator().C {
importStr += " \"" + (val).(string) + "\"\n"
}
importStr += ")\n\n"
}
//表名
tableName := "func (" + modelName + ") TableName() string {\n return \"" + table.Name + "\"\n}\n\n"
fileContent := packageStr + importStr + tableName + content + columnsStruct + columns
createOrReplaceFile(BasePackage, modelPackageName, doTable.Group, "", modelName, fileContent)
}
//生成dao
func generateDao(table *Table, fields []TableField, doTable TableInfo) {
projectName := ProjectName
modelName := getModelName(table.Name, doTable)
packageStr := "package " + daoPackageName + "\n\n"
haveCreateAt := false
haveUpdateAt := false
var pks []TableField
updateTimeFieldName := strcase.ToCamel(strings.ToLower(UpdateTime))
createTimeFieldName := strcase.ToCamel(strings.ToLower(CreateTime))
orderBy := make(map[string]string)
for j := 0; j < len(fields); j++ {
field := fields[j]
if strings.Contains(doTable.PK, field.FieldName) {
pks = append(pks, field)
}
if strings.ToLower(field.FieldName) == CreateTime {
orderBy[field.FieldName] = "DESC"
haveCreateAt = true
}
if strings.ToLower(field.FieldName) == UpdateTime {
haveUpdateAt = true
}
}
create := ""
if doTable.Group == "" {
create += "func Create" + modelName + "(m *model." + modelName + ") *model." + modelName + " {\n"
} else {
create += "func Create" + modelName + "(m *" + doTable.Group + "Model." + modelName + ") *" + doTable.Group + "Model." + modelName + " {\n"
}
if haveCreateAt || haveUpdateAt {
create += "\tvar now = time.Now()\n"
}
if haveCreateAt {
create += "\tm." + createTimeFieldName + " = &now\n"
}
if haveUpdateAt {
create += "\tm." + updateTimeFieldName + " = &now\n"
}
create += "\tresult := db.GetPgDb().Create(&m)\n"
create += "\tif result.Error != nil {\n"
create += "\t\texception.ThrowsErr(result.Error)\n"
create += "\t}\n"
create += "\treturn m\n"
create += "}\n"
updateByPrimaryKey := ""
findByPrimaryKey := ""
if len(pks) > 0 {
pkParams := ""
pkFields := ""
for j := 0; j < len(pks); j++ {
field := pks[j]
pkParams += strcase.ToLowerCamel(strings.ToLower(field.FieldName)) + " " + getModelFiledType(field) + ", "
pkFields += strcase.ToCamel(field.FieldName) + ": &" + strcase.ToLowerCamel(strings.ToLower(field.FieldName)) + ", "
orderBy[field.FieldName] = "DESC"
}
pkParams = pkParams[0 : len(pkParams)-2]
pkFields = pkFields[0 : len(pkFields)-2]
if doTable.Group == "" {
findByPrimaryKey += "func Find" + modelName + "ByPrimaryKey(" + pkParams + ") (m *model." + modelName + ") {\n"
findByPrimaryKey += "\tresult := db.GetPgDb().Where(model." + modelName + "{" + pkFields + "}).First(&m)\n"
} else {
findByPrimaryKey += "func Find" + modelName + "ByPrimaryKey(" + pkParams + ") (m *" + doTable.Group + "Model." + modelName + ") {\n"
findByPrimaryKey += "\tresult := db.GetPgDb().Where(" + doTable.Group + "Model." + modelName + "{" + pkFields + "}).First(&m)\n"
}
findByPrimaryKey += "\tif result.Error != nil {\n"
findByPrimaryKey += "\t\tif errors.Is(result.Error, gorm.ErrRecordNotFound) {\n"
findByPrimaryKey += "\t\t\treturn nil\n"
findByPrimaryKey += "\t\t} else {\n"
findByPrimaryKey += "\t\t\texception.ThrowsErr(result.Error)\n"
findByPrimaryKey += "\t\t}\n"
findByPrimaryKey += "\t}\n"
findByPrimaryKey += "\treturn m\n"
findByPrimaryKey += "}\n"
if doTable.Group == "" {
updateByPrimaryKey += "func Update" + modelName + "ByPrimaryKey(m *model." + modelName + ") int64 {\n"
} else {
updateByPrimaryKey += "func Update" + modelName + "ByPrimaryKey(m *" + doTable.Group + "Model." + modelName + ") int64 {\n"
}
if haveUpdateAt {
updateByPrimaryKey += "\tvar now = time.Now()\n"
updateByPrimaryKey += "\tm." + updateTimeFieldName + " = &now\n"
}
updateByPrimaryKey += "\tresult := db.GetPgDb().Updates(m)\n"
updateByPrimaryKey += "\tif result.Error != nil {\n"
updateByPrimaryKey += "\t\texception.ThrowsErr(result.Error)\n"
updateByPrimaryKey += "\t}\n"
updateByPrimaryKey += "\treturn result.RowsAffected\n"
updateByPrimaryKey += "}\n"
}
pageQuery := "func Page" + modelName + "(params []page.Param,pageNum int,pageSize int) *page.Data {\n"
orderByP := ""
if len(orderBy) > 0 {
orderByStr := ""
for k, v := range orderBy {
orderByStr += " + model." + modelName + "Columns." + strcase.ToCamel(k) + " + \" " + v + ",\""
}
pageQuery += "\torderBy := " + orderByStr[3:len(orderByStr)-2] + "\"\n"
orderByP = ", orderBy"
} else {
pageQuery += "\torderBy := \"\""
}
if doTable.Group == "" {
pageQuery += "\treturn PagePlus.Page(params,pageNum,pageSize,&model." + modelName + "{},[] model." + modelName + "{}" + orderByP + ",db.GetPgDb())\n"
} else {
pageQuery += "\treturn PagePlus.Page(params,pageNum,pageSize,&" + doTable.Group + "." + modelName + "{},[]" + doTable.Group + "." + modelName + "{}" + orderByP + ",db.GetPgDb())\n"
}
pageQuery += "}\n"
importStr := "import (\n"
importStr += "\t\"" + projectName + "/a/PagePlus\"\n"
if conf.DBType == "" {
importStr += "\t\"" + projectName + "/a/db\"\n"
} else {
importStr += "\t\"" + projectName + "/a/db/" + conf.DBType + "\"\n"
}
importStr += "\t\"" + projectName + "/a/exception\"\n"
importStr += "\t\"" + projectName + "/a/page\"\n"
if doTable.Group == "" {
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + modelPackageName + "\"\n"
} else {
importStr += "\t" + doTable.Group + "Model \"" + projectName + "/" + BasePackage + "/" + modelPackageName + "/" + doTable.Group + "\"\n"
}
if len(pks) > 0 {
importStr += "\t\"errors\"\n"
importStr += "\t\"gorm.io/gorm\"\n"
}
if haveCreateAt || haveUpdateAt {
importStr += "\t\"time\"\n"
}
importStr += ")\n"
fileContent := packageStr + importStr + create + updateByPrimaryKey + findByPrimaryKey + pageQuery
createOrReplaceFile(BasePackage, daoPackageName, doTable.Group, "", modelName, fileContent)
}
//生成Api相关params
func generateApiParams(table *Table, fields []TableField, doTable TableInfo) {
projectName := ProjectName
modelName := getModelName(table.Name, doTable)
packageStr := "package params\n\n"
importStr := ""
createParams := "type " + modelName + "AddParams struct {\n"
updateParams := "type " + modelName + "UpdateParams struct {\n"
pageParams := "type " + modelName + "PageParams struct {\n" +
"\tpage.ParamPage\n"
importPs := mapset.NewSet(projectName + "/a/page")
for _, field := range fields {
//字段名
fieldName := strcase.ToCamel(strings.ToLower(field.FieldName))
//根据字段 获取对应的字段的类型
fieldType := getModelFiledType(field)
//根据字段 获取对应的JSON tag 信息
fieldJson := getModelFieldJson(field)
//根据字段 获取对应的备注信息
fieldComment := getModelFieldComment(field)
content := ""
content = "\t" + fieldName + " *" + fieldType + " `" + fieldJson + "` " + fieldComment + "\n"
if strings.Contains(doTable.PK, field.FieldName) {
if !doTable.AutoGenerateID {
createParams += content
}
updateParams += content
pageParams += content
} else if strings.ToLower(field.FieldName) == Handler ||
strings.ToLower(field.FieldName) == CreateTime ||
strings.ToLower(field.FieldName) == UpdateTime {
} else {
importP := getModelImport(field)
if importP != "" && !importPs.Contains(importP) {
importPs.Add(importP)
}
createParams += content
updateParams += content
pageParams += content
}
}
createParams += "}\n"
updateParams += "}\n"
pageParams += "}\n"
if importPs.Cardinality() > 0 {
importStr = "import (\n"
for val := range importPs.Iterator().C {
importStr += " \"" + (val).(string) + "\"\n"
}
importStr += ")\n\n"
}
fileContent := packageStr + importStr + createParams + updateParams + pageParams
createOrReplaceFile(BasePackage, webPackageName, doTable.Group, "params", modelName, fileContent)
}
//生成service
func generateService(table *Table, fields []TableField, doTable TableInfo) {
projectName := ProjectName
modelName := getModelName(table.Name, doTable)
packageStr := "package " + servicePackageName + "\n\n"
haveHandler := false
for _, field := range fields {
if strings.ToLower(field.FieldName) == Handler {
haveHandler = true
}
}
importStr := "import (\n"
importStr += "\t\"" + projectName + "/a/page\"\n"
if haveHandler {
importStr += "\t\"" + projectName + "/a/request\"\n"
}
importStr += "\t\"" + projectName + "/a/sqlOp\"\n"
if doTable.Group == "" {
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + daoPackageName + "\"\n"
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + modelPackageName + "\"\n"
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + webPackageName + "/params\"\n"
} else {
importStr += "\t" + doTable.Group + "Dao \"" + projectName + "/" + BasePackage + "/" + daoPackageName + "/" + doTable.Group + "\"\n"
importStr += "\t" + doTable.Group + "Model \"" + projectName + "/" + BasePackage + "/" + modelPackageName + "/" + doTable.Group + "\"\n"
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + webPackageName + "/" + doTable.Group + "/params\"\n"
}
if haveHandler {
importStr += "\t\"fmt\"\n"
importStr += "\t\"github.com/gin-gonic/gin\"\n"
}
importStr += ")\n"
addOne := ""
if haveHandler {
addOne += "func Add" + modelName + "(addParams params." + modelName + "AddParams, c *gin.Context) {\n"
} else {
addOne += "func Add" + modelName + "(addParams params." + modelName + "AddParams) {\n"
}
if doTable.Group == "" {
addOne += "\tvar m model." + modelName + "\n"
} else {
addOne += "\tvar m " + doTable.Group + "Model." + modelName + "\n"
}
updateByPrimaryKey := ""
if haveHandler {
updateByPrimaryKey += "func Update" + modelName + "(updateParams params." + modelName + "UpdateParams, c *gin.Context) {\n"
} else {
updateByPrimaryKey += "func Update" + modelName + "(updateParams params." + modelName + "UpdateParams) {\n"
}
if doTable.Group == "" {
updateByPrimaryKey += "\tvar m model." + modelName + "\n"
} else {
updateByPrimaryKey += "\tvar m " + doTable.Group + "Model." + modelName + "\n"
}
pageParams := "func buildParamsPage" + modelName + "(params *params." + modelName + "PageParams) []page.Param {\n"
pageParams += "\tvar daoParams []page.Param\n"
pageParams += "\t//Todo 根据实际情况拼分页查询条件\n"
if doTable.Group == "" {
pageParams += "\tvar column = &model." + modelName + "Columns\n"
} else {
pageParams += "\tvar column = &" + doTable.Group + "Model." + modelName + "Columns\n"
}
var pks []TableField
for _, field := range fields {
//字段名
fieldName := strcase.ToCamel(strings.ToLower(field.FieldName))
buildParams := false
if strings.Contains(doTable.PK, field.FieldName) {
buildParams = true
if !doTable.AutoGenerateID {
addOne += "\tm." + fieldName + "=addParams." + fieldName + "\n"
}
updateByPrimaryKey += "\tm." + fieldName + "=updateParams." + fieldName + "\n"
pks = append(pks, field)
} else if strings.ToLower(field.FieldName) == Handler {
addOne += "\tcurrentUser := request.GetCurrentUser(c)\n"
addOne += "\tvar handler = fmt.Sprintf(\"%s(%s)\",currentUser.Name,currentUser.Account)\n"
addOne += "\tm.Handler = &handler\n"
updateByPrimaryKey += "\tcurrentUser := request.GetCurrentUser(c)\n"
updateByPrimaryKey += "\tvar handler = fmt.Sprintf(\"%s(%s)\",currentUser.Name,currentUser.Account)\n"
updateByPrimaryKey += "\tm.Handler = &handler\n"
} else if strings.ToLower(field.FieldName) == CreateTime ||
strings.ToLower(field.FieldName) == UpdateTime {
} else {
addOne += "\tm." + fieldName + "=addParams." + fieldName + "\n"
updateByPrimaryKey += "\tm." + fieldName + "=updateParams." + fieldName + "\n"
buildParams = true
}
if buildParams {
pageParams +=
"\tif params." + fieldName + " != nil {\n" +
"\t\tdaoParams = append(daoParams, page.Param{Column: column." + fieldName + ", Op: sqlOp.Equal, Value: params." + fieldName + "})\n" +
"\t}\n"
}
}
if doTable.Group == "" {
addOne += "\tdao.Create" + modelName + "(&m)\n"
} else {
addOne += "\t" + doTable.Group + "Dao.Create" + modelName + "(&m)\n"
}
addOne += "}\n"
if doTable.Group == "" {
updateByPrimaryKey += "\tdao.Update" + modelName + "ByPrimaryKey(&m)\n"
} else {
updateByPrimaryKey += "\t" + doTable.Group + "Dao.Update" + modelName + "ByPrimaryKey(&m)\n"
}
updateByPrimaryKey += "}\n"
findByPrimaryKey := ""
if len(pks) > 0 {
pkParams := ""
pkFields := ""
for j := 0; j < len(pks); j++ {
field := pks[j]
pkParams += strcase.ToLowerCamel(strings.ToLower(field.FieldName)) + " " + getModelFiledType(field) + ", "
pkFields += strcase.ToLowerCamel(strings.ToLower(field.FieldName)) + ", "
}
pkParams = pkParams[0 : len(pkParams)-2]
pkFields = pkFields[0 : len(pkFields)-2]
if doTable.Group == "" {
findByPrimaryKey += "func Find" + modelName + "(" + pkParams + ") *model." + modelName + " {\n"
findByPrimaryKey += "\treturn dao.Find" + modelName + "ByPrimaryKey(" + pkFields + ")\n"
} else {
findByPrimaryKey += "func Find" + modelName + "(" + pkParams + ") *" + doTable.Group + "Model." + modelName + " {\n"
findByPrimaryKey += "\treturn " + doTable.Group + "Dao.Find" + modelName + "ByPrimaryKey(" + pkFields + ")\n"
}
findByPrimaryKey += "}\n"
}
pageQuery := "func Page" + modelName + "(params *params." + modelName + "PageParams) *page.Data {\n"
if doTable.Group == "" {
pageQuery += "\treturn dao.Page" + modelName + "(buildParamsPage" + modelName + "(params),params.PageNum,params.PageSize)\n"
} else {
pageQuery += "\treturn " + doTable.Group + "Dao.Page" + modelName + "(buildParamsPage" + modelName + "(params),params.PageNum,params.PageSize)\n"
}
pageQuery += "}\n"
pageParams += "\treturn daoParams\n"
pageParams += "}"
fileContent := ""
if len(pks) > 0 {
fileContent = packageStr + importStr + addOne + updateByPrimaryKey + findByPrimaryKey + pageQuery + pageParams
} else {
fileContent = packageStr + importStr + addOne + pageQuery + pageParams
}
createOrReplaceFile(BasePackage, servicePackageName, doTable.Group, "", modelName, fileContent)
}
//生成Api相关Response
func generateResponse(table *Table, doTable TableInfo) {
projectName := ProjectName
modelName := getModelName(table.Name, doTable)
packageStr := "package response\n\n"
importStr := "import (\n"
importStr += "\t\"" + projectName + "/a/getWay\"\n"
importStr += "\t\"" + projectName + "/a/page\"\n\n"
if doTable.Group == "" {
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + modelPackageName + "\"\n"
} else {
importStr += "\t" + doTable.Group + "Model \"" + projectName + "/" + BasePackage + "/" + modelPackageName + "/" + doTable.Group + "\"\n"
}
importStr += ")\n"
pageResponse := "type " + modelName + "PageResponse struct {\n"
pageResponse += "\tgetWay.ServerResponse\n"
pageResponse += "\tData " + modelName + "PageData `json:\"data\"`\n"
pageResponse += "}\n\n"
pageResponse += "type " + modelName + "PageData struct {\n"
pageResponse += "\tpage.Page\n"
if doTable.Group == "" {
pageResponse += "\tList []" + "model." + modelName + "\n"
} else {
pageResponse += "\tList []" + doTable.Group + "Model." + modelName + "\n"
}
pageResponse += "}\n"
fileContent := packageStr + importStr + pageResponse
createOrReplaceFile(BasePackage, webPackageName, doTable.Group, "response", modelName, fileContent)
}
func getApiPrefix(tableName string, ignoreRouterPrefixL int) string {
apiPrefix := "/" + BasePackage
reg := regexp.MustCompile(`(_)`)
tableApiPrefix := reg.ReplaceAllLiteralString(strings.ToLower(tableName), "/")
tableApiPrefix = tableApiPrefix[ignoreRouterPrefixL:]
if strings.Index(tableApiPrefix, "/") != 0 {
tableApiPrefix = "/" + tableApiPrefix
}
apiPrefix = apiPrefix + tableApiPrefix
return apiPrefix
}
//生成api
func generateApi(table *Table, fields []TableField, doTable TableInfo) {
projectName := ProjectName
modelName := getModelName(table.Name, doTable)
packageStr := "package " + webPackageName + "\n\n"
haveHandler := false
var pks []TableField
for _, field := range fields {
if strings.Contains(doTable.PK, field.FieldName) {
pks = append(pks, field)
}
if strings.ToLower(field.FieldName) == Handler {
haveHandler = true
}
}
importStr := "import (\n"
importStr += "\t\"" + projectName + "/a/exception\"\n"
importStr += "\t\"" + projectName + "/a/exception/catch\"\n"
importStr += "\t\"" + projectName + "/a/getWay\"\n"
if doTable.Group == "" {
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + servicePackageName + "\"\n"
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + webPackageName + "/params\"\n"
} else {
importStr += "\t" + doTable.Group + "Service \"" + projectName + "/" + BasePackage + "/" + servicePackageName + "/" + doTable.Group + "\"\n"
importStr += "\t\"" + projectName + "/" + BasePackage + "/" + webPackageName + "/" + doTable.Group + "/params\"\n"
}
importStr += "\t\"github.com/gin-gonic/gin\"\n"
importStr += ")\n"
apiPrefix := getApiPrefix(table.Name, doTable.IgnoreRouterPrefixL)
addRouter := apiPrefix + "/add"
updateRouter := apiPrefix + "/update"
pageRouter := apiPrefix + "/page"
initRouter := "// Init" + modelName + "Rout 在InitRouter中添加Init" + modelName + "Rout(r),进行路由初始化\n"
initRouter += "func Init" + modelName + "Rout(engine *gin.Engine) {\n"
initRouter += "\tengine.POST(\"" + addRouter + "\", add" + modelName + ")\n"
if len(pks) > 0 {
initRouter += "\tengine.POST(\"" + updateRouter + "\", update" + modelName + ")\n"
}
initRouter += "\tengine.POST(\"" + pageRouter + "\", page" + modelName + ")\n"
initRouter += "}\n"
addApi := "// @Tags " + table.Description + "\n"
addApi += "// @Summary 新增" + table.Description + "\n"
addApi += "// @Param " + modelName + "AddParams body params." + modelName + "AddParams false \"参数\"\n"
addApi += "// @Param token header string true \"登陆token\"\n"
addApi += "// @Product json\n"
addApi += "// @Success 200 {object} getWay.ServerResponse\n"
addApi += "// @Router " + addRouter + " [POST]\n"
addApi += "func add" + modelName + "(c *gin.Context) {\n"
addApi += "\tdefer catch.ExceptionCatch(c)\n"
addApi += "\tvar param params." + modelName + "AddParams\n"
addApi += "\tvar err error\n"
addApi += "\terr = getWay.BindRequestBody(c, &param)\n"
addApi += "\tif err==nil {\n"
addPrams := ""
if haveHandler {
addPrams = "(param, c)"
} else {
addPrams = "(param)"
}
if doTable.Group == "" {
addApi += "\t\tservice.Add" + modelName + addPrams + "\n"
} else {
addApi += "\t\t" + doTable.Group + "Service.Add" + modelName + "(param)\n"
}
addApi += "\t\tgetWay.Success(c)\n"
addApi += "\t}else{\n"
addApi += "\t\texception.ThrowsErr(err)\n"
addApi += "\t}\n"
addApi += "}\n"
updateApi := "// @Tags " + table.Description + "\n"
updateApi += "// @Summary 修改" + table.Description + "\n"
updateApi += "// @Param " + modelName + "AddParams body params." + modelName + "UpdateParams false \"修改参数\"\n"
updateApi += "// @Param token header string true \"登陆token\"\n"
updateApi += "// @Product json\n"
updateApi += "// @Success 200 {object} getWay.ServerResponse\n"
updateApi += "// @Router " + updateRouter + " [POST]\n"
updateApi += "func update" + modelName + "(c *gin.Context) {\n"
updateApi += "\tdefer catch.ExceptionCatch(c)\n"
updateApi += "\tvar param params." + modelName + "UpdateParams\n"
updateApi += "\tvar err error\n"
updateApi += "\terr = getWay.BindRequestBody(c, &param)\n"
updateApi += "\tif err==nil {\n"
updatePrams := ""
if haveHandler {
updatePrams = "(param, c)"
} else {
updatePrams = "(param)"
}
if doTable.Group == "" {
updateApi += "\t\tservice.Update" + modelName + updatePrams + "\n"
} else {
updateApi += "\t\t" + doTable.Group + "Service.Update" + modelName + updatePrams + "\n"
}
updateApi += "\t\tgetWay.Success(c)\n"
updateApi += "\t}else{\n"
updateApi += "\t\texception.ThrowsErr(err)\n"
updateApi += "\t}\n"
updateApi += "}\n"
pageApi := "// @Tags " + table.Description + "\n"
pageApi += "// @Summary 分页查询" + table.Description + "\n"
pageApi += "// @Param " + modelName + "PageParams body params." + modelName + "PageParams false \"参数\"\n"
pageApi += "// @Param token header string true \"登陆token\"\n"
pageApi += "// @Product json\n"
pageApi += "// @Success 200 {object} response." + modelName + "PageResponse\n"
pageApi += "// @Router " + pageRouter + " [POST]\n"
pageApi += "func page" + modelName + "(c *gin.Context) {\n"
pageApi += "\tdefer catch.ExceptionCatch(c)\n"
pageApi += "\tvar param params." + modelName + "PageParams\n"
pageApi += "\tvar err error\n"
pageApi += "\terr = getWay.BindRequestBody(c, &param)\n"
pageApi += "\tif err==nil {\n"
if doTable.Group == "" {
pageApi += "\t\tpage := service.Page" + modelName + "(&param)\n"
} else {
pageApi += "\t\tpage := " + doTable.Group + "Service.Page" + modelName + "(param)\n"
}
pageApi += "\t\tgetWay.SuccessData(c,*page)\n"
pageApi += "\t}else{\n"
pageApi += "\t\texception.ThrowsErr(err)\n"
pageApi += "\t}\n"
pageApi += "}\n"
fileContent := ""
if len(pks) > 0 {
fileContent = packageStr + importStr + initRouter + addApi + updateApi + pageApi
} else {
fileContent = packageStr + importStr + initRouter + addApi + pageApi
}
createOrReplaceFile(BasePackage, webPackageName, doTable.Group, "", modelName, fileContent)
}
//检查文件是否存在
func checkFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
func buildFileDirectory(basePackageName, packageName, group, subPackageName string) string {
fileDirectory := ""
if basePackageName != "" {
fileDirectory += basePackageName + PathSeparator
}
if packageName != "" {
fileDirectory += packageName + PathSeparator
}
if &group != nil && group != "" {
fileDirectory += group + PathSeparator
}
fileDirectory += subPackageName + PathSeparator
return fileDirectory
}
func createOrReplaceFile(basePackage, packageName, group, subPackageName, modelName, fileContent string) {
fileSuffix := ""
if subPackageName != "" {
fileSuffix = strcase.ToCamel(subPackageName)
} else {
fileSuffix = strcase.ToCamel(packageName)
}
fileDirectory := buildFileDirectory(basePackage, packageName, group, subPackageName)
filename := fileDirectory + modelName + fileSuffix + ".go"
var f *os.File
var err error
if checkFileIsExist(filename) {
if !ModelReplace {
fmt.Println(modelName + " 已存在,需删除才能重新生成...")
return
}
f, err = os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC, os.ModePerm) //打开文件
if err != nil {
panic(err)
}
} else {
//创建目录
os.MkdirAll(fileDirectory, os.ModePerm)
f, err = os.OpenFile(filename, os.O_CREATE|os.O_EXCL, os.ModePerm)
if err != nil {
panic(err)
}
}
defer f.Close()
_, err = io.WriteString(f, fileContent)
fmt.Println(modelName + fileSuffix + " 已生成...")
}
package generate
import (
"git.168cad.top/zhengqiuyun/rym-util/a/db/mysql"
)
func MysqlAllTables() []Table {
var tables []Table
//查询库中所有表
tablesSql := "\nSELECT\ntable_name AS name,\nTABLE_COMMENT as description\nFROM\ninformation_schema.TABLES\nwhere table_schema=?"
db.GetPgDb().Raw(tablesSql, NameSpace).Scan(&tables)
return tables
}
func MysqlGetTableFiledByTableName(tableName string) []TableField {
var tableFields []TableField
tableInfoSql := "\nSELECT\n" +
"column_name as field_name,\n" +
"data_type as field_type,\n" +
"CHARACTER_MAXIMUM_LENGTH as length,\n" +
"CHARACTER_MAXIMUM_LENGTH as length_var,\n" +
"false as not_null,\n" +
"COLUMN_COMMENT as `comment`,\n" +
"COLUMN_TYPE as column_type\n" +
"FROM\n" +
"information_schema.columns\n" +
"where table_name=?\n" +
"and TABLE_SCHEMA=?\n" +
"order by column_name"
db.GetPgDb().Raw(tableInfoSql, tableName, NameSpace).Scan(&tableFields)
return tableFields
}
package generate
import (
"git.168cad.top/zhengqiuyun/rym-util/a/db/mysql"
)
func AllTables() []Table {
var tables []Table
//查询库中所有表
tablesSql := "SELECT a.oid,\n a.relname AS name,\n b.description\n FROM pg_class a\n LEFT OUTER JOIN pg_description b ON b.objsubid=0 AND a.oid = b.objoid\n WHERE a.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname='public')\n AND a.relkind='r'\n ORDER BY a.relname"
db.GetPgDb().Raw(tablesSql).Scan(&tables)
return tables
}
func GetTableFiledByTableName(tableName string) []TableField {
var tableFields []TableField
tableInfoSql := "SELECT a.attname AS field_name,\n t.typname AS field_type,\n a.attlen AS length,\n a.atttypmod AS length_var,\n a.attnotnull AS notnull,\n b.description AS comment\n FROM pg_class c,\n pg_attribute a\n LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,\n pg_type t\n WHERE c.relname = ?\n and a.attnum > 0\n and a.attrelid = c.oid\n and a.atttypid = t.oid\n ORDER BY a.attnum"
db.GetPgDb().Raw(tableInfoSql, tableName).Scan(&tableFields)
return tableFields
}
package getWay
type Error struct {
Code State
}
func ThrowsGetWayErr(code State) {
if &code != nil {
panic(Error{code})
}
}
package getWay
import (
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
"github.com/gin-gonic/gin"
)
const headerKeyToken = "token"
const headerKeyPlatformCode = "platform"
const headerKeyClientSource = "clientSource"
func getHeader(c *gin.Context, key string) string {
v := c.GetHeader(key)
return v
}
func GetToken(c *gin.Context) string {
return getHeader(c, headerKeyToken)
}
func SetToken(v string, c *gin.Context) {
c.Header(headerKeyToken, v)
}
func GetPlatformCode(c *gin.Context) string {
platformCode := getHeader(c, headerKeyPlatformCode)
if platformCode == "" {
exception.ThrowsErrS("平台错误")
}
return platformCode
}
func GetClientSource(c *gin.Context) string {
platformCode := getHeader(c, headerKeyClientSource)
return platformCode
}
package getWay
import (
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
"git.168cad.top/zhengqiuyun/rym-util/a/db/redis"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"github.com/gin-gonic/gin"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
)
func GetCurrentUserId(c *gin.Context) (uint32, bool) {
userId, b := c.Get(CurrentUserIdKey)
if b {
transUserId := userId.(uint32)
return transUserId, b
}
return 0, b
}
type UserInfo struct {
Id uint32
Account string
Name string
}
func GetCurrentUser(c *gin.Context) *UserInfo {
var userInfo = UserInfo{}
adminResponse, b := c.Get(CurrentUserKey)
if b {
admin := adminResponse.(Admin)
userInfo.Name = admin.Name
userInfo.Account = admin.LoginAccount
userInfo.Id = admin.Id
}
return &userInfo
}
func GetAdminInfo(token string) Admin {
var adminResponse = AdminResponse{}
resp, err := http.Get(conf.SystemHost + "/admin/current?token=" + token)
if err != nil {
log.Error(err.Error())
return Admin{}
}
defer resp.Body.Close()
adminResponseBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error(err.Error())
return Admin{}
}
err = json.Unmarshal(adminResponseBytes, &adminResponse)
if err != nil {
log.Error(err.Error())
}
return adminResponse.Admin
}
type AdminResponse struct {
code int
msg string
Admin Admin
}
type Admin struct {
Id uint32
Name string
LoginAccount string
}
const requestBodyKey = "requestBody"
func BindRequestBody(c *gin.Context, param interface{}) error {
c.ShouldBindJSON(param)
bytes, err := json.Marshal(param)
c.Set(requestBodyKey, string(bytes))
return err
}
func GetParams(c *gin.Context) string {
rd := ""
params := c.Request.URL.Query().Encode()
if params != "" {
rd += params
}
ad := c.GetString(requestBodyKey)
if ad != "" {
rd += ad
}
return rd
}
func GetServerIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return ""
}
for _, addr := range addrs {
ipAddr, ok := addr.(*net.IPNet)
if !ok {
continue
}
if ipAddr.IP.IsLoopback() {
continue
}
if !ipAddr.IP.IsGlobalUnicast() {
continue
}
return ipAddr.IP.String()
}
return ""
}
func GetClientIP(c *gin.Context) string {
ip := c.ClientIP()
return ip
}
func GetURL(c *gin.Context) string {
url := c.Request.URL.Path
return url
}
func GetMethod(c *gin.Context) string {
method := c.Request.Method
return method
}
func SetStartTime(c *gin.Context) {
c.Set(StartTimeKey, time.Now().UnixNano())
logStart(c)
}
func GetStartTime(c *gin.Context) int64 {
startTime := c.GetInt64(StartTimeKey)
return startTime
}
func ValidRequest(c *gin.Context) {
defer exceptionGetWayCatch(c)
ip := c.ClientIP()
url := c.Request.RequestURI
token := GetToken(c)
if token == "" {
if checkIp(ip) { //如果没有token,看是否是ip白名单
log.Debug(fmt.Sprintf("IP白名单校验通过:%s", ip))
} else {
log.Debug(fmt.Sprintf("IP白名单校验不通过:%s", ip))
if checkUri(url) { //如果不是ip白名单,看是否是url白名单,例如一些第三方的回调
log.Debug(fmt.Sprintf("URL白名单校验通过:%s", url))
} else {
log.Debug(fmt.Sprintf("URL白名单校验不通过:%s", url))
ThrowsGetWayErr(Illegal9)
}
}
} else {
if redis.Exists(token) { //校验token是否有效
currentUser := GetAdminInfo(token)
c.Set(CurrentUserKey, currentUser)
log.Debug(fmt.Sprintf("登陆校验通过:%s,对应用户id: %d", token, currentUser.Id))
} else {
log.Debug(fmt.Sprintf("登陆校验不通过:%s", token))
ThrowsGetWayErr(Expire)
}
}
}
func exceptionGetWayCatch(c *gin.Context) {
err := recover() //获取异常
if err != nil {
switch err.(type) {
case Error:
e := (err).(Error)
FailGetWay(c, e.Code)
break
}
}
}
func checkUri(uri string) bool {
for _, v := range conf.WhiteListUri {
if strings.Index(uri, v) == 0 {
return true
}
}
return false
}
func checkIp(ip string) bool {
for _, v := range conf.WhiteListIp {
if strings.Index(ip, v) == 0 {
return true
}
}
return false
}
func logStart(c *gin.Context) {
log.Info(fmt.Sprintf("开始 %s %s %s %s", GetMethod(c), GetURL(c), GetToken(c), GetClientIP(c)))
}
package getWay
import (
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
db "git.168cad.top/zhengqiuyun/rym-util/a/db/mysql"
"git.168cad.top/zhengqiuyun/rym-util/a/db/redis"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"git.168cad.top/zhengqiuyun/rym-util/a/log/es"
"git.168cad.top/zhengqiuyun/rym-util/a/util"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
type ServerResponse struct {
Code State `json:"code"` //0为成功,其他都是失败
Msg string `json:"msg,omitempty"` //非1000情况下的错误描述
}
type ServerDataResponse struct {
ServerResponse
Data interface{} `json:"data,omitempty"`
}
func response(state State) ServerResponse {
return ServerResponse{Code: state, Msg: state.String()}
}
func FailGetWay(c *gin.Context, state State) {
resp := response(state)
c.JSON(http.StatusBadGateway, resp)
c.Abort()
logEnd(c, resp)
}
func FailAndMsg(c *gin.Context, msg string) {
db.Rollback()
resp := ServerResponse{Code: BusinessError, Msg: msg}
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
func Success(c *gin.Context) {
db.Commit()
resp := response(OK)
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
func SuccessData(c *gin.Context, data interface{}) {
db.Commit()
resp := ServerDataResponse{response(OK), data}
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
type WxResponse struct {
Code string `json:"code"`
Message string `json:"message"`
}
func WxSuccess(c *gin.Context) {
resp := WxResponse{"SUCCESS", "成功"}
c.JSON(http.StatusOK, resp)
logEnd(c, resp)
}
func AliSuccess(c *gin.Context) {
resp := "success"
c.JSON(http.StatusOK, resp)
logEnd(c, resp)
}
func logEnd(c *gin.Context, data interface{}) {
esSwitch := redis.SwitchOpen(redis.ES日志开关 + conf.ServerName)
startTime := GetStartTime(c)
endTime := time.Now().UnixNano()
var responseStr string
if data != nil {
dataJson, _ := json.Marshal(data)
rs := string(dataJson)
excludeUrl := []string{""}
if esSwitch {
if util.ArrayContains(excludeUrl, GetURL(c)) && len(rs) > conf.LogResponseLength {
responseStr = rs[0:conf.LogResponseLength] + "......"
} else {
responseStr = rs
}
} else {
if len(rs) > conf.LogResponseLength {
responseStr = rs[0:conf.LogResponseLength] + "......"
} else {
responseStr = rs
}
}
}
token := GetToken(c)
if esSwitch && token != "" {
esLog(c, responseStr)
log.Info(fmt.Sprintf("结束,耗时%d毫秒", (endTime-startTime)/1e6))
} else {
log.Info(fmt.Sprintf("返回数据:%s", responseStr))
log.Info(fmt.Sprintf("结束,耗时%d毫秒 %s %s %s %s %s", (endTime-startTime)/1e6, GetMethod(c), GetURL(c), token, GetClientIP(c), GetParams(c)))
}
}
func esLog(c *gin.Context, response string) {
log := es.ServerLogModel{
ServerName: conf.ServerName,
Env: conf.ENV,
TimeStamp: util.MilSecond(time.Now()),
ThreadNo: fmt.Sprintf("%d", util.GetGID()),
ServerIp: GetServerIP(),
ClientIp: GetClientIP(c),
Token: GetToken(c),
CustomerId: GetCurrentUser(c).Id,
ClientSource: GetClientSource(c),
Url: GetURL(c),
Method: GetMethod(c),
Request: GetParams(c),
Response: response,
DealTimes: util.MilSecond(time.Now()) - GetStartTime(c)/1e6,
}
es.InsertEsLog(log)
}
package getWay
type State int16
// iota 初始化后会自动递增
const (
BusinessError State = 1001
OK State = 1000
Expire State = 1 - iota
Illegal1
Illegal2
Illegal3
Illegal4
Illegal5
Illegal6
Illegal7
Illegal8
Illegal9
)
func (t State) String() string {
switch t {
case BusinessError:
return "business error"
case OK:
return "OK"
case Expire:
return "expire request"
case Illegal1:
return "illegal request(1)"
case Illegal2:
return "illegal request(2)"
case Illegal3:
return "illegal request(3)"
case Illegal4:
return "illegal request(4)"
case Illegal5:
return "illegal request(5)"
case Illegal6:
return "illegal request(6)"
case Illegal7:
return "illegal request(7)"
case Illegal8:
return "illegal request(8)"
case Illegal9:
return "illegal request(9)"
default:
return "unknown"
}
}
package getWay
const CurrentUserKey = "userInfo"
const CurrentUserIdKey = "userID"
const StartTimeKey = "StartTime"
const LoginUri = "/api/v1/app/login"
const LoginExpire = 10 * 24 * 60 * 60
package jeff
func CheckCRC(buf []byte) bool {
var wCrcData uint16 = 0xffff
for _, v := range buf {
wCrcData ^= uint16(v)
for j := 0; j < 8; j++ {
if wCrcData&1 != 0 {
wCrcData >>= 1
wCrcData ^= 0xa001
} else {
wCrcData >>= 1
}
}
}
return wCrcData == 0
}
// GetCRC 获取2个字节的CRC16
func GetCRC(buf []byte, len int) { //传入的切片必须装得下
var wCrcData uint16 = 0xffff
for i := 0; i < len; i++ {
wCrcData ^= uint16(buf[i])
for j := 0; j < 8; j++ {
if wCrcData&1 != 0 {
wCrcData >>= 1
wCrcData ^= 0xa001
} else {
wCrcData >>= 1
}
}
}
buf[len] = byte(wCrcData)
buf[len+1] = byte(wCrcData >> 8)
}
package jeff
import (
"encoding/base64"
"errors"
)
func EncryptBytesToBase64(cleartext []byte, pswd string, iv string) (base64Result []byte) { //看base64库,返回切片更快,本来tcp发送也是切片,不过这里面string也是切片
var pswdIv [16]byte
var pswdSum byte
var i int
cleartextLen := len(cleartext)
var result = make([]byte, cleartextLen+1)
for i = 0; i < 16; i++ {
pswdIv[i] = ((pswd[i] & 0xaa) | (pswd[15-i] & 0x55)) + iv[15-i] + byte(i)
if i%2 == 0 {
pswdSum += pswd[i] + iv[i]
} else {
pswdSum -= pswd[i] - iv[i]
}
}
for i = 0; i < 16; i++ {
if i%2 == 0 {
pswdIv[i] = ^pswdIv[i] + pswdSum
} else {
pswdIv[i] = pswdIv[i] - ^pswdSum
}
}
result[cleartextLen] = ^pswdSum
for i = 0; i < cleartextLen; i++ {
result[cleartextLen] += cleartext[i]
}
for i = 0; i < cleartextLen; i++ {
result[i] = ^((cleartext[i] & 0x72) | (cleartext[cleartextLen-1-i] & 0x8d))
if i%2 == 0 {
result[i] += pswdIv[i%16] - result[cleartextLen]
} else {
result[i] -= pswdIv[i%16] + result[cleartextLen]
}
}
base64Result = make([]byte, base64.StdEncoding.EncodedLen(cleartextLen+1)+2) //多出两个用来装起始结束符
base64.StdEncoding.Encode(base64Result[1:], result)
return
//return base64.StdEncoding.EncodeToString(result)
}
// DecryptBase64ToBytes 解密并转换为bytes
func DecryptBase64ToBytes(ciphertext []byte, pswd string, iv string) ([]byte, error) { //看base64库,传入切片更快,本来tcp接收也是切片,不过这里面string也是切片
var pswdIv [16]byte
var pswdSum byte
var i int
cipherBytes := make([]byte, base64.StdEncoding.DecodedLen(len(ciphertext)))
hexLen, err := base64.StdEncoding.Decode(cipherBytes, ciphertext)
//cipherBytes, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return nil, err
}
clearLen := hexLen - 1
var resultBytes = make([]byte, clearLen)
var resultBytesTemp = make([]byte, clearLen)
for i = 0; i < 16; i++ {
pswdIv[i] = ((pswd[i] & 0xaa) | (pswd[15-i] & 0x55)) + iv[15-i] + byte(i)
if i%2 == 0 {
pswdSum += pswd[i] + iv[i]
} else {
pswdSum -= pswd[i] - iv[i]
}
}
for i = 0; i < 16; i++ {
if i%2 == 0 {
pswdIv[i] = ^pswdIv[i] + pswdSum
} else {
pswdIv[i] = pswdIv[i] - ^pswdSum
}
}
for i = 0; i < clearLen; i++ {
if i%2 == 0 {
resultBytesTemp[i] = ^(cipherBytes[i] - (pswdIv[i%16] - cipherBytes[clearLen]))
} else {
resultBytesTemp[i] = ^(cipherBytes[i] + (pswdIv[i%16] + cipherBytes[clearLen]))
}
}
var sum byte
for i = 0; i < clearLen; i++ {
resultBytes[i] = (resultBytesTemp[i] & 0x72) | (resultBytesTemp[clearLen-1-i] & 0x8d)
sum += resultBytes[i]
}
sum += ^pswdSum
if sum != cipherBytes[clearLen] {
return nil, errors.New("密文校验错误")
}
return resultBytes, nil
}
func EncryptBytesToBase64URL(cleartext []byte, pswd string) string {
var i int
cleartextLen := len(cleartext)
var result = make([]byte, cleartextLen+1)
result[cleartextLen] = 0x11
for i = 0; i < cleartextLen; i++ {
if i%2 == 0 {
result[cleartextLen] -= cleartext[i] | 0x23
} else {
result[cleartextLen] += cleartext[i] & 0x36
}
result[cleartextLen] += ^((cleartext[i] >> 3) | (cleartext[i] << 5))
}
for i = 0; i < cleartextLen; i++ {
result[i] = ^((cleartext[i] & 0x72) | (cleartext[cleartextLen-1-i] & 0x8d))
if i%2 == 0 {
result[i] += pswd[i%16] - result[cleartextLen]
} else {
result[i] -= pswd[i%16] + result[cleartextLen]
}
}
return base64.URLEncoding.EncodeToString(result)
}
func DecryptBase64URLToBytes(ciphertext string, pswd string) ([]byte, error) { //
var i int
hex, err := base64.URLEncoding.DecodeString(ciphertext)
if err != nil {
return nil, err
}
clearLen := len(hex) - 1
var resultBytes = make([]byte, clearLen)
var resultBytesTemp = make([]byte, clearLen)
for i = 0; i < clearLen; i++ {
if i%2 == 0 {
resultBytesTemp[i] = ^(hex[i] - (pswd[i%16] - hex[clearLen]))
} else {
resultBytesTemp[i] = ^(hex[i] + (pswd[i%16] + hex[clearLen]))
}
}
var sum byte
for i = 0; i < clearLen; i++ {
resultBytes[i] = (resultBytesTemp[i] & 0x72) | (resultBytesTemp[clearLen-1-i] & 0x8d)
//sum += resultBytes[i]
if i%2 == 0 {
sum -= resultBytes[i] | 0x23
} else {
sum += resultBytes[i] & 0x36
}
sum += ^((resultBytes[i] >> 3) | (resultBytes[i] << 5))
}
sum += 0x11
if sum != hex[clearLen] {
return nil, errors.New("密文校验错误")
}
return resultBytes, nil
}
package jeff
//import (
// "git.168cad.top/zhengqiuyun/rym-util/a/getWay"
// cache "git.168cad.top/zhengqiuyun/rym-util/app/cache/customer"
// "math/rand"
// "time"
//)
//
//const jeffWTKey = "ekkidlsedksldkkk"
//
//const tokenClearLen = 20
//const tokenLen = 28
//
//type tokenResult struct {
// CreatTime int64 //token创建时间
// UserID uint32 //
// ExpireTime uint32
// UserType uint8 // 1微信家长 2后台用户 3硬件设备 4服务器请求 其余预留
// UserLevel uint8 // 用户等级
// CheckResult getWay.State
//}
//
//func CreateAppToken(creatTime int64, userID, expireTime uint32) string {
// cache.SetAppToken(userID)
// return createToken(creatTime, userID, expireTime, 1, 0)
//}
//
//func CreateServerToken(creatTime int64, expireTime uint32) string {
// return createToken(creatTime, 1, expireTime, 4, 0)
//}
//
//// CreateToken 生成token,duration到期时间,秒的时间戳
//func createToken(creatTime int64, userID, expireTime uint32, userType, userLevel uint8) string {
// var clear = make([]byte, tokenClearLen) //7字节创建时间 4字节结束时间 4字节有效时长 2字节CRC 3字节随机数预留
// r := rand.New(rand.NewSource(time.Now().UnixNano()))
// random := byte(r.Intn(256))
//
// clear[0] = ^byte(userID>>24) - random
// clear[1] = byte(expireTime>>16) - random
// clear[2] = byte(userID>>16) + random + 166
// clear[3] = ^byte(creatTime>>24) - random
// clear[4] = byte(creatTime>>48) - random + 23
// clear[5] = ^byte(expireTime >> 8)
// clear[6] = byte(creatTime>>32) + random + 66
// clear[7] = byte(expireTime>>24) + random + 99
// clear[8] = byte(creatTime>>16) + random - 88
// clear[9] = ^byte(userID)
// clear[10] = byte(creatTime) - 69
// clear[11] = byte(expireTime) + random + 27
// clear[12] = byte(userID>>8) - random - 33
// clear[13] = ^byte(creatTime>>40) - random - 28
// clear[14] = byte(creatTime>>8) - random - 69
// clear[15] = ^random + 0x5a
// clear[16] = userType + (userLevel << 4) - random
// clear[17] = 0x1a + random
// GetCRC(clear, 18)
// clear[18] = ^(clear[18] + random - 15)
// clear[19] = ^clear[19] - random
//
// return EncryptBytesToBase64URL(clear, jeffWTKey)
//}
//
//func decryptAndCheckToken(token string) (clearStruct tokenResult) {
// if len(token) != tokenLen {
// getWay.ThrowsGetWayErr(getWay.Illegal1)
// return
// }
// clear, err := DecryptBase64URLToBytes(token, jeffWTKey)
// if err != nil {
// getWay.ThrowsGetWayErr(getWay.Illegal2)
// return
// }
// if len(clear) != tokenClearLen {
// getWay.ThrowsGetWayErr(getWay.Illegal3)
// return
// }
// random := clear[17] - 0x1a
// if clear[15] != ^random+0x5a {
// getWay.ThrowsGetWayErr(getWay.Illegal4)
// return
// }
// clear[18] = ^clear[18] - random + 15
// clear[19] = ^(clear[19] + random)
// if CheckCRC(clear) == false {
// getWay.ThrowsGetWayErr(getWay.Illegal5)
// return
// }
// clearStruct.ExpireTime = (uint32(clear[11] - 27 - random)) +
// (uint32(^clear[5]) << 8) +
// (uint32(clear[1]+random) << 16) +
// (uint32(clear[7]-random-99) << 24)
// if uint32(time.Now().Unix()) > clearStruct.ExpireTime { // 到期时间已经过了
// getWay.ThrowsGetWayErr(getWay.Illegal6)
// return
// }
// clearStruct.CreatTime = int64(clear[10]+69) +
// (int64(clear[14]+69+random) << 8) +
// (int64(clear[8]+88-random) << 16) +
// (int64(^(clear[3] + random)) << 24) +
// (int64(clear[6]-66-random) << 32) +
// (int64(^(clear[13] + 28 + random)) << 40) +
// (int64(clear[4]-23+random) << 48)
//
// if time.Now().UnixMicro() < clearStruct.CreatTime { // 创建时间居然大于当前时间
// getWay.ThrowsGetWayErr(getWay.Illegal7)
// return
// }
// clearStruct.UserID = uint32(^clear[9]) +
// (uint32(clear[12]+33+random) << 8) +
// (uint32(clear[2]-166-random) << 16) +
// (uint32(^(clear[0] + random)) << 24)
//
// clearStruct.UserType = clear[16] + random
// clearStruct.UserType = clearStruct.UserType & 0xf
//
// clearStruct.CheckResult = getWay.OK
// if clearStruct.UserType != 1 && clearStruct.UserType != 2 {
// getWay.ThrowsGetWayErr(getWay.Illegal8)
// }
// return
//}
//
//func CheckTokenExit(clearStruct *tokenResult) {
// v := cache.GetAppToken(clearStruct.UserID)
// if !v {
// getWay.ThrowsGetWayErr(getWay.Expire)
// return
// }
//}
package alipay
import (
"crypto"
"crypto/md5"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"io"
"io/ioutil"
"math"
"net/http"
"net/url"
"sort"
"strings"
"sync"
"time"
"github.com/smartwalle/crypto4go"
)
var (
ErrSignNotFound = errors.New("alipay: sign content not found")
ErrAliPublicKeyNotFound = errors.New("alipay: alipay public key not found")
)
const (
kAliPayPublicKeySN = "alipay-public-key"
kAppAuthToken = "app_auth_token"
)
type Client struct {
mu sync.Mutex
isProduction bool
appId string
apiDomain string
notifyVerifyDomain string
Client *http.Client
location *time.Location
appPrivateKey *rsa.PrivateKey // 应用私钥
appCertSN string
rootCertSN string
aliPublicCertSN string
aliPublicKeyList map[string]*rsa.PublicKey
}
type OptionFunc func(c *Client)
func WithTimeLocation(location *time.Location) OptionFunc {
return func(c *Client) {
c.location = location
}
}
func WithHTTPClient(client *http.Client) OptionFunc {
return func(c *Client) {
c.Client = client
}
}
// New 初始化支付宝客户端
//
// appId - 支付宝应用 id
//
// privateKey - 应用私钥,开发者自己生成
//
// isProduction - 是否为生产环境,传 false 的时候为沙箱环境,用于开发测试,正式上线的时候需要改为 true
func New(appId, privateKey string, isProduction bool, opts ...OptionFunc) (client *Client, err error) {
priKey, err := crypto4go.ParsePKCS1PrivateKey(crypto4go.FormatPKCS1PrivateKey(privateKey))
if err != nil {
priKey, err = crypto4go.ParsePKCS8PrivateKey(crypto4go.FormatPKCS8PrivateKey(privateKey))
if err != nil {
return nil, err
}
}
client = &Client{}
client.isProduction = isProduction
client.appId = appId
if client.isProduction {
client.apiDomain = kProductionURL
client.notifyVerifyDomain = kProductionMAPIURL
} else {
client.apiDomain = kSandboxURL
client.notifyVerifyDomain = kSandboxURL
}
client.Client = http.DefaultClient
client.location = time.Local
client.appPrivateKey = priKey
client.aliPublicKeyList = make(map[string]*rsa.PublicKey)
for _, opt := range opts {
opt(client)
}
return client, nil
}
func (this *Client) IsProduction() bool {
return this.isProduction
}
// LoadAliPayPublicKey 加载支付宝公钥
func (this *Client) LoadAliPayPublicKey(aliPublicKey string) error {
var pub *rsa.PublicKey
var err error
if len(aliPublicKey) < 0 {
return ErrAliPublicKeyNotFound
}
pub, err = crypto4go.ParsePublicKey(crypto4go.FormatPublicKey(aliPublicKey))
if err != nil {
return err
}
this.mu.Lock()
this.aliPublicCertSN = kAliPayPublicKeySN
this.aliPublicKeyList[this.aliPublicCertSN] = pub
this.mu.Unlock()
return nil
}
// LoadAppPublicCert 加载应用公钥证书
func (this *Client) LoadAppPublicCert(s string) error {
cert, err := crypto4go.ParseCertificate([]byte(s))
if err != nil {
return err
}
this.appCertSN = getCertSN(cert)
return nil
}
// LoadAppPublicCertFromFile 加载应用公钥证书
func (this *Client) LoadAppPublicCertFromFile(filename string) error {
b, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
return this.LoadAppPublicCert(string(b))
}
// LoadAliPayPublicCert 加载支付宝公钥证书
func (this *Client) LoadAliPayPublicCert(s string) error {
cert, err := crypto4go.ParseCertificate([]byte(s))
if err != nil {
return err
}
key, ok := cert.PublicKey.(*rsa.PublicKey)
if ok == false {
return nil
}
this.mu.Lock()
this.aliPublicCertSN = getCertSN(cert)
this.aliPublicKeyList[this.aliPublicCertSN] = key
this.mu.Unlock()
return nil
}
// LoadAliPayPublicCertFromFile 加载支付宝公钥证书
func (this *Client) LoadAliPayPublicCertFromFile(filename string) error {
b, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
return this.LoadAliPayPublicCert(string(b))
}
// LoadAliPayRootCert 加载支付宝根证书
func (this *Client) LoadAliPayRootCert(s string) error {
var certStrList = strings.Split(s, kCertificateEnd)
var certSNList = make([]string, 0, len(certStrList))
for _, certStr := range certStrList {
certStr = certStr + kCertificateEnd
var cert, _ = crypto4go.ParseCertificate([]byte(certStr))
if cert != nil && (cert.SignatureAlgorithm == x509.SHA256WithRSA || cert.SignatureAlgorithm == x509.SHA1WithRSA) {
certSNList = append(certSNList, getCertSN(cert))
}
}
this.rootCertSN = strings.Join(certSNList, "_")
return nil
}
// LoadAliPayRootCertFromFile 加载支付宝根证书
func (this *Client) LoadAliPayRootCertFromFile(filename string) error {
b, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
return this.LoadAliPayRootCert(string(b))
}
func (this *Client) URLValues(param Param) (value url.Values, err error) {
var p = url.Values{}
p.Add("app_id", this.appId)
p.Add("method", param.APIName())
p.Add("format", kFormat)
p.Add("charset", kCharset)
p.Add("sign_type", kSignTypeRSA2)
p.Add("timestamp", time.Now().In(this.location).Format(kTimeFormat))
p.Add("version", kVersion)
if this.appCertSN != "" {
p.Add("app_cert_sn", this.appCertSN)
}
if this.rootCertSN != "" {
p.Add("alipay_root_cert_sn", this.rootCertSN)
}
bytes, err := json.Marshal(param)
if err != nil {
return nil, err
}
p.Add("biz_content", string(bytes))
var ps = param.Params()
if ps != nil {
for key, value := range ps {
if key == kAppAuthToken && value == "" {
continue
}
p.Add(key, value)
}
}
sign, err := signWithPKCS1v15(p, this.appPrivateKey, crypto.SHA256)
if err != nil {
return nil, err
}
p.Add("sign", sign)
return p, nil
}
func (this *Client) doRequest(method string, param Param, result interface{}) (err error) {
var buf io.Reader
if param != nil {
p, err := this.URLValues(param)
if err != nil {
return err
}
buf = strings.NewReader(p.Encode())
}
req, err := http.NewRequest(method, this.apiDomain, buf)
if err != nil {
return err
}
req.Header.Set("Content-Type", kContentType)
resp, err := this.Client.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
var dataStr = string(data)
var rootNodeName = strings.Replace(param.APIName(), ".", "_", -1) + kResponseSuffix
var rootIndex = strings.LastIndex(dataStr, rootNodeName)
var errorIndex = strings.LastIndex(dataStr, kErrorResponse)
var content string
var certSN string
var sign string
if rootIndex > 0 {
content, certSN, sign = parseJSONSource(dataStr, rootNodeName, rootIndex)
if sign == "" {
var errRsp *ErrorRsp
if err = json.Unmarshal([]byte(content), &errRsp); err != nil {
return err
}
// alipay.open.app.alipaycert.download(应用支付宝公钥证书下载) 没有返回 sign 字段,所以再判断一次 code
if errRsp.Code != CodeSuccess {
if errRsp != nil {
return errRsp
}
return ErrSignNotFound
}
}
} else if errorIndex > 0 {
content, certSN, sign = parseJSONSource(dataStr, kErrorResponse, errorIndex)
if sign == "" {
var errRsp *ErrorRsp
if err = json.Unmarshal([]byte(content), &errRsp); err != nil {
return err
}
return errRsp
}
} else {
return ErrSignNotFound
}
if sign != "" {
publicKey, err := this.getAliPayPublicKey(certSN)
if err != nil {
return err
}
if ok, err := verifyData([]byte(content), sign, publicKey); ok == false {
return err
}
}
err = json.Unmarshal(data, result)
if err != nil {
return err
}
return err
}
func (this *Client) DoRequest(method string, param Param, result interface{}) (err error) {
return this.doRequest(method, param, result)
}
func (this *Client) VerifySign(data url.Values) (ok bool, err error) {
var certSN = data.Get(kCertSNNodeName)
publicKey, err := this.getAliPayPublicKey(certSN)
if err != nil {
return false, err
}
return verifySign(data, publicKey)
}
func (this *Client) getAliPayPublicKey(certSN string) (key *rsa.PublicKey, err error) {
this.mu.Lock()
defer this.mu.Unlock()
if certSN == "" {
certSN = this.aliPublicCertSN
}
key = this.aliPublicKeyList[certSN]
if key == nil {
if this.isProduction {
cert, err := this.downloadAliPayCert(certSN)
if err != nil {
return nil, err
}
var ok bool
key, ok = cert.PublicKey.(*rsa.PublicKey)
if ok == false {
return nil, ErrAliPublicKeyNotFound
}
} else {
return nil, ErrAliPublicKeyNotFound
}
}
return key, nil
}
func (this *Client) CertDownload(param CertDownload) (result *CertDownloadRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
func (this *Client) downloadAliPayCert(certSN string) (cert *x509.Certificate, err error) {
var cp = CertDownload{}
cp.AliPayCertSN = certSN
rsp, err := this.CertDownload(cp)
if err != nil {
return nil, err
}
certBytes, err := base64.StdEncoding.DecodeString(rsp.Content.AliPayCertContent)
if err != nil {
return nil, err
}
cert, err = crypto4go.ParseCertificate(certBytes)
if err != nil {
return nil, err
}
key, ok := cert.PublicKey.(*rsa.PublicKey)
if ok == false {
return nil, nil
}
this.aliPublicCertSN = getCertSN(cert)
this.aliPublicKeyList[this.aliPublicCertSN] = key
return cert, nil
}
func parseJSONSource(rawData string, nodeName string, nodeIndex int) (content, certSN, sign string) {
var dataStartIndex = nodeIndex + len(nodeName) + 2
var signIndex = strings.LastIndex(rawData, "\""+kSignNodeName+"\"")
var certIndex = strings.LastIndex(rawData, "\""+kCertSNNodeName+"\"")
var dataEndIndex int
if signIndex > 0 && certIndex > 0 {
dataEndIndex = int(math.Min(float64(signIndex), float64(certIndex))) - 1
} else if certIndex > 0 {
dataEndIndex = certIndex - 1
} else if signIndex > 0 {
dataEndIndex = signIndex - 1
} else {
dataEndIndex = len(rawData) - 1
}
var indexLen = dataEndIndex - dataStartIndex
if indexLen < 0 {
return "", "", ""
}
content = rawData[dataStartIndex:dataEndIndex]
if certIndex > 0 {
var certStartIndex = certIndex + len(kCertSNNodeName) + 4
certSN = rawData[certStartIndex:]
var certEndIndex = strings.Index(certSN, "\"")
certSN = certSN[:certEndIndex]
}
if signIndex > 0 {
var signStartIndex = signIndex + len(kSignNodeName) + 4
sign = rawData[signStartIndex:]
var signEndIndex = strings.LastIndex(sign, "\"")
sign = sign[:signEndIndex]
}
return content, certSN, sign
}
func signWithPKCS1v15(param url.Values, privateKey *rsa.PrivateKey, hash crypto.Hash) (s string, err error) {
if param == nil {
param = make(url.Values, 0)
}
var pList = make([]string, 0, 0)
for key := range param {
var value = strings.TrimSpace(param.Get(key))
if len(value) > 0 {
pList = append(pList, key+"="+value)
}
}
sort.Strings(pList)
var src = strings.Join(pList, "&")
sig, err := crypto4go.RSASignWithKey([]byte(src), privateKey, hash)
if err != nil {
return "", err
}
s = base64.StdEncoding.EncodeToString(sig)
return s, nil
}
func verifySign(data url.Values, key *rsa.PublicKey) (ok bool, err error) {
sign := data.Get(kSignNodeName)
var keys = make([]string, 0, 0)
for k := range data {
if k == kSignNodeName || k == kSignTypeNodeName || k == kCertSNNodeName {
continue
}
keys = append(keys, k)
}
sort.Strings(keys)
var buf strings.Builder
for _, k := range keys {
vs := data[k]
for _, v := range vs {
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(k)
buf.WriteByte('=')
buf.WriteString(v)
}
}
s := buf.String()
return verifyData([]byte(s), sign, key)
}
func verifyData(data []byte, sign string, key *rsa.PublicKey) (ok bool, err error) {
signBytes, err := base64.StdEncoding.DecodeString(sign)
if err != nil {
return false, err
}
if err = crypto4go.RSAVerifyWithKey(data, signBytes, key, crypto.SHA256); err != nil {
return false, err
}
return true, nil
}
func getCertSN(cert *x509.Certificate) string {
var value = md5.Sum([]byte(cert.Issuer.String() + cert.SerialNumber.String()))
return hex.EncodeToString(value[:])
}
package alipay
import "fmt"
const (
kSandboxURL = "https://openapi.alipaydev.com/gateway.do"
kProductionURL = "https://openapi.alipay.com/gateway.do"
kProductionMAPIURL = "https://mapi.alipay.com/gateway.do"
kFormat = "JSON"
kCharset = "utf-8"
kVersion = "1.0"
kSignTypeRSA2 = "RSA2"
kContentType = "application/x-www-form-urlencoded;charset=utf-8"
kTimeFormat = "2006-01-02 15:04:05"
)
const (
kResponseSuffix = "_response"
kErrorResponse = "error_response"
kSignNodeName = "sign"
kSignTypeNodeName = "sign_type"
kCertSNNodeName = "alipay_cert_sn"
kCertificateEnd = "-----END CERTIFICATE-----"
)
// Code 支付宝接口响应 code https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=105806&docType=1
type Code string
func (c Code) IsSuccess() bool {
return c == CodeSuccess
}
const (
CodeSuccess Code = "10000" // 接口调用成功
CodeUnknowError Code = "20000" // 服务不可用
CodeInvalidAuthToken Code = "20001" // 授权权限不足
CodeMissingParam Code = "40001" // 缺少必选参数
CodeInvalidParam Code = "40002" // 非法的参数
CodeBusinessFailed Code = "40004" // 业务处理失败
CodePermissionDenied Code = "40006" // 权限不足
)
type Param interface {
// 用于提供访问的 method
APIName() string
// 返回参数列表
Params() map[string]string
}
type ErrorRsp struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
}
func (this *ErrorRsp) Error() string {
return fmt.Sprintf("%s - %s", this.Code, this.SubMsg)
}
type CertDownload struct {
AppAuthToken string `json:"-"` // 可选
AliPayCertSN string `json:"alipay_cert_sn"` // 支付宝公钥证书序列号
}
func (this CertDownload) APIName() string {
return "alipay.open.app.alipaycert.download"
}
func (this CertDownload) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
return m
}
type CertDownloadRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
AliPayCertContent string `json:"alipay_cert_content"`
} `json:"alipay_open_app_alipaycert_download_response"`
Sign string `json:"sign"`
}
package alipay
import (
"crypto"
"net/url"
"strings"
)
// PublicAppAuthorize 用户信息授权接口(网站支付宝登录快速接入) https://docs.open.alipay.com/289/105656#s3 (https://docs.open.alipay.com/263/105809)
func (this *Client) PublicAppAuthorize(scopes []string, redirectURI, state string) (result *url.URL, err error) {
var domain = kSandboxPublicAppAuthorize
if this.isProduction {
domain = kProductionPublicAppAuthorize
}
var p = url.Values{}
p.Set("app_id", this.appId)
p.Set("scope", strings.Join(scopes, ","))
p.Set("redirect_uri", redirectURI)
if state != "" {
p.Set("state", state)
}
result, err = url.Parse(domain + "?" + p.Encode())
if err != nil {
return nil, err
}
return result, nil
}
// SystemOauthToken 换取授权访问令牌接口 https://docs.open.alipay.com/api_9/alipay.system.oauth.token
func (this *Client) SystemOauthToken(param SystemOauthToken) (result *SystemOauthTokenRsp, err error) {
err = this.doRequest("POST", param, &result)
if result != nil {
if result.Error != nil {
result.Content.Code = Code(result.Error.Code)
result.Content.Msg = result.Error.Msg
result.Content.SubCode = result.Error.SubCode
result.Content.SubMsg = result.Error.SubMsg
} else {
result.Content.Code = CodeSuccess
}
}
return result, err
}
// UserInfoShare 支付宝会员授权信息查询接口 https://docs.open.alipay.com/api_2/alipay.user.info.share
func (this *Client) UserInfoShare(param UserInfoShare) (result *UserInfoShareRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// AppToAppAuth 第三方应用授权接口 https://docs.open.alipay.com/20160728150111277227/intro
func (this *Client) AppToAppAuth(redirectURI string) (result *url.URL, err error) {
var domain = kSandboxAppToAppAuth
if this.isProduction {
domain = kProductionAppToAppAuth
}
var p = url.Values{}
p.Set("app_id", this.appId)
p.Set("redirect_uri", redirectURI)
result, err = url.Parse(domain + "?" + p.Encode())
if err != nil {
return nil, err
}
return result, nil
}
// OpenAuthTokenApp 换取应用授权令牌接口 https://docs.open.alipay.com/api_9/alipay.open.auth.token.app
func (this *Client) OpenAuthTokenApp(param OpenAuthTokenApp) (result *OpenAuthTokenAppRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// AccountAuth 支付宝登录时, 帮客户端做参数签名, 返回授权请求信息字串接口 https://docs.open.alipay.com/218/105327
func (this *Client) AccountAuth(param AccountAuth) (result string, err error) {
var p = url.Values{}
p.Add("app_id", this.appId)
p.Add("method", param.APIName())
var ps = param.Params()
if ps != nil {
for key, value := range ps {
p.Add(key, value)
}
}
p.Add("sign_type", kSignTypeRSA2)
sign, err := signWithPKCS1v15(p, this.appPrivateKey, crypto.SHA256)
if err != nil {
return "", err
}
p.Add("sign", sign)
return p.Encode(), err
}
package alipay
const (
kProductionPublicAppAuthorize = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm"
kSandboxPublicAppAuthorize = "https://openauth.alipaydev.com/oauth2/publicAppAuthorize.htm"
)
const (
kProductionAppToAppAuth = "https://openauth.alipay.com/oauth2/appToAppAuth.htm"
kSandboxAppToAppAuth = "https://openauth.alipaydev.com/oauth2/appToAppAuth.htm"
)
// SystemOauthToken 换取授权访问令牌接口请求参数 https://docs.open.alipay.com/api_9/alipay.system.oauth.token
type SystemOauthToken struct {
AppAuthToken string `json:"-"` // 可选
GrantType string `json:"-"` // 值为 authorization_code 时,代表用code换取;值为refresh_token时,代表用refresh_token换取
Code string `json:"-"`
RefreshToken string `json:"-"`
}
func (this SystemOauthToken) APIName() string {
return "alipay.system.oauth.token"
}
func (this SystemOauthToken) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["grant_type"] = this.GrantType
if this.Code != "" {
m["code"] = this.Code
}
if this.RefreshToken != "" {
m["refresh_token"] = this.RefreshToken
}
return m
}
// SystemOauthTokenRsp 换取授权访问令牌接口请求参数
type SystemOauthTokenRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
UserId string `json:"user_id"`
AccessToken string `json:"access_token"`
ExpiresIn int64 `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
ReExpiresIn int64 `json:"re_expires_in"`
} `json:"alipay_system_oauth_token_response"`
Error *struct {
Code string `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
} `json:"error_response"` // 不要访问此结构体
Sign string `json:"sign"`
}
// UserInfoShare 支付宝会员授权信息查询接口请求参数 https://docs.open.alipay.com/api_2/alipay.user.info.share
type UserInfoShare struct {
AppAuthToken string `json:"-"` // 可选
AuthToken string `json:"-"` // 是
}
func (this UserInfoShare) APIName() string {
return "alipay.user.info.share"
}
func (this UserInfoShare) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["auth_token"] = this.AuthToken
return m
}
// UserInfoShareRsp 支付宝会员授权信息查询接口响应参数
type UserInfoShareRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
AuthNo string `json:"auth_no"`
UserId string `json:"user_id"`
Avatar string `json:"avatar"`
Province string `json:"province"`
City string `json:"city"`
NickName string `json:"nick_name"`
IsStudentCertified string `json:"is_student_certified"`
UserType string `json:"user_type"`
UserStatus string `json:"user_status"`
IsCertified string `json:"is_certified"`
Gender string `json:"gender"`
} `json:"alipay_user_info_share_response"`
Sign string `json:"sign"`
}
// OpenAuthTokenApp 换取应用授权令牌请求参数 https://docs.open.alipay.com/api_9/alipay.open.auth.token.app
type OpenAuthTokenApp struct {
GrantType string `json:"grant_type"` // 值为 authorization_code 时,代表用code换取;值为refresh_token时,代表用refresh_token换取
Code string `json:"code"`
RefreshToken string `json:"refresh_token"`
}
func (this OpenAuthTokenApp) APIName() string {
return "alipay.open.auth.token.app"
}
func (this OpenAuthTokenApp) Params() map[string]string {
var m = make(map[string]string)
m["grant_type"] = this.GrantType
if this.Code != "" {
m["code"] = this.Code
}
if this.RefreshToken != "" {
m["refresh_token"] = this.RefreshToken
}
return m
}
// OpenAuthTokenAppRsp 换取应用授权令牌响应参数 新版返回值 参见 https://opendocs.alipay.com/open/20160728150111277227/intro
type OpenAuthTokenAppRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode Code `json:"sub_code"`
SubMsg string `json:"sub_msg"`
Tokens []*OpenAuthToken `json:"tokens"`
} `json:"alipay_open_auth_token_app_response"`
Sign string `json:"sign"`
}
type OpenAuthToken struct {
AppAuthToken string `json:"app_auth_token"` // 授权令牌信息
AppRefreshToken string `json:"app_refresh_token"` // 令牌信息
AuthAppId string `json:"auth_app_id"` // 授权方应用id
ExpiresIn int64 `json:"expires_in"` // 令牌有效期
ReExpiresIn int64 `json:"re_expires_in"` // 有效期
UserId string `json:"user_id"` // 支付宝用户标识
}
// AccountAuth 支付宝登录时, 帮客户端做参数签名, 返回授权请求信息字串接口请求参数 https://docs.open.alipay.com/218/105327/
type AccountAuth struct {
Pid string `json:"pid"`
TargetId string `json:"target_id"`
AuthType string `json:"auth_type"`
}
func (this AccountAuth) APIName() string {
return "alipay.open.auth.sdk.code.get"
}
func (this AccountAuth) Params() map[string]string {
var m = make(map[string]string)
m["apiname"] = "com.alipay.account.auth"
m["app_name"] = "mc"
m["biz_type"] = "openservice"
m["pid"] = this.Pid
m["product_id"] = "APP_FAST_LOGIN"
m["scope"] = "kuaijie"
m["target_id"] = this.TargetId
m["auth_type"] = this.AuthType
return m
}
package alipay
import (
"errors"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
var (
kSuccess = []byte("success")
)
func NewRequest(method, url string, params url.Values) (*http.Request, error) {
var m = strings.ToUpper(method)
var body io.Reader
if m == "GET" || m == "HEAD" {
if len(params) > 0 {
if strings.Contains(url, "?") {
url = url + "&" + params.Encode()
} else {
url = url + "?" + params.Encode()
}
}
} else {
body = strings.NewReader(params.Encode())
}
return http.NewRequest(m, url, body)
}
func (this *Client) NotifyVerify(partnerId, notifyId string) bool {
var param = url.Values{}
param.Add("service", "notify_verify")
param.Add("partner", partnerId)
param.Add("notify_id", notifyId)
req, err := NewRequest("GET", this.notifyVerifyDomain, param)
if err != nil {
return false
}
rep, err := this.Client.Do(req)
if err != nil {
return false
}
defer rep.Body.Close()
data, err := ioutil.ReadAll(rep.Body)
if err != nil {
return false
}
if string(data) == "true" {
return true
}
return false
}
func (this *Client) GetTradeNotification(req *http.Request) (noti *TradeNotification, err error) {
if req == nil {
return nil, errors.New("request 参数不能为空")
}
if err = req.ParseForm(); err != nil {
return nil, err
}
noti = &TradeNotification{}
noti.AppId = req.FormValue("app_id")
noti.AuthAppId = req.FormValue("auth_app_id")
noti.NotifyId = req.FormValue("notify_id")
noti.NotifyType = req.FormValue("notify_type")
noti.NotifyTime = req.FormValue("notify_time")
noti.TradeNo = req.FormValue("trade_no")
noti.TradeStatus = TradeStatus(req.FormValue("trade_status"))
noti.TotalAmount = req.FormValue("total_amount")
noti.ReceiptAmount = req.FormValue("receipt_amount")
noti.InvoiceAmount = req.FormValue("invoice_amount")
noti.BuyerPayAmount = req.FormValue("buyer_pay_amount")
noti.SellerId = req.FormValue("seller_id")
noti.SellerEmail = req.FormValue("seller_email")
noti.BuyerId = req.FormValue("buyer_id")
noti.BuyerLogonId = req.FormValue("buyer_logon_id")
noti.FundBillList = req.FormValue("fund_bill_list")
noti.Charset = req.FormValue("charset")
noti.PointAmount = req.FormValue("point_amount")
noti.OutTradeNo = req.FormValue("out_trade_no")
noti.OutBizNo = req.FormValue("out_biz_no")
noti.GmtCreate = req.FormValue("gmt_create")
noti.GmtPayment = req.FormValue("gmt_payment")
noti.GmtRefund = req.FormValue("gmt_refund")
noti.GmtClose = req.FormValue("gmt_close")
noti.Subject = req.FormValue("subject")
noti.Body = req.FormValue("body")
noti.RefundFee = req.FormValue("refund_fee")
noti.Version = req.FormValue("version")
noti.SignType = req.FormValue("sign_type")
noti.Sign = req.FormValue("sign")
noti.PassbackParams = req.FormValue("passback_params")
noti.VoucherDetailList = req.FormValue("voucher_detail_list")
noti.AgreementNo = req.FormValue("agreement_no")
noti.ExternalAgreementNo = req.FormValue("external_agreement_no")
//if len(noti.NotifyId) == 0 {
// return nil, errors.New("不是有效的 Notify")
//}
ok, err := this.VerifySign(req.Form)
if ok == false {
return nil, err
}
return noti, err
}
func (this *Client) AckNotification(w http.ResponseWriter) {
AckNotification(w)
}
func AckNotification(w http.ResponseWriter) {
w.WriteHeader(http.StatusOK)
w.Write(kSuccess)
}
package alipay
const (
NotifyTypeTradeStatusSync = "trade_status_sync"
)
// TradeNotification 通知响应参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.8AmJwg&treeId=203&articleId=105286&docType=1
type TradeNotification struct {
AuthAppId string `json:"auth_app_id"` // App Id
NotifyTime string `json:"notify_time"` // 通知时间
NotifyType string `json:"notify_type"` // 通知类型
NotifyId string `json:"notify_id"` // 通知校验ID
AppId string `json:"app_id"` // 开发者的app_id
Charset string `json:"charset"` // 编码格式
Version string `json:"version"` // 接口版本
SignType string `json:"sign_type"` // 签名类型
Sign string `json:"sign"` // 签名
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"` // 商户订单号
OutBizNo string `json:"out_biz_no"` // 商户业务号
BuyerId string `json:"buyer_id"` // 买家支付宝用户号
BuyerLogonId string `json:"buyer_logon_id"` // 买家支付宝账号
SellerId string `json:"seller_id"` // 卖家支付宝用户号
SellerEmail string `json:"seller_email"` // 卖家支付宝账号
TradeStatus TradeStatus `json:"trade_status"` // 交易状态
TotalAmount string `json:"total_amount"` // 订单金额
ReceiptAmount string `json:"receipt_amount"` // 实收金额
InvoiceAmount string `json:"invoice_amount"` // 开票金额
BuyerPayAmount string `json:"buyer_pay_amount"` // 付款金额
PointAmount string `json:"point_amount"` // 集分宝金额
RefundFee string `json:"refund_fee"` // 总退款金额
Subject string `json:"subject"` // 商品的标题/交易标题/订单标题/订单关键字等,是请求时对应的参数,原样通知回来。
Body string `json:"body"` // 商品描述
GmtCreate string `json:"gmt_create"` // 交易创建时间
GmtPayment string `json:"gmt_payment"` // 交易付款时间
GmtRefund string `json:"gmt_refund"` // 交易退款时间
GmtClose string `json:"gmt_close"` // 交易结束时间
FundBillList string `json:"fund_bill_list"` // 支付金额信息
PassbackParams string `json:"passback_params"` // 回传参数
VoucherDetailList string `json:"voucher_detail_list"` // 优惠券信息
AgreementNo string `json:"agreement_no"` //支付宝签约号
ExternalAgreementNo string `json:"external_agreement_no"` // 商户自定义签约号
}
package alipay
import (
"net/url"
)
// TradePagePay 统一收单下单并支付页面接口 https://docs.open.alipay.com/api_1/alipay.trade.page.pay
func (this *Client) TradePagePay(param TradePagePay) (result *url.URL, err error) {
p, err := this.URLValues(param)
if err != nil {
return nil, err
}
result, err = url.Parse(this.apiDomain + "?" + p.Encode())
if err != nil {
return nil, err
}
return result, err
}
// TradeAppPay App支付接口 https://docs.open.alipay.com/api_1/alipay.trade.app.pay
func (this *Client) TradeAppPay(param TradeAppPay) (result string, err error) {
p, err := this.URLValues(param)
if err != nil {
return "", err
}
return p.Encode(), err
}
// TradeFastPayRefundQuery 统一收单交易退款查询接口 https://docs.open.alipay.com/api_1/alipay.trade.fastpay.refund.query
func (this *Client) TradeFastPayRefundQuery(param TradeFastPayRefundQuery) (result *TradeFastPayRefundQueryRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeOrderSettle 统一收单交易结算接口 https://docs.open.alipay.com/api_1/alipay.trade.order.settle
func (this *Client) TradeOrderSettle(param TradeOrderSettle) (result *TradeOrderSettleRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeClose 统一收单交易关闭接口 https://docs.open.alipay.com/api_1/alipay.trade.close/
func (this *Client) TradeClose(param TradeClose) (result *TradeCloseRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeCancel 统一收单交易撤销接口 https://docs.open.alipay.com/api_1/alipay.trade.cancel/
func (this *Client) TradeCancel(param TradeCancel) (result *TradeCancelRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeRefund 统一收单交易退款接口 https://docs.open.alipay.com/api_1/alipay.trade.refund/
func (this *Client) TradeRefund(param TradeRefund) (result *TradeRefundRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradePreCreate 统一收单线下交易预创建接口 https://docs.open.alipay.com/api_1/alipay.trade.precreate/
func (this *Client) TradePreCreate(param TradePreCreate) (result *TradePreCreateRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeQuery 统一收单线下交易查询接口 https://docs.open.alipay.com/api_1/alipay.trade.query/
func (this *Client) TradeQuery(param TradeQuery) (result *TradeQueryRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeCreate 统一收单交易创建接口 https://docs.open.alipay.com/api_1/alipay.trade.create/
func (this *Client) TradeCreate(param TradeCreate) (result *TradeCreateRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradePay 统一收单交易支付接口 https://docs.open.alipay.com/api_1/alipay.trade.pay/
func (this *Client) TradePay(param TradePay) (result *TradePayRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeOrderInfoSync 支付宝订单信息同步接口 https://docs.open.alipay.com/api_1/alipay.trade.orderinfo.sync/
func (this *Client) TradeOrderInfoSync(param TradeOrderInfoSync) (result *TradeOrderInfoSyncRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeRefundAsync 统一收单交易退款(异步)接口 https://opendocs.alipay.com/pre-apis/api_pre/alipay.trade.refund.apply
func (this *Client) TradeRefundAsync(param TradeRefundAsync) (result *TradeRefundAsyncRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeSettleConfirm 统一收单确认结算接口请求参数 https://opendocs.alipay.com/open/028xqy
func (this *Client) TradeSettleConfirm(param TradeSettleConfirm) (result *TradeSettleConfirmRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
package alipay
// TradeRefundAsync 统一收单交易退款接口(异步)请求参数 https://opendocs.alipay.com/pre-apis/api_pre/alipay.trade.refund.apply
type TradeRefundAsync struct {
AppAuthToken string `json:"-"` // 可选
NotifyURL string `json:"-"` // 可选
OutTradeNo string `json:"out_trade_no,omitempty"` // 与 TradeNo 二选一
TradeNo string `json:"trade_no,omitempty"` // 与 OutTradeNo 二选一
RefundAmount string `json:"refund_amount"` // 必须 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数
RefundReason string `json:"refund_reason"` // 可选 退款的原因说明
OutRequestNo string `json:"out_request_no"` // 必须 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。
OperatorId string `json:"operator_id"` // 可选 商户的操作员编号
StoreId string `json:"store_id"` // 可选 商户的门店编号
TerminalId string `json:"terminal_id"` // 可选 商户的终端编号
}
func (this TradeRefundAsync) APIName() string {
return "alipay.trade.refund.apply"
}
func (this TradeRefundAsync) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
return m
}
// TradeRefundAsyncRsp 统一收单交易退款接口(异步)响应参数
type TradeRefundAsyncRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"` // 商户订单号
OutRequestNo string `json:"out_request_no"` // 本笔退款对应的退款请求号
RefundAmount string `json:"refund_amount"` // 本次退款请求,对应的退款金额
RefundStatus string `json:"refund_status"` // REFUND_PROCESSING 退款处理中;REFUND_SUCCESS 退款处理成功;REFUND_FAIL 退款失败
} `json:"alipay_trade_refund_apply_response"`
Sign string `json:"sign"`
}
func (this *TradeRefundAsyncRsp) IsSuccess() bool {
return this.Content.Code == CodeSuccess
}
package alipay
type Trade struct {
NotifyURL string `json:"-"`
ReturnURL string `json:"-"`
AppAuthToken string `json:"-"` // 可选
// biz content,这四个参数是必须的
Subject string `json:"subject"` // 订单标题
OutTradeNo string `json:"out_trade_no"` // 商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复
TotalAmount string `json:"total_amount"` // 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
ProductCode string `json:"product_code"` // 销售产品码,与支付宝签约的产品码名称。 参考官方文档, App 支付时默认值为 QUICK_MSECURITY_PAY
Body string `json:"body,omitempty"` // 订单描述
BusinessParams string `json:"business_params,omitempty"` // 商户传入业务信息,具体值要和支付宝约定,应用于安全,营销等参数直传场景,格式为json格式
DisablePayChannels string `json:"disable_pay_channels,omitempty"` // 禁用渠道,用户不可用指定渠道支付 当有多个渠道时用“,”分隔 注,与enable_pay_channels互斥
EnablePayChannels string `json:"enable_pay_channels,omitempty"` // 可用渠道,用户只能在指定渠道范围内支付 当有多个渠道时用“,”分隔 注,与disable_pay_channels互斥
//ExtUserInfo string `json:"ext_user_info,omitempty"` // 外部指定买家
ExtendParams map[string]interface{} `json:"extend_params,omitempty"` // 业务扩展参数,详见下面的“业务扩展参数说明”
AgreementSignParams interface{} `json:"agreement_sign_params,omitempty"` // 签约参数。如果希望在sdk中支付并签约,需要在这里传入签约信息。 周期扣款场景 product_code 为 CYCLE_PAY_AUTH 时必填。
GoodsType string `json:"goods_type,omitempty"` // 商品主类型:0—虚拟类商品,1—实物类商品 注:虚拟类商品不支持使用花呗渠道
InvoiceInfo string `json:"invoice_info,omitempty"` // 开票信息
PassbackParams string `json:"passback_params,omitempty"` // 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝
PromoParams string `json:"promo_params,omitempty"` // 优惠参数 注:仅与支付宝协商后可用
RoyaltyInfo string `json:"royalty_info,omitempty"` // 描述分账信息,json格式,详见分账参数说明
SellerId string `json:"seller_id,omitempty"` // 收款支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID
SettleInfo *SettleInfo `json:"settle_info,omitempty"` // 描述结算信息,json格式,详见结算参数说明
SpecifiedChannel string `json:"specified_channel,omitempty"` // 指定渠道,目前仅支持传入pcredit  若由于用户原因渠道不可用,用户可选择是否用其他渠道支付。  注:该参数不可与花呗分期参数同时传入
StoreId string `json:"store_id,omitempty"` // 商户门店编号。该参数用于请求参数中以区分各门店,非必传项。
SubMerchant *SubMerchant `json:"sub_merchant,omitempty"` // 间连受理商户信息体,当前只对特殊银行机构特定场景下使用此字段
TimeoutExpress string `json:"timeout_express,omitempty"` // 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。
TimeExpire string `json:"time_expire,omitempty"` // 该笔订单绝对超时时间,格式为yyyy-MM-dd HH:mm:ss
}
type SettleInfo struct {
SettleDetailInfos []*SettleDetailInfo `json:"settle_detail_infos,omitempty"`
}
type SettleDetailInfo struct {
Amount string `json:"amount,omitempty"`
TransInType string `json:"trans_in_type,omitempty"`
}
type SubMerchant struct {
MerchantId string `json:"merchant_id,omitempty"`
}
// TradePagePay 统一收单下单并支付页面接口请求参数 https://opendocs.alipay.com/apis/api_1/alipay.trade.page.pay
type TradePagePay struct {
Trade
AuthToken string `json:"auth_token,omitempty"` // 针对用户授权接口,获取用户相关数据时,用于标识用户授权关系
GoodsDetail []*GoodsDetail `json:"goods_detail,omitempty"` // 订单包含的商品列表信息,Json格式,详见商品明细说明
QRPayMode string `json:"qr_pay_mode,omitempty"` // PC扫码支付的方式,支持前置模式和跳转模式。
QRCodeWidth string `json:"qrcode_width,omitempty"` // 商户自定义二维码宽度 注:qr_pay_mode=4时该参数生效
}
type GoodsDetail struct {
GoodsId string `json:"goods_id"`
AliPayGoodsId string `json:"alipay_goods_id,omitempty"`
GoodsName string `json:"goods_name"`
Quantity int `json:"quantity"`
Price float64 `json:"price"`
GoodsCategory string `json:"goods_category,omitempty"`
CategoriesTree string `json:"categories_tree,omitempty"`
Body string `json:"body,omitempty"`
ShowURL string `json:"show_url,omitempty"`
}
func (this TradePagePay) APIName() string {
return "alipay.trade.page.pay"
}
func (this TradePagePay) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
m["return_url"] = this.ReturnURL
return m
}
type TradeStatus string
const (
TradeStatusWaitBuyerPay TradeStatus = "WAIT_BUYER_PAY" //(交易创建,等待买家付款)
TradeStatusClosed TradeStatus = "TRADE_CLOSED" //(未付款交易超时关闭,或支付完成后全额退款)
TradeStatusSuccess TradeStatus = "TRADE_SUCCESS" //(交易支付成功)
TradeStatusFinished TradeStatus = "TRADE_FINISHED" //(交易结束,不可退款)
)
// TradeQuery 统一收单线下交易查询接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.query/
type TradeQuery struct {
AppAuthToken string `json:"-"` // 可选
OutTradeNo string `json:"out_trade_no,omitempty"` // 订单支付时传入的商户订单号, 与 TradeNo 二选一
TradeNo string `json:"trade_no,omitempty"` // 支付宝交易号
QueryOptions []string `json:"query_options,omitempty"` // 可选 查询选项,商户通过上送该字段来定制查询返回信息 TRADE_SETTLE_INFO
}
func (this TradeQuery) APIName() string {
return "alipay.trade.query"
}
func (this TradeQuery) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
return m
}
// TradeQueryRsp 统一收单线下交易查询接口响应参数
type TradeQueryRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"` // 商家订单号
BuyerLogonId string `json:"buyer_logon_id"` // 买家支付宝账号
TradeStatus TradeStatus `json:"trade_status"` // 交易状态
TotalAmount string `json:"total_amount"` // 交易的订单金额
TransCurrency string `json:"trans_currency"` // 标价币种
SettleCurrency string `json:"settle_currency"` // 订单结算币种
SettleAmount string `json:"settle_amount"` // 结算币种订单金额
PayCurrency string `json:"pay_currency"` // 订单支付币种
PayAmount string `json:"pay_amount"` // 支付币种订单金额
SettleTransRate string `json:"settle_trans_rate"` // 结算币种兑换标价币种汇率
TransPayRate string `json:"trans_pay_rate"` // 标价币种兑换支付币种汇率
BuyerPayAmount string `json:"buyer_pay_amount"` // 买家实付金额,单位为元,两位小数。
PointAmount string `json:"point_amount"` // 积分支付的金额,单位为元,两位小数。
InvoiceAmount string `json:"invoice_amount"` // 交易中用户支付的可开具发票的金额,单位为元,两位小数。
SendPayDate string `json:"send_pay_date"` // 本次交易打款给卖家的时间
ReceiptAmount string `json:"receipt_amount"` // 实收金额,单位为元,两位小数
StoreId string `json:"store_id"` // 商户门店编号
TerminalId string `json:"terminal_id"` // 商户机具终端编号
FundBillList []*FundBill `json:"fund_bill_list,omitempty"` // 交易支付使用的资金渠道
StoreName string `json:"store_name"` // 请求交易支付中的商户店铺的名称
BuyerUserId string `json:"buyer_user_id"` // 买家在支付宝的用户id
ChargeAmount string `json:"charge_amount"` // 该笔交易针对收款方的收费金额;
ChargeFlags string `json:"charge_flags"` // 费率活动标识,当交易享受活动优惠费率时,返回该活动的标识;
SettlementId string `json:"settlement_id"` // 支付清算编号,用于清算对账使用;
AuthTradePayMode string `json:"auth_trade_pay_mode"` // 预授权支付模式,该参数仅在信用预授权支付场景下返回。信用预授权支付:CREDIT_PREAUTH_PAY
BuyerUserType string `json:"buyer_user_type"` // 买家用户类型。CORPORATE:企业用户;PRIVATE:个人用户。
MdiscountAmount string `json:"mdiscount_amount"` // 商家优惠金额
DiscountAmount string `json:"discount_amount"` // 平台优惠金额
BuyerUserName string `json:"buyer_user_name"` // 买家名称;
Subject string `json:"subject"` // 订单标题;
Body string `json:"body"` // 订单描述;
AlipaySubMerchantId string `json:"alipay_sub_merchant_id"` // 间连商户在支付宝端的商户编号;
ExtInfos string `json:"ext_infos"` // 交易额外信息,特殊场景下与支付宝约定返回。
PassbackParams string `json:"passback_params"` // 公用回传参数。返回支付时传入的passback_params参数信息
DiscountGoodsDetail string `json:"discount_goods_detail"` // 本次交易支付所使用的单品券优惠的商品优惠信息
IndustrySepcDetailGov string `json:"industry_sepc_detail_gov"` // 行业特殊信息-统筹相关
IndustrySepcDetailAcc string `json:"industry_sepc_detail_acc"` // 行业特殊信息-个账相关
VoucherDetailList []*VoucherDetail `json:"voucher_detail_list,omitempty"` // 本交易支付时使用的所有优惠券信息
TradeSettleInfo *TradeSettleInfo `json:"trade_settle_info,omitempty"` // 返回的交易结算信息,包含分账、补差等信息
} `json:"alipay_trade_query_response"`
Sign string `json:"sign"`
}
type FundBill struct {
FundChannel string `json:"fund_channel"` // 交易使用的资金渠道,详见 支付渠道列表
BankCode string `json:"bank_code"` // 银行卡支付时的银行代码
Amount string `json:"amount"` // 该支付工具类型所使用的金额
RealAmount float64 `json:"real_amount,string"` // 渠道实际付款金额
}
type VoucherDetail struct {
Id string `json:"id"` // 券id
Name string `json:"name"` // 券名称
Type string `json:"type"` // 当前有三种类型: ALIPAY_FIX_VOUCHER - 全场代金券, ALIPAY_DISCOUNT_VOUCHER - 折扣券, ALIPAY_ITEM_VOUCHER - 单品优惠
Amount string `json:"amount"` // 优惠券面额,它应该会等于商家出资加上其他出资方出资
MerchantContribute string `json:"merchant_contribute"` // 商家出资(特指发起交易的商家出资金额)
OtherContribute string `json:"other_contribute"` // 其他出资方出资金额,可能是支付宝,可能是品牌商,或者其他方,也可能是他们的一起出资
Memo string `json:"memo"` // 优惠券备注信息
}
type TradeSettleInfo struct {
TradeSettleDetailList []*TradeSettleDetail `json:"trade_settle_detail_list"`
}
type TradeSettleDetail struct {
OperationType string `json:"operation_type"`
OperationSerialNo string `json:"operation_serial_no"`
OperationDate string `json:"operation_dt"`
TransOut string `json:"trans_out"`
TransIn string `json:"trans_in"`
Amount string `json:"amount"`
}
func (this *TradeQueryRsp) IsSuccess() bool {
if this.Content.Code == CodeSuccess {
return true
}
return false
}
// TradeClose 统一收单交易关闭接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.close/
type TradeClose struct {
AppAuthToken string `json:"-"` // 可选
NotifyURL string `json:"-"` // 可选
OutTradeNo string `json:"out_trade_no,omitempty"` // 与 TradeNo 二选一
TradeNo string `json:"trade_no,omitempty"` // 与 OutTradeNo 二选一
OperatorId string `json:"operator_id,omitempty"` // 可选
}
func (this TradeClose) APIName() string {
return "alipay.trade.close"
}
func (this TradeClose) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
return m
}
// TradeCloseRsp 统一收单交易关闭接口响应参数
type TradeCloseRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
OutTradeNo string `json:"out_trade_no"`
TradeNo string `json:"trade_no"`
} `json:"alipay_trade_close_response"`
Sign string `json:"sign"`
}
// TradeRefund 统一收单交易退款接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.refund/
type TradeRefund struct {
AppAuthToken string `json:"-"` // 可选
OutTradeNo string `json:"out_trade_no,omitempty"` // 与 TradeNo 二选一
TradeNo string `json:"trade_no,omitempty"` // 与 OutTradeNo 二选一
OutRequestNo string `json:"out_request_no"` // 必须 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。
RefundAmount string `json:"refund_amount"` // 必须 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数
RefundCurrency string `json:"refund_currency"` // 可选 订单退款币种信息
RefundReason string `json:"refund_reason"` // 可选 退款的原因说明
OperatorId string `json:"operator_id"` // 可选 商户的操作员编号
StoreId string `json:"store_id"` // 可选 商户的门店编号
TerminalId string `json:"terminal_id"` // 可选 商户的终端编号
}
func (this TradeRefund) APIName() string {
return "alipay.trade.refund"
}
func (this TradeRefund) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
return m
}
// TradeRefundRsp 统一收单交易退款接口响应参数
type TradeRefundRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"` // 商户订单号
BuyerLogonId string `json:"buyer_logon_id"` // 用户的登录id
BuyerUserId string `json:"buyer_user_id"` // 买家在支付宝的用户id
FundChange string `json:"fund_change"` // 本次退款是否发生了资金变化
RefundFee string `json:"refund_fee"` // 退款总金额
RefundCurrency string `json:"refund_currency"` // 退款币种信息
GmtRefundPay string `json:"gmt_refund_pay"` // 退款支付时间
StoreName string `json:"store_name"` // 交易在支付时候的门店名称
RefundDetailItemList []*RefundDetailItem `json:"refund_detail_item_list,omitempty"` // 退款使用的资金渠道
RefundSettlementId string `json:"refund_settlement_id"` // 退款清算编号,用于清算对账使用;只在银行间联交易场景下返回该信息;
PresentRefundBuyerAmount string `json:"present_refund_buyer_amount"` // 本次退款金额中买家退款金额
PresentRefundDiscountAmount string `json:"present_refund_discount_amount"` // 本次退款金额中平台优惠退款金额
PresentRefundMdiscountAmount string `json:"present_refund_mdiscount_amount"` // 本次退款金额中商家优惠退款金额
SendBackFee string `json:"send_back_fee"`
} `json:"alipay_trade_refund_response"`
Sign string `json:"sign"`
}
func (this *TradeRefundRsp) IsSuccess() bool {
if this.Content.Code == CodeSuccess {
return true
}
return false
}
type RefundDetailItem struct {
FundChannel string `json:"fund_channel"` // 交易使用的资金渠道,详见 支付渠道列表
Amount string `json:"amount"` // 该支付工具类型所使用的金额
RealAmount string `json:"real_amount"` // 渠道实际付款金额
FundType string `json:"fund_type"` // 渠道所使用的资金类型
}
// TradeFastPayRefundQuery 统一收单交易退款查询接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.fastpay.refund.query
type TradeFastPayRefundQuery struct {
AppAuthToken string `json:"-"` // 可选
OutTradeNo string `json:"out_trade_no,omitempty"` // 与 TradeNo 二选一
TradeNo string `json:"trade_no,omitempty"` // 与 OutTradeNo 二选一
OutRequestNo string `json:"out_request_no"` // 必须 请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号
QueryOptions []string `json:"query_options,omitempty"` // 可选 查询选项,商户通过上送该参数来定制同步需要额外返回的信息字段,数组格式。 refund_detail_item_list
}
func (this TradeFastPayRefundQuery) APIName() string {
return "alipay.trade.fastpay.refund.query"
}
func (this TradeFastPayRefundQuery) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
return m
}
// TradeFastPayRefundQueryRsp 统一收单交易退款查询接口响应参数
type TradeFastPayRefundQueryRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"` // 创建交易传入的商户订单号
OutRequestNo string `json:"out_request_no"` // 本笔退款对应的退款请求号
RefundReason string `json:"refund_reason"` // 发起退款时,传入的退款原因
TotalAmount string `json:"total_amount"` // 发该笔退款所对应的交易的订单金额
RefundAmount string `json:"refund_amount"` // 本次退款请求,对应的退款金额
RefundStatus string `json:"refund_status"` // 退款状态。枚举值: REFUND_SUCCESS 退款处理成功; 未返回该字段表示退款请求未收到或者退款失败;
RefundRoyaltys []*RefundRoyalty `json:"refund_royaltys"` // 退分账明细信息
GMTRefundPay string `json:"gmt_refund_pay"` // 退款时间。
RefundDetailItemList []*RefundDetailItem `json:"refund_detail_item_list,omitempty"` // 本次退款使用的资金渠道;
SendBackFee string `json:"send_back_fee"` // 本次商户实际退回金额;
DepositBackInfo []*DepositBackInfo `json:"deposit_back_info"` // 银行卡冲退信息
} `json:"alipay_trade_fastpay_refund_query_response"`
Sign string `json:"sign"`
}
func (this *TradeFastPayRefundQueryRsp) IsSuccess() bool {
if this.Content.Code == CodeSuccess {
return true
}
return false
}
type RefundRoyalty struct {
RefundAmount string `json:"refund_amount"`
RoyaltyType string `json:"royalty_type"`
ResultCode string `json:"result_code"`
TransOut string `json:"trans_out"`
TransOutEmail string `json:"trans_out_email"`
TransIn string `json:"trans_in"`
TransInEmail string `json:"trans_in_email"`
}
type DepositBackInfo struct {
HasDepositBack string `json:"has_deposit_back"`
DBackStatus string `json:"dback_status"`
DBackAmount string `json:"dback_amount"`
BankAckTime string `json:"bank_ack_time"`
ESTBankReceiptTime string `json:"est_bank_receipt_time"`
}
// TradeOrderSettle 统一收单交易结算接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.order.settle
type TradeOrderSettle struct {
AppAuthToken string `json:"-"` // 可选
OutRequestNo string `json:"out_request_no"` // 必须 结算请求流水号 开发者自行生成并保证唯一性
TradeNo string `json:"trade_no"` // 必须 支付宝订单号
RoyaltyParameters []*RoyaltyParameter `json:"royalty_parameters"` // 必须 分账明细信息
OperatorId string `json:"operator_id"` //可选 操作员id
}
func (this TradeOrderSettle) APIName() string {
return "alipay.trade.order.settle"
}
func (this TradeOrderSettle) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
return m
}
type RoyaltyParameter struct {
TransOut string `json:"trans_out"` // 可选 分账支出方账户,类型为userId,本参数为要分账的支付宝账号对应的支付宝唯一用户号。以2088开头的纯16位数字。
TransIn string `json:"trans_in"` // 可选 分账收入方账户,类型为userId,本参数为要分账的支付宝账号对应的支付宝唯一用户号。以2088开头的纯16位数字。
Amount float64 `json:"amount"` // 可选 分账的金额,单位为元
AmountPercentage float64 `json:"amount_percentage,omitempty"` // 可选 分账信息中分账百分比。取值范围为大于0,少于或等于100的整数。
Desc string `json:"desc"` // 可选 分账描述
}
// TradeOrderSettleRsp 统一收单交易结算接口响应参数
type TradeOrderSettleRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"`
} `json:"alipay_trade_order_settle_response"`
Sign string `json:"sign"`
}
// TradeCreate 统一收单交易创建接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.create/
type TradeCreate struct {
Trade
DiscountableAmount string `json:"discountable_amount"` // 可打折金额. 参与优惠计算的金额,单位为元,精确到小数点后两位
BuyerId string `json:"buyer_id"`
GoodsDetail []*GoodsDetailItem `json:"goods_detail,omitempty"`
OperatorId string `json:"operator_id"`
TerminalId string `json:"terminal_id"`
}
func (this TradeCreate) APIName() string {
return "alipay.trade.create"
}
func (this TradeCreate) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
return m
}
// TradeCreateRsp 统一收单交易创建接口响应参数
type TradeCreateRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"`
} `json:"alipay_trade_create_response"`
Sign string `json:"sign"`
}
type RoyaltyInfo struct {
RoyaltyType string `json:"royalty_type"`
RoyaltyDetailInfo []*RoyaltyDetailInfoItem `json:"royalty_detail_infos,omitempty"`
}
type RoyaltyDetailInfoItem struct {
SerialNo string `json:"serial_no"`
TransInType string `json:"trans_in_type"`
BatchNo string `json:"batch_no"`
OutRelationId string `json:"out_relation_id"`
TransOutType string `json:"trans_out_type"`
TransOut string `json:"trans_out"`
TransIn string `json:"trans_in"`
Amount string `json:"amount"`
Desc string `json:"desc"`
AmountPercentage string `json:"amount_percentage"`
AliPayStoreId string `json:"alipay_store_id"`
}
type SubMerchantItem struct {
MerchantId string `json:"merchant_id"`
}
type GoodsDetailItem struct {
GoodsId string `json:"goods_id"`
AliPayGoodsId string `json:"alipay_goods_id"`
GoodsName string `json:"goods_name"`
Quantity string `json:"quantity"`
Price string `json:"price"`
GoodsCategory string `json:"goods_category"`
Body string `json:"body"`
ShowUrl string `json:"show_url"`
}
type AgreementParams struct {
AgreementNo string `json:"agreement_no,omitempty"`
AuthConfirmNo string `json:"auth_confirm_no,omitempty"`
ApplyToken string `json:"apply_token,omitempty"`
}
// TradePay 统一收单交易支付接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.pay/
type TradePay struct {
Trade
Scene string `json:"scene"` // 必须 支付场景 条码支付,取值:bar_code 声波支付,取值:wave_code, bar_code, wave_code
AuthCode string `json:"auth_code,omitempty"` // 必须 支付授权码
AuthNo string `json:"auth_no,omitempty"` // 可选 预授权冻结交易号
BuyerId string `json:"buyer_id"` // 可选 家的支付宝用户id,如果为空,会从传入了码值信息中获取买家ID
TransCurrency string `json:"trans_currency,omitempty"`
SettleCurrency string `json:"settle_currency,omitempty"`
DiscountableAmount string `json:"discountable_amount,omitempty"` // 可选 参与优惠计算的金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]。 如果该值未传入,但传入了【订单总金额】和【不可打折金额】,则该值默认为【订单总金额】-【不可打折金额】
GoodsDetail []*GoodsDetailItem `json:"goods_detail,omitempty"` // 可选 订单包含的商品列表信息,Json格式,其它说明详见商品明细说明
OperatorId string `json:"operator_id,omitempty"` // 可选 商户操作员编号
TerminalId string `json:"terminal_id,omitempty"` // 可选 商户机具终端编号
AuthConfirmMode string `json:"auth_confirm_mode,omitempty"`
TerminalParams string `json:"terminal_params,omitempty"`
AgreementParams *AgreementParams `json:"agreement_params,omitempty"`
}
func (this TradePay) APIName() string {
return "alipay.trade.pay"
}
func (this TradePay) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
return m
}
// TradePayRsp 统一收单交易支付接口响应参数
type TradePayRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
BuyerLogonId string `json:"buyer_logon_id"` // 买家支付宝账号
BuyerPayAmount string `json:"buyer_pay_amount"` // 买家实付金额,单位为元,两位小数。
BuyerUserId string `json:"buyer_user_id"` // 买家在支付宝的用户id
CardBalance string `json:"card_balance"` // 支付宝卡余额
DiscountGoodsDetail string `json:"discount_goods_detail"` // 本次交易支付所使用的单品券优惠的商品优惠信息
FundBillList []*FundBill `json:"fund_bill_list,omitempty"` // 交易支付使用的资金渠道
GmtPayment string `json:"gmt_payment"`
InvoiceAmount string `json:"invoice_amount"` // 交易中用户支付的可开具发票的金额,单位为元,两位小数。
OutTradeNo string `json:"out_trade_no"` // 创建交易传入的商户订单号
TradeNo string `json:"trade_no"` // 支付宝交易号
PointAmount string `json:"point_amount"` // 积分支付的金额,单位为元,两位小数。
ReceiptAmount string `json:"receipt_amount"` // 实收金额,单位为元,两位小数
StoreName string `json:"store_name"` // 发生支付交易的商户门店名称
TotalAmount string `json:"total_amount"` // 发该笔退款所对应的交易的订单金额
VoucherDetailList []*VoucherDetail `json:"voucher_detail_list,omitempty"` // 本交易支付时使用的所有优惠券信息
} `json:"alipay_trade_pay_response"`
Sign string `json:"sign"`
}
func (this *TradePayRsp) IsSuccess() bool {
if this.Content.Code == CodeSuccess {
return true
}
return false
}
// TradeAppPay App支付接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.app.pay/
type TradeAppPay struct {
Trade
TimeExpire string `json:"time_expire,omitempty"` // 绝对超时时间,格式为yyyy-MM-dd HH:mm。
GoodsDetail []*GoodsDetail `json:"goods_detail,omitempty"` // 订单包含的商品列表信息,Json格式,详见商品明细说明
}
func (this TradeAppPay) APIName() string {
return "alipay.trade.app.pay"
}
func (this TradeAppPay) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
return m
}
// TradePreCreate 统一收单线下交易预创建接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.precreate/
type TradePreCreate struct {
Trade
DiscountableAmount string `json:"discountable_amount"` // 可选 可打折金额. 参与优惠计算的金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 如果该值未传入,但传入了【订单总金额】,【不可打折金额】则该值默认为【订单总金额】-【不可打折金额】
GoodsDetail []*GoodsDetailItem `json:"goods_detail,omitempty"` // 可选 订单包含的商品列表信息.Json格式. 其它说明详见:“商品明细说明”
OperatorId string `json:"operator_id"` // 可选 商户操作员编号
TerminalId string `json:"terminal_id"` // 可选 商户机具终端编号
}
func (this TradePreCreate) APIName() string {
return "alipay.trade.precreate"
}
func (this TradePreCreate) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
return m
}
// TradePreCreateRsp 统一收单线下交易预创建接口响应参数
type TradePreCreateRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
OutTradeNo string `json:"out_trade_no"` // 创建交易传入的商户订单号
QRCode string `json:"qr_code"` // 当前预下单请求生成的二维码码串,可以用二维码生成工具根据该码串值生成对应的二维码
} `json:"alipay_trade_precreate_response"`
Sign string `json:"sign"`
}
func (this *TradePreCreateRsp) IsSuccess() bool {
if this.Content.Code == CodeSuccess {
return true
}
return false
}
// TradeCancel 统一收单交易撤销接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.cancel/
type TradeCancel struct {
AppAuthToken string `json:"-"` // 可选
NotifyURL string `json:"-"` // 可选
OutTradeNo string `json:"out_trade_no"` // 原支付请求的商户订单号,和支付宝交易号不能同时为空
TradeNo string `json:"trade_no"` // 支付宝交易号,和商户订单号不能同时为空
}
func (this TradeCancel) APIName() string {
return "alipay.trade.cancel"
}
func (this TradeCancel) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
return m
}
// TradeCancelRsp 统一收单交易撤销接口响应参数
type TradeCancelRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"` // 创建交易传入的商户订单号
RetryFlag string `json:"retry_flag"` // 是否需要重试
Action string `json:"action"` // 本次撤销触发的交易动作 close:关闭交易,无退款 refund:产生了退款
} `json:"alipay_trade_cancel_response"`
Sign string `json:"sign"`
}
func (this *TradeCancelRsp) IsSuccess() bool {
if this.Content.Code == CodeSuccess {
return true
}
return false
}
// TradeOrderInfoSync 支付宝订单信息同步接口请求参数 https://docs.open.alipay.com/api_1/alipay.trade.orderinfo.sync/
type TradeOrderInfoSync struct {
AppAuthToken string `json:"-"` // 可选
OutRequestNo string `json:"out_request_no"` // 必选 标识一笔交易多次请求,同一笔交易多次信息同步时需要保证唯一
BizType string `json:"biz_type"` // 必选 交易信息同步对应的业务类型,具体值与支付宝约定;信用授权场景下传CREDIT_AUTH
TradeNo string `json:"trade_no"` // 可选 支付宝交易号,和商户订单号不能同时为空
OrderBizInfo string `json:"order_biz_info"` // 可选 商户传入同步信息,具体值要和支付宝约定;用于芝麻信用租车、单次授权等信息同步场景,格式为json格式
}
func (this TradeOrderInfoSync) APIName() string {
return "alipay.trade.orderinfo.sync"
}
func (this TradeOrderInfoSync) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
return m
}
// TradeOrderInfoSyncRsp 支付宝订单信息同步接口响应参数
type TradeOrderInfoSyncRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"`
OutTradeNo string `json:"out_trade_no"`
BuyerUserId string `json:"buyer_user_id"`
} `json:"alipay_trade_orderinfo_sync_response"`
Sign string `json:"sign"`
}
// TradeSettleConfirm 统一收单确认结算接口请求参数 https://opendocs.alipay.com/open/028xqy
type TradeSettleConfirm struct {
AppAuthToken string `json:"-"` // 可选
OutRequestNo string `json:"out_request_no,omitempty"`
TradeNo string `json:"trade_no,omitempty"`
SettleInfo *TradeSettleConfirmSettleInfo `json:"settle_info,omitempty"`
ExtendParams *TradeSettleConfirmExtendParams `json:"extend_params,omitempty"`
}
func (this TradeSettleConfirm) APIName() string {
return "alipay.trade.settle.confirm"
}
func (this TradeSettleConfirm) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
return m
}
type TradeSettleConfirmSettleInfo struct {
SettleDetailInfos []*TradeSettleConfirmSettleInfoDetail `json:"settle_detail_infos,omitempty"`
SettlePeriodTime string `json:"settle_period_time,omitempty"`
}
type TradeSettleConfirmSettleInfoDetail struct {
TransInType string `json:"trans_in_type,omitempty"`
TransIn string `json:"trans_in,omitempty"`
SummaryDimension string `json:"summary_dimension,omitempty"`
SettleEntityId string `json:"settle_entity_id,omitempty"`
SettleEntityType string `json:"settle_entity_type,omitempty"`
Amount string `json:"amount,omitempty"`
}
type TradeSettleConfirmExtendParams struct {
RoyaltyFreeze string `json:"royalty_freeze,omitempty"`
}
// TradeSettleConfirmRsp 统一收单确认结算接口响应参数
type TradeSettleConfirmRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"`
OutRequestNo string `json:"out_request_no"`
SettleAmount float64 `json:"settle_amount"`
} `json:"alipay_trade_settle_confirm_response"`
Sign string `json:"sign"`
}
package lib_allinpay
import (
"crypto/aes"
"crypto/sha1"
"encoding/hex"
"errors"
"strings"
)
func AesEncryptECB(orgDataStr, keyStr string) (string, error) {
src := []byte(orgDataStr)
key := []byte(keyStr)
key, err := AesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return "", err
}
cipher, _ := aes.NewCipher(generateKey(key))
length := (len(src) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, src)
pad := byte(len(plain) - len(src))
for i := len(src); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
// 分组分块加密
for bs, be := 0, cipher.BlockSize(); bs <= len(src); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return strings.ToUpper(hex.EncodeToString(encrypted)), nil
}
func AesDecryptECB(encryptedStr, keyStr string) (string, error) {
encrypted, err := hex.DecodeString(strings.ToLower(encryptedStr))
if err != nil {
return "", err
}
key := []byte(keyStr)
key, err = AesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return "", err
}
cipher, _ := aes.NewCipher(generateKey(key))
decrypted := make([]byte, len(encrypted))
//
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return string(decrypted[:trim]), nil
}
func AesSha1prng(keyBytes []byte, encryptLength int) ([]byte, error) {
hashs := Sha1(Sha1(keyBytes))
maxLen := len(hashs)
realLen := encryptLength / 8
if realLen > maxLen {
return nil, errors.New("invalid length!")
}
return hashs[0:realLen], nil
}
func Sha1(data []byte) []byte {
h := sha1.New()
h.Write(data)
return h.Sum(nil)
}
func generateKey(key []byte) (genKey []byte) {
genKey = make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return genKey
}
package lib_allinpay
import (
"crypto"
"crypto/md5"
"crypto/rsa"
"encoding/base64"
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"git.168cad.top/zhengqiuyun/rym-util/a/util"
"io"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
type Client struct {
httpClient *http.Client
privateKey *rsa.PrivateKey
tlPublicKey *rsa.PublicKey
}
func New(privateKeyPath, pwd, tlPublicKeyPath string) (*Client, error) {
var client = Client{}
privateKey, err := getPrivateKey(privateKeyPath, pwd)
if err != nil {
return nil, err
}
client.privateKey = privateKey
publicKey, err := loadPublicKeyWithPath(tlPublicKeyPath)
if err != nil {
return nil, err
}
client.tlPublicKey = publicKey
client.httpClient = http.DefaultClient
return &client, nil
}
func (c *Client) doRequest(method string, param Param, result interface{}) (err error) {
var buf io.Reader
requestStr := ""
if param != nil {
p, err := c.URLValues(param)
if err != nil {
return err
}
requestStr = p.Encode()
buf = strings.NewReader(requestStr)
}
log.Debug(fmt.Sprintf("请求参数:%s", requestStr))
req, err := http.NewRequest(method, conf.AllinpayUrl, buf)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
resp, err := c.httpClient.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
log.Debug(fmt.Sprintf("请求结果:%s", string(data)))
ok, err := verifyData(data, c.tlPublicKey)
if err != nil {
return err
}
if !ok {
exception.ThrowsErrS("请求结果校验错误,请检查公钥配置")
}
err = json.Unmarshal(data, result)
if err != nil {
return err
}
return err
}
func verifyData(data []byte, key *rsa.PublicKey) (ok bool, err error) {
sign := ""
dataMap := make(map[string]interface{})
err = json.Unmarshal(data, &dataMap)
var sortKeys = util.SortKeys(dataMap)
signDataMap := make(map[string]interface{})
for _, k := range sortKeys {
if k == "sign" {
sign = dataMap[k].(string)
} else {
signDataMap[k] = dataMap[k]
}
}
signDataByte, _ := json.Marshal(signDataMap)
md5Str := md5B(signDataByte)
signBytes, err := base64.StdEncoding.DecodeString(sign)
if err != nil {
return false, err
}
if err = RSAVerifyWithKey([]byte(md5Str), signBytes, key, crypto.SHA256); err != nil {
return false, err
}
return true, nil
}
func (c *Client) URLValues(param Param) (value url.Values, err error) {
var p = url.Values{}
p.Add("appId", conf.AllinpayAppId)
p.Add("method", param.apiName())
p.Add("format", "JSON")
p.Add("charset", "utf-8")
p.Add("timestamp", util.FormatDateTime(time.Now()))
p.Add("version", "1.0")
bytes, err := json.Marshal(param)
if err != nil {
return nil, err
}
p.Add("bizContent", string(bytes))
sign, err := signWithPKCS1v15(p, c.privateKey, crypto.SHA256)
if err != nil {
return nil, err
}
p.Add("sign", sign)
p.Add("signType", "SHA256WithRSA")
return p, nil
}
func signWithPKCS1v15(param url.Values, privateKey *rsa.PrivateKey, hash crypto.Hash) (s string, err error) {
if param == nil {
param = make(url.Values, 0)
}
var pList = make([]string, 0, 0)
for key := range param {
var value = strings.TrimSpace(param.Get(key))
if len(value) > 0 {
pList = append(pList, key+"="+value)
}
}
sort.Strings(pList)
var src = strings.Join(pList, "&")
log.Debug(fmt.Sprintf("签名数据:%s", src))
md5Str := md5S(src)
sig, err := RSASignWithKey([]byte(md5Str), privateKey, hash)
if err != nil {
return "", err
}
s = base64.StdEncoding.EncodeToString(sig)
return s, nil
}
func md5B(src []byte) string {
h := md5.New()
h.Write(src)
bb := h.Sum(nil)
sEnc := base64.StdEncoding.EncodeToString(bb)
return sEnc
}
func md5S(src string) string {
return md5B([]byte(src))
}
func (c *Client) GetTradeNotification(data map[string]string, sign string) (result PayNotifyData, err error) {
err = c.getDefaultNotification(data, sign, &result)
return result, err
}
func (c *Client) getDefaultNotification(data map[string]string, sign string, result interface{}) error {
var pList = make([]string, 0, 0)
for k, v := range data {
pList = append(pList, k+"="+v)
}
sort.Strings(pList)
var src = strings.Join(pList, "&")
log.Debug(fmt.Sprintf("签名数据:%s", src))
md5Str := md5B([]byte(src))
signBytes, err := base64.StdEncoding.DecodeString(sign)
if err != nil {
return err
}
if err = RSAVerifyWithKey([]byte(md5Str), signBytes, c.tlPublicKey, crypto.SHA256); err != nil {
return err
}
err = json.Unmarshal([]byte(data["bizContent"]), result)
if err != nil {
return err
}
return err
}
package lib_allinpay
const (
CodeSuccess = "10000"
)
const (
SubCodeSuccess = "OK"
)
type Param interface {
// APIName 用于提供访问的 method
apiName() string
}
type OpenResponse struct {
Code string
Msg string
SubCode string
SubMsg string
Sign string
TraceId string
}
type DefaultOpenResponse struct {
OpenResponse
Data interface{}
}
package main
import (
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
lib_allinpay "git.168cad.top/zhengqiuyun/rym-util/a/lib/allinpay"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"git.168cad.top/zhengqiuyun/rym-util/a/util"
"time"
)
var payerId = "test-DCRYM-U-4553"
var recieverId = "DCRYM-B-2"
var appId = "wx99b75b4bdb31b3c3"
var openId = "oVv8-5SsNWRNEcuOPu51sxTBwEyA"
func main() {
//testCreateMember()//创建会员
//testBindWxOpenId()//绑定微信openId
//testGetMemberInfo()//查询会员
//testConsumeApply()//消费申请
//testGetOrderDetail() //获取订单详情
//testQueryReserveFundBalance() //查询平台头寸
//testQueryBalance() //查询会员账户
//testQueryBankCard()//查询银行卡
//testWithDrawApply()//提现申请
//testAesEncryptECB()//银行卡加密解密
//testQueryInExpDetail()
//testGetPayeeFundsInTransitDetail()//收款方在途资金明细查询
testGetTradeNotification()
}
func testGetPayeeFundsInTransitDetail() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay.GetPayeeFundsInTransitDetail{}
p.BizUserId = recieverId
p.DateStart = "2022-04-20"
p.DateEnd = "2022-04-26"
p.AccountSetNo = conf.AllinpayAccountSetNo
response, err := client.GetPayeeFundsInTransitDetail(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay.CodeSuccess && response.SubCode == lib_allinpay.SubCodeSuccess {
log.Info(fmt.Sprintf("%v", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testQueryInExpDetail() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay.QueryInExpDetail{}
p.BizUserId = recieverId
p.DateStart = "2022-04-01"
p.DateEnd = "2022-04-25"
p.StartPosition = 1
p.QueryNum = 10
p.TradeType = "3"
response, err := client.QueryInExpDetail(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay.CodeSuccess && response.SubCode == lib_allinpay.SubCodeSuccess {
log.Info(fmt.Sprintf("%v", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testAesEncryptECB() {
//key的长度必须是16、24或者32字节,分别用于选择AES-128, AES-192, or AES-256
var key = "B9qzpSpA7llER2fpowePNMNcArCHJLlO"
origData := "324348812323"
//加密
en, err := lib_allinpay.AesEncryptECB(origData, key)
if err != nil {
exception.ThrowsErr(err)
}
fmt.Println(en)
//解密
de, err := lib_allinpay.AesDecryptECB(en, key)
if err != nil {
exception.ThrowsErr(err)
}
fmt.Println(de)
}
func testCreateMember() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay.CreateMember{}
p.BizUserId = payerId
p.MemberType = 3
p.Source = 1
response, err := client.CreateMember(p)
if err != nil {
exception.ThrowsErr(err)
}
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
func testBindWxOpenId() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay.ApplyBindAcct{}
p.BizUserId = payerId
p.OperationType = "set"
p.AcctType = "weChatMiniProgram"
p.Acct = openId
response, err := client.ApplyBindAcct(p)
if err != nil {
exception.ThrowsErr(err)
}
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
func testGetMemberInfo() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay.GetMemberInfo{}
p.BizUserId = payerId
response, err := client.GetMemberInfo(p)
if err != nil {
exception.ThrowsErr(err)
}
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
func testConsumeApply() {
title := "测试服务支付"
orderNo := "202204221721"
money := 10
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay.ConsumeApply{}
p.PayerId = payerId
p.BizOrderNo = orderNo
p.RecieverId = recieverId
p.Amount = int64(money)
p.Fee = 0
p.ValidateType = 0
p.BackUrl = conf.MainHost + "/pay/allin/pay/notify"
payMethod := lib_allinpay.PayMethod{}
WECHATPAY_MINIPROGRAM_ORG := lib_allinpay.WECHATPAY_MINIPROGRAM_ORG{}
WECHATPAY_MINIPROGRAM_ORG.VspCusid = "55265104816Z9YW"
WECHATPAY_MINIPROGRAM_ORG.SubAppid = appId
WECHATPAY_MINIPROGRAM_ORG.LimitPay = ""
WECHATPAY_MINIPROGRAM_ORG.Amount = int64(money)
WECHATPAY_MINIPROGRAM_ORG.Acct = openId
payMethod.WECHATPAY_MINIPROGRAM_ORG = &WECHATPAY_MINIPROGRAM_ORG
expireTime := util.FormatDateTime(util.Add(time.Now(), 10))
p.OrderExpireDatetime = expireTime
p.PayMethod = &payMethod
p.IndustryCode = "1910"
p.IndustryName = "其他"
p.Source = 1
p.Summary = title
response, err := client.ConsumeApply(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay.CodeSuccess && response.SubCode == lib_allinpay.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data.PayInfo))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testGetOrderDetail() {
orderNo := "202204221721"
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay.GetOrderDetail{}
p.BizOrderNo = orderNo
response, err := client.GetOrderDetail(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay.CodeSuccess && response.SubCode == lib_allinpay.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testQueryReserveFundBalance() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay.QueryReserveFundBalance{}
response, err := client.QueryReserveFundBalance(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay.CodeSuccess && response.SubCode == lib_allinpay.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testQueryBalance() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay.QueryBalance{}
p.BizUserId = recieverId
p.AccountSetNo = conf.AllinpayAccountSetNo
response, err := client.QueryBalance(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay.CodeSuccess && response.SubCode == lib_allinpay.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testQueryBankCard() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay.QueryBankCard{}
p.BizUserId = recieverId
response, err := client.QueryBankCard(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay.CodeSuccess && response.SubCode == lib_allinpay.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testWithDrawApply() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay.WithdrawApply{}
p.AccountSetNo = conf.AllinpayAccountSetNo
p.BizOrderNo = "TX202204241728"
p.BizUserId = recieverId
p.Amount = 5000
p.Fee = 100
p.ValidateType = 0
expireMinute := int64(30)
timeExpire := util.Add(time.Now(), expireMinute*60)
p.OrderExpireDatetime = util.FormatDateTime(timeExpire)
p.BackUrl = conf.MainHost + "/pay/allin/pay/draw/notify"
bankCardNo := "324348812323"
encryptBankCardNo, err := lib_allinpay.AesEncryptECB(bankCardNo, conf.AllinpaySecretKey)
log.Info(fmt.Sprintf("银行卡加密数据:%s", encryptBankCardNo))
if err != nil {
exception.ThrowsErrS("通联密钥错误,请检查配置")
}
p.BankCardNo = encryptBankCardNo
p.BankCardPro = 0
p.WithdrawType = "D0"
p.IndustryCode = "1910"
p.IndustryName = "其他"
p.Source = 1
p.Summary = ""
response, err := client.WithdrawApply(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay.CodeSuccess && response.SubCode == lib_allinpay.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testGetTradeNotification() {
client, err := lib_allinpay.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
data := make(map[string]string)
data["notifyTime"] = "2022-04-29 17:35:01"
data["notifyType"] = "allinpay.yunst.orderService.pay"
data["notifyId"] = "1519973518882033666"
data["charset"] = "utf-8"
data["version"] = "1.0"
sign := "o/K4Pkkjv885sq0ZO7CEQ6mxH9ERry6WGVqT214LtdDLChNL+hYh400Wb0G/A1N8kpSJjs1vhFb1IG69zDrJ34QJOBHQb3uLVvlZrAyfKXGY0EZkZiHQDZsX5g1lB177ajKoISuoHhTeZ4Yc+FsT1TrVqpITfHqk4GmOBC0Hfn+dqTOH/blPnFZCxrSjf0VjJYgG1eYy6bQOlPjYs/SAm+G+n8Yc+yYftaO6TRKxUXV8GmgBEhXfIUuPPCvFniAABBJcJIAFWBc3eON3lO8TjTBdR04qldw7Elzj6i4coIrDSDIJ3nOcJlRjIUTDoQ9RJ+YgOMFNV+dVC2l/GQ7cjQ=="
data["appId"] = "1461169657065537537"
data["bizContent"] = "{\"amount\":500,\"orderNo\":\"1519973481674969088\",\"channelFee\":\"1\",\"channelPaytime\":\"2022-04-29 17:35:01\",\"extendInfo\":\"\",\"payInterfaceOutTradeNo\":\"220429116422306984\",\"buyerBizUserId\":\"DCRYM-U-3063358\",\"cusid\":\"55265104816ZA0L\",\"payInterfacetrxcode\":\"VSP501\",\"payDatetime\":\"2022-04-29 17:35:01\",\"acct\":\"oVv8-5YBsfJD6fH4EQcWXOfiMFtU\",\"bizOrderNo\":\"RO1651224885155063358348858\",\"status\":\"OK\"}"
rd, err := client.GetTradeNotification(data, sign)
if err != nil {
exception.ThrowsErr(err)
}
log.Info(fmt.Sprintf("%v", rd))
}
package lib_allinpay
// CreateMember 创建会员
func (c *Client) CreateMember(param CreateMember) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//ApplyBindAcct 绑定会员标识-用于小程序支付等
func (c *Client) ApplyBindAcct(param ApplyBindAcct) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//GetMemberInfo 查询会员
func (c *Client) GetMemberInfo(param GetMemberInfo) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//QueryBankCard 查询绑定银行卡
func (c *Client) QueryBankCard(param QueryBankCard) (result *QueryBankCardResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
package lib_allinpay
type CreateMember struct {
BizUserId string `json:"bizUserId"`
MemberType uint8 `json:"memberType"`
Source uint8 `json:"source"`
}
func (CreateMember) apiName() string {
return "allinpay.yunst.memberService.createMember"
}
type ApplyBindAcct struct {
BizUserId string `json:"bizUserId"`
OperationType string `json:"operationType"`
AcctType string `json:"acctType"`
Acct string `json:"acct"`
}
func (ApplyBindAcct) apiName() string {
return "allinpay.yunst.memberService.applyBindAcct"
}
type GetMemberInfo struct {
BizUserId string `json:"bizUserId"`
}
func (GetMemberInfo) apiName() string {
return "allinpay.yunst.memberService.getMemberInfo"
}
type QueryBankCard struct {
BizUserId string `json:"bizUserId"`
CardNo string `json:"cardNo"`
}
func (QueryBankCard) apiName() string {
return "allinpay.yunst.memberService.queryBankCard"
}
type QueryBankCardResponse struct {
OpenResponse
Data QueryBankCardResponseData
}
type QueryBankCardResponseData struct {
BindCardList []BindCard
}
type BindCard struct {
BankCardNo string
BankName string
BindState string
Phone string
BranchBankName string
}
package lib_allinpay
//ConsumeApply 绑定会员标识-用于小程序支付等
func (c *Client) ConsumeApply(param ConsumeApply) (result *WxMiniPayOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//GetOrderDetail 绑定会员标识-用于小程序支付等
func (c *Client) GetOrderDetail(param GetOrderDetail) (result *GetOrderDetailOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//Refund 退款
func (c *Client) Refund(param Refund) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//QueryReserveFundBalance 查询平台头寸信息(账户信息)
func (c *Client) QueryReserveFundBalance(param QueryReserveFundBalance) (result *QueryReserveFundBalanceResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//QueryBalance 查询会员账户信息
func (c *Client) QueryBalance(param QueryBalance) (result *QueryBalanceResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//WithdrawApply 提现
func (c *Client) WithdrawApply(param WithdrawApply) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//QueryInExpDetail 查询账户收支明细
func (c *Client) QueryInExpDetail(param QueryInExpDetail) (result *QueryInExpDetailResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//GetPayeeFundsInTransitDetail 收款方在途资金明细查询
func (c *Client) GetPayeeFundsInTransitDetail(param GetPayeeFundsInTransitDetail) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
package lib_allinpay
type ConsumeApply struct {
PayerId string `json:"payerId"`
BizOrderNo string `json:"bizOrderNo"`
RecieverId string `json:"recieverId"`
Amount int64 `json:"amount"`
Fee int64 `json:"fee"`
ValidateType uint8 `json:"validateType"`
BackUrl string `json:"backUrl"`
OrderExpireDatetime string `json:"orderExpireDatetime"`
PayMethod *PayMethod `json:"payMethod"`
IndustryCode string `json:"industryCode"`
IndustryName string `json:"industryName"`
Source int `json:"source"`
Summary string `json:"summary"`
}
type PayMethod struct {
WECHATPAY_MINIPROGRAM_ORG *WECHATPAY_MINIPROGRAM_ORG `json:"WECHATPAY_MINIPROGRAM_ORG"`
}
type WECHATPAY_MINIPROGRAM_ORG struct {
VspCusid string `json:"vspCusid"`
SubAppid string `json:"subAppid"`
LimitPay string `json:"limitPay"`
Amount int64 `json:"amount"`
Acct string `json:"acct"`
}
func (ConsumeApply) apiName() string {
return "allinpay.yunst.orderService.consumeApply"
}
type WxMiniPayOpenResponse struct {
OpenResponse
Data WxMiniPayOpenResponseData
}
type WxMiniPayOpenResponseData struct {
PayInterfaceOutTradeNo string
OrderNo string
PayInfo string
BizUserId string
BizOrderNo string
}
type GetOrderDetail struct {
BizOrderNo string `json:"bizOrderNo"`
}
func (GetOrderDetail) apiName() string {
return "allinpay.yunst.orderService.getOrderDetail"
}
type GetOrderDetailOpenResponse struct {
OpenResponse
Data GetOrderDetailOpenResponseData
}
type GetOrderDetailOpenResponseData struct {
Amount string
BizOrderNo string
BuyerBizUserId string
OrderStatus string
OrderNo string
ErrorMessage string
PayDatetime string
}
type Refund struct {
BizUserId string `json:"bizUserId"`
BizOrderNo string `json:"bizOrderNo"`
OriBizOrderNo string `json:"oriBizOrderNo"`
Amount int64 `json:"amount"`
FeeAmount int64 `json:"feeAmount"`
RefundType string `json:"refundType"`
BackUrl string `json:"backUrl"`
RefundList []RefundAccount `json:"refundList"`
}
type RefundAccount struct {
AccountSetNo string `json:"accountSetNo"`
BizUserId string `json:"bizUserId"`
Amount int64 `json:"amount"`
}
func (Refund) apiName() string {
return "allinpay.yunst.orderService.refund"
}
type QueryReserveFundBalance struct {
}
func (QueryReserveFundBalance) apiName() string {
return "allinpay.yunst.merchantService.queryReserveFundBalance"
}
type QueryReserveFundBalanceResponse struct {
OpenResponse
Data QueryReserveFundBalanceResponseData
}
type QueryReserveFundBalanceResponseData struct {
AccountName string
AccountNo string
Balance string
DefClr string
}
type QueryBalance struct {
AccountSetNo string `json:"accountSetNo"`
BizUserId string `json:"bizUserId"`
}
func (QueryBalance) apiName() string {
return "allinpay.yunst.orderService.queryBalance"
}
type QueryBalanceResponse struct {
OpenResponse
Data QueryBalanceResponseData
}
type QueryBalanceResponseData struct {
AllAmount string
FreezenAmount string
}
type WithdrawApply struct {
AccountSetNo string `json:"accountSetNo"`
BizUserId string `json:"bizUserId"`
BizOrderNo string `json:"bizOrderNo"`
Amount int64 `json:"amount"`
Fee int64 `json:"fee"`
ValidateType uint8 `json:"validateType"`
BackUrl string `json:"backUrl"`
OrderExpireDatetime string `json:"orderExpireDatetime"`
BankCardNo string `json:"bankCardNo"`
BankCardPro uint8 `json:"bankCardPro"`
WithdrawType string `json:"withdrawType"`
IndustryCode string `json:"industryCode"`
IndustryName string `json:"industryName"`
Source uint8 `json:"source"`
Summary string `json:"summary"`
}
func (WithdrawApply) apiName() string {
return "allinpay.yunst.orderService.withdrawApply"
}
type WithdrawApplyResponseData struct {
PayInterfaceOutTradeNo string
BuyerBizUserId string
Amount int64
OrderNo string
ExtendInfo string
PayDatetime string
Acct string
BizOrderNo string
Status string
}
type QueryInExpDetail struct {
BizUserId string `json:"bizUserId"`
BizOrderNo string `json:"bizOrderNo"`
DateStart string `json:"dateStart"`
DateEnd string `json:"dateEnd"`
StartPosition int `json:"startPosition"`
QueryNum int `json:"queryNum"`
TradeType string `json:"tradeType"`
}
func (QueryInExpDetail) apiName() string {
return "allinpay.yunst.orderService.queryInExpDetail"
}
type QueryInExpDetailResponse struct {
OpenResponse
Data QueryInExpDetailResponseData
}
type QueryInExpDetailResponseData struct {
BizUserId string
TotalNum string
InExpDetail []InExpDetail
ExtendInfo string
}
type InExpDetail struct {
TradeNo string
AccountSetName string
ChangeTime string
CurAmount int64
OriAmount int64
ChgAmount int64
CurFreezenAmount int64
BizOrderNo string
TradeType string
Type string
Remark string
ExtendInfo string
}
type GetPayeeFundsInTransitDetail struct {
BizUserId string `json:"bizUserId"`
BizOrderNo string `json:"bizOrderNo"`
DateStart string `json:"dateStart"`
DateEnd string `json:"dateEnd"`
AccountSetNo string `json:"accountSetNo"`
}
func (GetPayeeFundsInTransitDetail) apiName() string {
return "allinpay.yunst.orderService.getPayeeFundsInTransitDetail"
}
type PayNotifyData struct {
Amount *int `json:"amount"`
OrderNo *string `json:"orderNo"`
ChannelFee *string `json:"channelFee"`
ChannelPaytime *string `json:"channelPaytime"`
ExtendInfo *string `json:"extendInfo"`
PayInterfaceOutTradeNo *string `json:"payInterfaceOutTradeNo"`
BuyerBizUserId *string `json:"buyerBizUserId"`
Cusid *string `json:"cusid"`
PayInterfacetrxcode *string `json:"payInterfacetrxcode"`
PayDatetime *string `json:"payDatetime"`
Acct *string `json:"acct"`
BizOrderNo *string `json:"bizOrderNo"`
Status *string `json:"status"`
RefundWhereabouts *int `json:"refundWhereabouts"`
OriOrderNo *string `json:"oriOrderNo"`
OriBizOrderNo *string `json:"oriBizOrderNo"`
}
package lib_allinpay
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"golang.org/x/crypto/pkcs12"
"io/ioutil"
"os"
)
//通过公钥的文件路径加载公钥
func loadPublicKeyWithPath(path string) (publicKey *rsa.PublicKey, err error) {
//读取证书并解码
pemTmp, err := ioutil.ReadFile(path)
if err != nil {
return nil, fmt.Errorf(err.Error())
}
certBlock, _ := pem.Decode(pemTmp)
if certBlock == nil {
return nil, fmt.Errorf(err.Error())
}
//证书解析
certBody, err := x509.ParseCertificate(certBlock.Bytes)
if err != nil {
fmt.Println(err)
return
}
publicKey, ok := certBody.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("%s is not rsa public key", path)
}
return publicKey, nil
}
func loadPublicKey(publicKeyStr string) (publicKey *rsa.PublicKey, err error) {
block, _ := pem.Decode([]byte(publicKeyStr))
if block == nil {
return nil, errors.New("decode public key error")
}
//if block.Type != "PUBLIC KEY" {
// return nil, fmt.Errorf("the kind of PEM should be PUBLIC KEY")
//}
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parse public key err:%s", err.Error())
}
publicKey, ok := key.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("%s is not rsa public key", publicKeyStr)
}
return publicKey, nil
}
func getPrivateKey(privateKeyPath, privatePassword string) (*rsa.PrivateKey, error) {
f, err := os.Open(privateKeyPath)
if err != nil {
return nil, err
}
bytes, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
// 因为pfx证书公钥和密钥是成对的,所以要先转成pem.Block
blocks, err := pkcs12.ToPEM(bytes, privatePassword)
if err != nil {
return nil, err
}
if len(blocks) != 2 {
return nil, errors.New("解密错误")
}
// 拿到第一个block,用x509解析出私钥(当然公钥也是可以的)
privateKey, err := x509.ParsePKCS1PrivateKey(blocks[0].Bytes)
if err != nil {
return nil, err
}
return privateKey, nil
}
func RSASignWithKey(plaintext []byte, key *rsa.PrivateKey, hash crypto.Hash) ([]byte, error) {
var h = hash.New()
h.Write(plaintext)
var hashed = h.Sum(nil)
return rsa.SignPKCS1v15(rand.Reader, key, hash, hashed)
}
func RSAVerifyWithKey(ciphertext, sign []byte, key *rsa.PublicKey, hash crypto.Hash) error {
var h = hash.New()
h.Write(ciphertext)
var hashed = h.Sum(nil)
return rsa.VerifyPKCS1v15(key, hash, hashed, sign)
}
package log
import (
"bytes"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
"gorm.io/gorm/logger"
"runtime"
"strconv"
"strings"
"time"
)
const (
DebugL = "Debug"
InfoL = "Info"
ErrorL = "Error"
)
func DebugDo(f func()) {
if IsDebug() {
f()
}
}
func IsDebug() bool {
ok := false
switch strings.ToLower(conf.LogLevel) {
case strings.ToLower(DebugL):
ok = true
break
}
return ok
}
func Debug(msg string) {
ok := false
switch strings.ToLower(conf.LogLevel) {
case strings.ToLower(DebugL):
ok = true
break
}
if ok {
_, file, line, _ := runtime.Caller(1)
mark("Debug", msg, file, line)
}
}
func Info(msg string) {
ok := false
switch strings.ToLower(conf.LogLevel) {
case strings.ToLower(DebugL):
ok = true
break
case strings.ToLower(InfoL):
ok = true
break
}
if ok {
_, file, line, _ := runtime.Caller(1)
mark("Info", msg, file, line)
}
}
func Error(msg string) {
ok := false
switch strings.ToLower(conf.LogLevel) {
case strings.ToLower(DebugL):
ok = true
break
case strings.ToLower(InfoL):
ok = true
break
case strings.ToLower(ErrorL):
ok = true
break
}
if ok {
_, file, line, _ := runtime.Caller(1)
mark("Error", msg, file, line)
}
}
func mark(tag, msg string, file string, line int) {
str := "%s %s [%d] %s %d %s"
if conf.LogColorful {
if tag == "Error" {
str = "%s %s [%d] %s %d " + logger.Red + "%s" + logger.Reset
} else if tag == "Info" {
str = "%s %s [%d] %s %d " + logger.Yellow + "%s" + logger.Reset
} else {
str = "%s %s [%d] %s %d " + logger.Green + "%s" + logger.Reset
}
}
file = file[strings.LastIndex(file, "/")+1:]
fmt.Println(fmt.Sprintf(str, FormatDateMillTime(time.Now()), tag, GetGID(), file, line, msg))
}
func FormatDateMillTime(dataTime time.Time) string {
return dataTime.Format("2006-01-02 15:04:05.000000")
}
func GetGID() uint64 {
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, _ := strconv.ParseUint(string(b), 10, 64)
return n
}
package es
const indexNamePrefix = "manage_client_log"
package es
import (
"context"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"github.com/olivere/elastic/v7"
_log "log"
"os"
)
var Client *elastic.Client
//初始化
func init() {
host := conf.EsHttpHost
var err error
errorLog := _log.New(os.Stdout, "APP", _log.LstdFlags)
Client, err = elastic.NewClient(elastic.SetErrorLog(errorLog), elastic.SetURL(host))
if err != nil {
exception.ThrowsErrS(fmt.Sprintf("ES连接失败:%s", err.Error()))
}
info, code, err := Client.Ping(host).Do(context.Background())
if err != nil {
panic(err)
}
log.Info(fmt.Sprintf("Elasticsearch connect %d", code))
log.Info(fmt.Sprintf("Elasticsearch version %s", info.Version.Number))
}
package es
import (
"context"
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
log2 "git.168cad.top/zhengqiuyun/rym-util/a/log"
"git.168cad.top/zhengqiuyun/rym-util/a/util"
"github.com/olivere/elastic/v7"
"sort"
"time"
)
func getCurrentIndex() string {
return indexNamePrefix + util.FormatDates(time.Now())
}
type ServerLogModel struct {
ServerName string `json:"serverName"`
Env string `json:"env"`
TimeStamp int64 `json:"timeStamp"`
ThreadNo string `json:"threadNo"`
ServerIp string `json:"serverIp"`
ClientIp string `json:"clientIp"`
Token string `json:"token"`
CustomerId uint32 `json:"customerId"`
ClientSource string `json:"clientSource"`
Url string `json:"url"`
Method string `json:"method"`
Request string `json:"request"`
Response string `json:"response"`
DealTimes int64 `json:"dealTimes"`
}
func InsertEsLog(log interface{}) {
indexName := getCurrentIndex()
put, err := Client.Index().
Index(indexName).
BodyJson(log).
Do(context.Background())
if err != nil {
log2.Error(fmt.Sprintf("insert es log fail:%s", err.Error()))
} else {
log2.Debug(fmt.Sprintf("insert es log success:%s", put.Id))
}
}
func GroupField(indexName, field string, size, minCount int, excludeValues []string) []byte {
if size == 0 {
size = 30
}
aggregationQuery := elastic.NewTermsAggregation().Field(field).MinDocCount(minCount).Size(size)
for _, excludeValue := range excludeValues {
aggregationQuery.ExcludeValues(excludeValue)
}
if log2.IsDebug() {
source, _ := aggregationQuery.Source()
queryByte, _ := json.Marshal(source)
log2.Info(fmt.Sprintf("查询条件:%s", string(queryByte)))
}
res, err := Client.Search(indexName).
Aggregation("group_field", aggregationQuery).
From(0).
Size(0).
Do(context.Background())
if err != nil {
exception.ThrowsErr(err)
}
bs, err := json.Marshal(res.Aggregations)
if err != nil {
exception.ThrowsErr(err)
}
return bs
}
func QueryLogs(indexName, filed, value string, from, size int) interface{} {
if from <= 0 {
from = 0
}
if size <= 0 {
size = 10
}
query := elastic.NewBoolQuery().Must(elastic.NewTermQuery(filed, value))
res, err := Client.Search(indexName).Query(query).
From(from).
Size(size).
Do(context.Background())
if err != nil {
exception.ThrowsErr(err)
}
return res
}
type IndexInfo struct {
Name string `json:"name"`
Count int `json:"count"`
Size string `json:"size"`
}
func AllIndex() interface{} {
res, err := Client.CatIndices().Do(context.Background())
if err != nil {
exception.ThrowsErr(err)
}
var keys []string
var sizeMap = make(map[string]IndexInfo)
for _, row := range res {
keys = append(keys, row.Index)
sizeMap[row.Index] = IndexInfo{row.Index, row.DocsCount, row.StoreSize}
}
sort.Strings(keys)
data := make([]IndexInfo, len(keys))
for i, key := range keys {
data[i] = sizeMap[key]
}
return data
}
func DeleteIndex(indexName string) interface{} {
res, err := Client.DeleteIndex(indexName).
Do(context.Background())
if err != nil {
exception.ThrowsErr(err)
}
return res
}
package page
type Page struct {
PageNum int `json:"pageNum"`
PageSize int `json:"pageSize"`
Total int `json:"total"`
}
type Data struct {
Page
List interface{} `json:"list"`
}
package page
type ParamPage struct {
PageNum int `json:"pageNum"`
PageSize int `json:"pageSize"`
}
type Param struct {
Column string
Op string
Value interface{}
}
package sqlOp
const Equal = "="
const Like = "like"
const LessThan = "<"
const GreatThan = ">"
const LessThanOrEqual = "<="
const GreatThanOrEqual = ">="
func DimLeft(s string) string {
return "%" + s
}
func DimRight(s string) string {
return s + "%"
}
func DimAll(s string) string {
return "%" + s + "%"
}
package util
func ArrayContains(array []string, e string) bool {
for _, v := range array {
if v == e {
return true
}
}
return false
}
package util
import (
"time"
)
const formatSimple0 = "2006-01-02 15:04:05.000000"
const formatSimple1 = "2006-01-02 15:04:05"
const formatSimple2 = "2006-01-02"
const formatSimple3 = "20060102"
const DayStart = "00:00:00"
const DayEnd = "23:59:59"
func FormatDate(dateTime time.Time) string {
return dateTime.Format(formatSimple2)
}
func FormatDates(dateTime time.Time) string {
return dateTime.Format(formatSimple3)
}
func FormatDateTime(dateTime time.Time) string {
return dateTime.Format(formatSimple1)
}
func FormatDateMillTime(dateTime time.Time) string {
return dateTime.Format(formatSimple0)
}
func PareDateStart(date string) time.Time {
stamp, _ := time.ParseInLocation(formatSimple1, date+" 00:00:00", time.Local)
return stamp
}
func AddDate(date time.Time, d int) time.Time {
t := (int64)(d * 24 * 60 * 60)
return Add(date, t)
}
func Add(date time.Time, d int64) time.Time {
t := date.Unix()
t += d //增加秒
return time.Unix(t, 0)
}
func Start(date time.Time) time.Time {
return time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location()) // 获取当天0点时间 time类型
}
func TimeSubDays(t1, t2 time.Time) int {
if t1.Location().String() != t2.Location().String() {
return -1
}
hours := t1.Sub(t2).Hours()
t1y, t1m, t1d := t1.Date()
t2y, t2m, t2d := t2.Date()
if t1y == t2y && t1m == t2m && t1d == t2d { //同一天
return 0
} else {
return int(hours/24 + 1)
}
}
func MilSecond(time time.Time) int64 {
return time.UnixNano() / 1e6
}
package util
func IfInt(isTrue bool, a, b int) int {
if isTrue {
return a
}
return b
}
func IfString(isTrue bool, a, b string) string {
if isTrue {
return a
}
return b
}
package util
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
)
func imgToBase64() {
imgUrl := "https://img.ipcfun.com/uploads/ishoulu/pic/2013/05/9215193abd60b5ff099795216.jpg"
//获取远端图片
res, err := http.Get(imgUrl)
if err != nil {
fmt.Println("A error occurred!")
return
}
defer res.Body.Close()
// 读取获取的[]byte数据
data, _ := ioutil.ReadAll(res.Body)
imageBase64 := base64.StdEncoding.EncodeToString(data)
fmt.Println("base64", imageBase64)
}
package util
import (
"bytes"
"crypto"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
"github.com/wechatpay-apiv3/wechatpay-go/utils"
"sort"
)
func Map2SHA256WithRSA(params map[string]interface{}, key string) (result string) {
var keys []string
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
var buf bytes.Buffer
for _, k := range keys {
buf.WriteString(fmt.Sprintf("%s=%v&", k, params[k]))
}
cleartext := buf.String()[:buf.Len()-1]
step3 := md5.Sum([]byte(cleartext))
shaNew := sha256.New()
shaNew.Write(step3[:])
priKey, err := utils.LoadPrivateKey(key)
if err != nil {
exception.ThrowsErr(err)
}
signature, err := rsa.SignPKCS1v15(rand.Reader, priKey, crypto.SHA256, shaNew.Sum(nil))
if err != nil {
exception.ThrowsErr(err)
}
return base64.StdEncoding.EncodeToString(signature)
}
package util
import (
"encoding/json"
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
"net/url"
"sort"
"strconv"
)
func ToMap(obj interface{}) map[string]interface{} {
m := make(map[string]interface{})
j, _ := json.Marshal(obj)
json.Unmarshal(j, &m)
return m
}
func StrToUrlValue(obj string) url.Values {
params := StrToMap(obj)
p := url.Values{}
for k, v := range params {
p.Add(k, GetInterfaceToString(v))
}
return p
}
func GetInterfaceToString(value interface{}) string {
var key string
if value == nil {
return key
}
switch value.(type) {
case float64:
ft := value.(float64)
key = strconv.FormatFloat(ft, 'f', -1, 64)
case float32:
ft := value.(float32)
key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
case int:
it := value.(int)
key = strconv.Itoa(it)
case uint:
it := value.(uint)
key = strconv.Itoa(int(it))
case int8:
it := value.(int8)
key = strconv.Itoa(int(it))
case uint8:
it := value.(uint8)
key = strconv.Itoa(int(it))
case int16:
it := value.(int16)
key = strconv.Itoa(int(it))
case uint16:
it := value.(uint16)
key = strconv.Itoa(int(it))
case int32:
it := value.(int32)
key = strconv.Itoa(int(it))
case uint32:
it := value.(uint32)
key = strconv.Itoa(int(it))
case int64:
it := value.(int64)
key = strconv.FormatInt(it, 10)
case uint64:
it := value.(uint64)
key = strconv.FormatUint(it, 10)
case string:
key = value.(string)
case []byte:
key = string(value.([]byte))
default:
newValue, _ := json.Marshal(value)
key = string(newValue)
}
return key
}
func StrToMap(obj string) map[string]interface{} {
m := make(map[string]interface{})
json.Unmarshal([]byte(obj), &m)
return m
}
func StrToMapStr(obj string) map[string]string {
m := make(map[string]string)
json.Unmarshal([]byte(obj), &m)
return m
}
func ToObject(txt string, p interface{}) {
err := json.Unmarshal([]byte(txt), p)
if err != nil {
exception.ThrowsErr(err)
}
}
func SortKeys(orgMap map[string]interface{}) []string {
var keys []string
for key := range orgMap {
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}
package util
import (
"crypto/md5"
"encoding/hex"
)
func Md5(s string) string {
h := md5.New()
h.Write([]byte(s))
r := hex.EncodeToString(h.Sum(nil))
return r
}
package util
import (
"os"
)
func Args(i int) string {
args := os.Args
if len(args) < i+1 {
return ""
}
return args[i]
}
package util
func EncodePwd(loginPwd, loginPwdSalt string) string {
pingPwd := loginPwdSalt + loginPwd
return Md5(pingPwd)
}
package util
import (
"bytes"
"runtime"
"strconv"
)
func GetGID() uint64 {
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, _ := strconv.ParseUint(string(b), 10, 64)
return n
}
package Stream
import (
"fmt"
"strings"
)
//泛型类型定义
type T interface{}
type U interface{}
//流计算数据结构定义
type Stream struct {
Head T
Tail *Stream
Length int
NotEmpty bool
}
var Nil = Stream{}
func Generate(r Stream, f func(Stream) T, m int) Stream {
if m == 1 {
return r
} else {
return Generate(New(f(r), &r), f, m-1)
}
}
func New(head T, tail *Stream) Stream {
return Stream{head, tail, tail.Length + 1, true}
}
func (s Stream) Add(i T) Stream {
return New(i, &s)
}
func (s Stream) Adderall(i ...T) Stream {
for _, v := range i {
s = s.Add(v)
}
return s
}
//左折叠 用于实现 reduce 的功能
func (s Stream) FoldLeft(i U, f func(U, T) U) U {
if s.NotEmpty {
return s.Tail.FoldLeft(f(i, s.Head), f)
} else {
return i
}
}
//右折叠
func (s Stream) FoldRight(i U, f func(U, T) U) U {
if s.NotEmpty {
return f(s.Tail.FoldRight(i, f), s.Head)
} else {
return i
}
}
//合并两个 Stream
func (s Stream) Merge(t Stream) Stream {
if t.NotEmpty {
return t.FoldRight(s, func(u U, t T) U {
return u.(Stream).Add(t)
}).(Stream)
} else {
return s
}
}
//倒序
func (s Stream) Reverse() Stream {
return s.FoldLeft(Nil, func(u U, t T) U {
return u.(Stream).Add(t)
}).(Stream)
}
//Map
func (s Stream) Map(f func(T) U) Stream {
return s.FoldRight(Nil, func(u U, t T) U {
return u.(Stream).Add(f(t))
}).(Stream)
}
//Reduce
func (s Stream) Reduce(i T, f func(T, T) T) T {
if s.NotEmpty {
return s.Tail.Reduce(f(i, s.Head), f)
} else {
return i
}
}
//过滤
func (s Stream) Filter(f func(T) bool) Stream {
return s.FoldRight(Nil, func(u U, t T) U {
if f(t) {
return u.(Stream).Add(t)
} else {
return u
}
}).(Stream)
}
//归并排序
func (s Stream) Sort(c func(T, T) bool) Stream {
n := s.Length / 2
if n == 0 {
return s
} else {
x, y := split(s, Nil, n)
return merge(x.Sort(c), y.Sort(c), c)
}
}
func split(x, y Stream, n int) (Stream, Stream) {
if n == 0 || !x.NotEmpty {
return x, y
}
return split(*x.Tail, y.Add(x.Head), n-1)
}
func merge(x, y Stream, c func(T, T) bool) Stream {
if !x.NotEmpty {
return y
}
if !y.NotEmpty {
return x
}
if c(x.Head, y.Head) {
return merge(*x.Tail, y, c).Add(x.Head)
} else {
return merge(x, *y.Tail, c).Add(y.Head)
}
}
//格式化显示 Stream 的所有项
func (s Stream) ToString() string {
return "{" + strings.Join(s.FoldRight([]string{}, func(u U, t T) U {
return append(u.([]string), fmt.Sprintf("%v", t))
}).([]string), ",") + "}"
}
package util
import (
"encoding/json"
"git.168cad.top/zhengqiuyun/rym-util/a/exception"
"github.com/gin-gonic/gin"
"github.com/shopspring/decimal"
"math/rand"
"strconv"
)
// 生成: 时间戳 + 设置前缀 + 随即字符串
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
func FandomString(strlen int) string {
result := make([]byte, strlen)
for i := 0; i < strlen; i++ {
result[i] = alphanum[rand.Intn(len(alphanum))]
}
return string(result)
}
func ParamUint32(c *gin.Context, key string) uint32 {
v := c.Query(key)
if v == "" {
return 0
}
i, err := strconv.Atoi(v)
if err != nil {
exception.ThrowsErrS("参数类型错误:请传入正确的数字")
}
return uint32(i)
}
func ParamUint8(c *gin.Context, key string) uint8 {
v := c.Query(key)
if v == "" {
return 0
}
i, err := strconv.Atoi(v)
if err != nil {
exception.ThrowsErrS("参数类型错误:请传入正确的数字")
}
return uint8(i)
}
func Param(c *gin.Context, key string) string {
v := c.Query(key)
return v
}
func Path(c *gin.Context, key string) string {
v := c.Param(key)
if v == "" {
exception.ThrowsErrS("参数[" + key + "]必填")
}
return v
}
// Strval 获取变量的字符串值
// 浮点型 3.0将会转换成字符串3, "3"
// 非数值或字符类型的变量将会被转换成JSON格式字符串
func Strval(value interface{}) string {
// interface 转 string
var key string
if value == nil {
return key
}
switch value.(type) {
case float64:
ft := value.(float64)
key = strconv.FormatFloat(ft, 'a', -1, 64)
case float32:
ft := value.(float32)
key = strconv.FormatFloat(float64(ft), 'a', -1, 64)
case int:
it := value.(int)
key = strconv.Itoa(it)
case uint:
it := value.(uint)
key = strconv.Itoa(int(it))
case int8:
it := value.(int8)
key = strconv.Itoa(int(it))
case uint8:
it := value.(uint8)
key = strconv.Itoa(int(it))
case int16:
it := value.(int16)
key = strconv.Itoa(int(it))
case uint16:
it := value.(uint16)
key = strconv.Itoa(int(it))
case int32:
it := value.(int32)
key = strconv.Itoa(int(it))
case uint32:
it := value.(uint32)
key = strconv.Itoa(int(it))
case int64:
it := value.(int64)
key = strconv.FormatInt(it, 10)
case uint64:
it := value.(uint64)
key = strconv.FormatUint(it, 10)
case string:
key = value.(string)
case []byte:
key = string(value.([]byte))
default:
newValue, _ := json.Marshal(value)
key = string(newValue)
}
return key
}
func IsEmpty(s *string) bool {
return s == nil || *s == ""
}
func IsNil(i interface{}) bool {
if i == nil {
return true
}
return false
}
func YuanToFen(money float64) int64 {
v12 := decimal.NewFromFloat(float64(money) * 100).Round(0).BigInt().Int64()
return v12
}
func FenToYuan(money int64) float64 {
v12, _ := decimal.NewFromFloat(float64(money) / 100).Round(2).Float64()
return v12
}
package util
import (
"crypto/aes"
"crypto/sha1"
"encoding/hex"
"errors"
"strings"
)
//AesEncryptECBAllin 通联数据加密
func AesEncryptECBAllin(src, key string) (string, error) {
data, err := AesEncryptECB(src, key)
return strings.ToUpper(data), err
}
//AesDecryptECBAllin 通联数据解密
func AesDecryptECBAllin(src, key string) (string, error) {
src = strings.ToLower(src)
data, err := AesDecryptECB(src, key)
return data, err
}
func AesEncryptECB(src, key string) (string, error) {
data, err := aesEncryptECB([]byte(src), []byte(key))
eStr := hex.EncodeToString(data)
return eStr, err
}
func AesDecryptECB(src, key string) (string, error) {
data, err := hex.DecodeString(src)
if err != nil {
return "", err
}
re, err := aesDecryptECB([]byte(data), []byte(key))
return string(re), err
}
func aesEncryptECB(src []byte, key []byte) ([]byte, error) {
key, err := aesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return nil, err
}
cipher, _ := aes.NewCipher(generateKey(key))
length := (len(src) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, src)
pad := byte(len(plain) - len(src))
for i := len(src); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
// 分组分块加密
for bs, be := 0, cipher.BlockSize(); bs <= len(src); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted, nil
}
func aesDecryptECB(encrypted []byte, key []byte) ([]byte, error) {
key, err := aesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return nil, err
}
cipher, _ := aes.NewCipher(generateKey(key))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim], nil
}
func aesSha1prng(keyBytes []byte, encryptLength int) ([]byte, error) {
a := sha1Key(sha1Key(keyBytes))
maxLen := len(a)
realLen := encryptLength / 8
if realLen > maxLen {
return nil, errors.New("密钥长度非法")
}
return a[0:realLen], nil
}
func sha1Key(data []byte) []byte {
h := sha1.New()
h.Write(data)
return h.Sum(nil)
}
func generateKey(key []byte) (genKey []byte) {
genKey = make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return genKey
}
package main
import (
"fmt"
util "git.168cad.top/zhengqiuyun/rym-util/a/util/aes"
)
func main() {
org := "18090279887"
key := "B9qzpSpA7llER2fpowePNMNcArCHJLlO"
fmt.Println("原生数据:" + org)
// 加密
res, err := util.AesEncryptECBAllin(org, key)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println("加密结果:" + res)
// 解密
de, err := util.AesDecryptECBAllin(res, key)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println("解密结果:" + de)
}
package util
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
)
func LoadPrivateKey(privateKeyStr string) (privateKey *rsa.PrivateKey, err error) {
block, _ := pem.Decode([]byte(buildFullPrivateKey(privateKeyStr)))
if block == nil {
return nil, fmt.Errorf("decode private key err")
}
if block.Type != "PRIVATE KEY" {
return nil, fmt.Errorf("the kind of PEM should be PRVATE KEY")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parse private key err:%s", err.Error())
}
privateKey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("%s is not rsa private key", privateKeyStr)
}
return privateKey, nil
}
func buildFullPrivateKey(privateKey string) string {
preLine := "-----BEGIN PRIVATE KEY-----\n"
endLine := "\n-----END PRIVATE KEY-----"
return preLine + privateKey + endLine
}
// LoadPublicKey 通过公钥的文本内容加载公钥
func LoadPublicKey(publicKeyStr string) (publicKey *rsa.PublicKey, err error) {
block, _ := pem.Decode([]byte(buildFullPublicKey(publicKeyStr)))
if block == nil {
return nil, fmt.Errorf("decode public key error")
}
if block.Type != "PUBLIC KEY" {
return nil, fmt.Errorf("the kind of PEM should be PUBLIC KEY")
}
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parse public key err:%s", err.Error())
}
publicKey, ok := key.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("%s is not rsa public key", publicKeyStr)
}
return publicKey, nil
}
func buildFullPublicKey(publicKey string) string {
preLine := "-----BEGIN PUBLIC KEY-----\n"
endLine := "\n-----END PUBLIC KEY-----"
return preLine + publicKey + endLine
}
module git.168cad.top/zhengqiuyun/rym-util
go 1.17
go 1.16
require (
github.com/deckarep/golang-set v1.7.1
github.com/garyburd/redigo v1.6.3
github.com/gin-gonic/gin v1.7.4
github.com/go-playground/validator/v10 v10.4.1
github.com/iancoleman/strcase v0.2.0
github.com/shopspring/decimal v1.2.0
github.com/wechatpay-apiv3/wechatpay-go v0.2.9
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
gorm.io/driver/mysql v1.2.2
gorm.io/driver/postgres v1.2.2
gorm.io/gorm v1.22.4
)
require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/olivere/elastic/v7 v7.0.32
github.com/robfig/cron v1.2.0
github.com/smartwalle/crypto4go v1.0.3
github.com/wenlng/go-captcha v1.2.5
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
)
replace git.168cad.top/zhengqiuyun/rym-util => ../rym-util
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
github.com/aws/aws-sdk-go v1.43.21/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/garyburd/redigo v1.6.3 h1:HCeeRluvAgMusMomi1+6Y5dmFOdYV/JzoRrrbFlkGIc=
github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.10.0 h1:4EYhlDVEMsJ30nNj0mmgwIUXoq7e9sMJrVC2ED6QlCU=
github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.8.1 h1:9k0IXtdJXHJbyAWQgbWr1lU+MEhPXZz6RIXxfR5oxXs=
github.com/jackc/pgtype v1.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.13.0 h1:JCjhT5vmhMAf/YwBHLvrBn4OGdIQBiFG6ym8Zmdx570=
github.com/jackc/pgx/v4 v4.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI=
github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartwalle/crypto4go v1.0.3 h1:LMyJ0IckEzvfdL83n5esyiyOOV5kdohHjcKFmzmFwmw=
github.com/smartwalle/crypto4go v1.0.3/go.mod h1:ZWGiSjwChZkEUY7TFzIt351l1pmK+UihDdCzZey+eUM=
github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
github.com/smartystreets/gunit v1.4.2/go.mod h1:ZjM1ozSIMJlAz/ay4SG8PeKF00ckUp+zMHZXV9/bvak=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/wechatpay-apiv3/wechatpay-go v0.2.9 h1:FnFdYLquHWEB0pBacOHC9BePgXcf26vZfn2X3uYbo0c=
github.com/wechatpay-apiv3/wechatpay-go v0.2.9/go.mod h1:W8ucVAOCKOii933cWROLaDLmRQ2cg/vHHVF4vGAVq9Q=
github.com/wenlng/go-captcha v1.2.5 h1:zA0/fovEl9oAhSg+KwHBwmq99GeeAXknWx6wYKjhjTg=
github.com/wenlng/go-captcha v1.2.5/go.mod h1:QgPgpEURSa37gF3GtojNoNRwbMwuatSBx5NXrzASOb0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/otel v1.5.0/go.mod h1:Jm/m+rNp/z0eqJc74H7LPwQ3G87qkU/AnnAydAjSAHk=
go.opentelemetry.io/otel/trace v1.5.0/go.mod h1:sq55kfhjXYr1zVSyexg0w1mpa03AYXR5eyTkB9NPPdE=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.2.2 h1:2qoqhOun1maoJOfLtnzJwq+bZlHkEF34rGntgySqp48=
gorm.io/driver/mysql v1.2.2/go.mod h1:qsiz+XcAyMrS6QY+X3M9R6b/lKM1imKmcuK9kac5LTo=
gorm.io/driver/postgres v1.2.2 h1:Ka9W6feOU+rPM9m007eYLMD4QoZuYGBnQ3Jp0faGSwg=
gorm.io/driver/postgres v1.2.2/go.mod h1:Ik3tK+a3FMp8ORZl29v4b3M0RsgXsaeMXh9s9eVMXco=
gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM=
gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment