Commit f50bf998 by zhengqiuyun86

初始化

parent 7610d771
package PagePlus
import (
"git.168cad.top/zhengqiuyun/rym-util/a/util"
"git.168cad.top/zhengqiuyun/rym-util/exception"
page2 "git.168cad.top/zhengqiuyun/rym-util/page"
"gorm.io/gorm"
)
func Page(params []page2.Param, pageNum int, pageSize int, m interface{}, data interface{}, orderBy string, db *gorm.DB) *page2.Data {
var page = page2.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 exception
import (
"errors"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"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/exception"
"git.168cad.top/zhengqiuyun/rym-util/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/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
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
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/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"
conf2 "git.168cad.top/zhengqiuyun/rym-util/conf"
"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) > conf2.LogResponseLength {
responseStr = rs[0:conf2.LogResponseLength] + "......"
} else {
responseStr = rs
}
} else {
if len(rs) > conf2.LogResponseLength {
responseStr = rs[0:conf2.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
// }
//}
module git.168cad.top/zhengqiuyun/rym-util
go 1.16
require (
)
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/smartwalle/crypto4go v1.0.3
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
)
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/log"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"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/log"
"git.168cad.top/zhengqiuyun/rym-util/exception"
lib_allinpay2 "git.168cad.top/zhengqiuyun/rym-util/lib/allinpay"
"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_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay2.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_allinpay2.CodeSuccess && response.SubCode == lib_allinpay2.SubCodeSuccess {
log.Info(fmt.Sprintf("%v", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testQueryInExpDetail() {
client, err := lib_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay2.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_allinpay2.CodeSuccess && response.SubCode == lib_allinpay2.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_allinpay2.AesEncryptECB(origData, key)
if err != nil {
exception.ThrowsErr(err)
}
fmt.Println(en)
//解密
de, err := lib_allinpay2.AesDecryptECB(en, key)
if err != nil {
exception.ThrowsErr(err)
}
fmt.Println(de)
}
func testCreateMember() {
client, err := lib_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay2.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_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay2.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_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
var p = lib_allinpay2.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_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay2.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_allinpay2.PayMethod{}
WECHATPAY_MINIPROGRAM_ORG := lib_allinpay2.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_allinpay2.CodeSuccess && response.SubCode == lib_allinpay2.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_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay2.GetOrderDetail{}
p.BizOrderNo = orderNo
response, err := client.GetOrderDetail(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay2.CodeSuccess && response.SubCode == lib_allinpay2.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testQueryReserveFundBalance() {
client, err := lib_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay2.QueryReserveFundBalance{}
response, err := client.QueryReserveFundBalance(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay2.CodeSuccess && response.SubCode == lib_allinpay2.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testQueryBalance() {
client, err := lib_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay2.QueryBalance{}
p.BizUserId = recieverId
p.AccountSetNo = conf.AllinpayAccountSetNo
response, err := client.QueryBalance(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay2.CodeSuccess && response.SubCode == lib_allinpay2.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testQueryBankCard() {
client, err := lib_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay2.QueryBankCard{}
p.BizUserId = recieverId
response, err := client.QueryBankCard(p)
if err != nil {
exception.ThrowsErr(err)
}
if response.Code == lib_allinpay2.CodeSuccess && response.SubCode == lib_allinpay2.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testWithDrawApply() {
client, err := lib_allinpay2.New(conf.AllinpayPrivateKeyPath, conf.AllinpayPwd, conf.AllinpayTlPublicKey)
if err != nil {
exception.ThrowsErr(err)
}
p := lib_allinpay2.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_allinpay2.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_allinpay2.CodeSuccess && response.SubCode == lib_allinpay2.SubCodeSuccess {
log.Info(fmt.Sprintf("%s", response.Data))
} else {
log.Info(fmt.Sprintf("%s-%s", response.Msg, response.SubMsg))
}
}
func testGetTradeNotification() {
client, err := lib_allinpay2.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 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
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/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)
}
......@@ -2,7 +2,6 @@ package util
import (
"encoding/json"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"net/url"
"sort"
"strconv"
......@@ -94,7 +93,7 @@ func StrToMapStr(obj string) map[string]string {
func ToObject(txt string, p interface{}) {
err := json.Unmarshal([]byte(txt), p)
if err != nil {
exception.ThrowsErr(err)
panic(err)
}
}
......
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), ",") + "}"
}
......@@ -2,9 +2,6 @@ package util
import (
"encoding/json"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"github.com/gin-gonic/gin"
"github.com/shopspring/decimal"
"math/rand"
"strconv"
)
......@@ -20,43 +17,6 @@ func FandomString(strlen int) string {
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格式字符串
......@@ -126,13 +86,3 @@ func IsNil(i interface{}) bool {
}
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"
"git.168cad.top/zhengqiuyun/rym-util/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
}
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