This commit is contained in:
Shiny 2024-12-17 22:28:48 +08:00
commit 754e1ae43c
50 changed files with 2969 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.idea
.vscode
*.log
*.exe
/go.sum
yaml
.DS_Store

75
go.mod Normal file
View File

@ -0,0 +1,75 @@
module code.zhecent.com/gopkg/light-core
go 1.23.1
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.63.68
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/gin-gonic/gin v1.10.0
github.com/go-pay/gopay v1.5.106
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/redis/go-redis/v9 v9.7.0
github.com/shopspring/decimal v1.4.0
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
golang.org/x/crypto v0.31.0
google.golang.org/protobuf v1.36.0
gorm.io/driver/mysql v1.5.7
gorm.io/gorm v1.25.12
)
require (
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-pay/crypto v0.0.1 // indirect
github.com/go-pay/errgroup v0.0.2 // indirect
github.com/go-pay/util v0.0.4 // indirect
github.com/go-pay/xlog v0.0.3 // indirect
github.com/go-pay/xtime v0.0.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

85
impl/int64Array.go Normal file
View File

@ -0,0 +1,85 @@
package impl
import (
"database/sql/driver"
"encoding/json"
)
type Int64Array []int64
func (v *Int64Array) Scan(value interface{}) error {
//判断类型
switch data := value.(type) {
case []byte:
return json.Unmarshal(data, v)
case string:
return json.Unmarshal([]byte(data), v)
case nil:
return nil
}
return json.Unmarshal(value.([]byte), v)
}
func (v Int64Array) Value() (driver.Value, error) {
return json.Marshal(v)
}
func (v Int64Array) RemoveDuplicates() Int64Array {
newArr := make([]int64, 0)
for i := 0; i < len(v); i++ {
repeat := false
for j := i + 1; j < len(v); j++ {
if v[i] == v[j] {
repeat = true
break
}
}
if !repeat {
newArr = append(newArr, v[i])
}
}
return newArr
}
func (v Int64Array) RemoveEmpty() Int64Array {
return v.RemoveValue(0)
}
func (v Int64Array) RemoveValue(value int64) Int64Array {
newArr := make([]int64, 0)
for i := 0; i < len(v); i++ {
if v[i] != value {
newArr = append(newArr, v[i])
}
}
return newArr
}
func (v Int64Array) Contains(id int64) bool {
for _, i := range v {
if i == id {
return true
}
}
return false
}
func (v Int64Array) Eq(arr []int64) bool {
if len(v) != len(arr) {
return false
}
for _, i := range arr {
//只要有一个不包含就是不一样的
if v.Contains(i) == false {
return false
}
}
return true
}
func (v Int64Array) ToIntSlice() []int {
out := make([]int, 0)
for _, i := range v {
out = append(out, int(i))
}
return out
}

86
impl/intArray.go Normal file
View File

@ -0,0 +1,86 @@
package impl
import (
"database/sql/driver"
"encoding/json"
)
type IntArray []int
func (v *IntArray) Scan(value interface{}) error {
//判断类型
switch data := value.(type) {
case []byte:
return json.Unmarshal(data, v)
case string:
return json.Unmarshal([]byte(data), v)
case nil:
return nil
}
return json.Unmarshal(value.([]byte), v)
}
func (v IntArray) Value() (driver.Value, error) {
return json.Marshal(v)
}
func (v IntArray) RemoveDuplicates() IntArray {
newArr := make([]int, 0)
for i := 0; i < len(v); i++ {
repeat := false
for j := i + 1; j < len(v); j++ {
if v[i] == v[j] {
repeat = true
break
}
}
if !repeat {
newArr = append(newArr, v[i])
}
}
return newArr
}
func (v IntArray) RemoveEmpty() IntArray {
return v.RemoveValue(0)
}
func (v IntArray) RemoveValue(value int) IntArray {
newArr := make([]int, 0)
for i := 0; i < len(v); i++ {
if v[i] != value {
newArr = append(newArr, v[i])
}
}
return newArr
}
func (v IntArray) Contains(id int) bool {
for _, i := range v {
if i == id {
return true
}
}
return false
}
func (v IntArray) Eq(arr []int) bool {
if len(v) != len(arr) {
return false
}
for _, i := range arr {
//只要有一个不包含就是不一样的
if v.Contains(i) == false {
return false
}
}
return true
}
func (v IntArray) ToIntSlice() []int {
out := make([]int, 0)
for _, i := range v {
out = append(out, int(i))
}
return out
}

87
impl/stringArray.go Normal file
View File

@ -0,0 +1,87 @@
package impl
import (
"database/sql/driver"
"encoding/json"
"strings"
)
type StringArray []string
func (v *StringArray) Scan(value interface{}) error {
//判断类型
switch data := value.(type) {
case []byte:
return json.Unmarshal(data, v)
case string:
return json.Unmarshal([]byte(data), v)
case nil:
return nil
}
return json.Unmarshal(value.([]byte), v)
}
func (v StringArray) Value() (driver.Value, error) {
return json.Marshal(v)
}
func (v StringArray) RemoveDuplicates() StringArray {
newArr := make([]string, 0)
for i := 0; i < len(v); i++ {
repeat := false
for j := i + 1; j < len(v); j++ {
if v[i] == v[j] {
repeat = true
break
}
}
if !repeat {
newArr = append(newArr, v[i])
}
}
return newArr
}
func (v StringArray) RemoveEmpty() StringArray {
return v.RemoveValue("")
}
func (v StringArray) RemoveValue(value string) StringArray {
newArr := make([]string, 0)
for i := 0; i < len(v); i++ {
if !strings.EqualFold(v[i], value) {
newArr = append(newArr, v[i])
}
}
return newArr
}
func (v StringArray) Contains(str string) bool {
for _, i := range v {
if i == str {
return true
}
}
return false
}
func (v StringArray) Eq(strArr []string) bool {
if len(v) != len(strArr) {
return false
}
for _, i := range strArr {
//只要有一个不包含就是不一样的
if v.Contains(i) == false {
return false
}
}
return true
}
func (v StringArray) ToStringSlice() []string {
out := make([]string, 0)
for _, i := range v {
out = append(out, i)
}
return out
}

52
lightCore/Config.go Normal file
View File

@ -0,0 +1,52 @@
package lightCore
var ConfigValue = &Config{}
type Config struct {
App AppConfigModel `mapstructure:"app" yaml:"app"`
Server ServerConfigModel `mapstructure:"server" yaml:"server"`
Database DatabaseConfigModel `mapstructure:"database" yaml:"database"`
Redis RedisConfigModel `mapstructure:"redis" yaml:"redis"`
Admin AdminConfigModel `mapstructure:"admin" yaml:"admin"`
}
func (t *Config) IsRelease() bool {
return t.Server.RunMode == "release"
}
type AppConfigModel struct {
JwtSecret string `mapstructure:"jwt_secret" yaml:"jwt_secret"`
AliOssSign string `mapstructure:"ali_oss_sign" yaml:"ali_oss_sign"`
}
type AdminConfigModel struct {
JwtSecret string `mapstructure:"jwt_secret" yaml:"jwt_secret"`
JwtExpires int `mapstructure:"jwt_expires" yaml:"jwt_expires"`
ApiPath string `mapstructure:"api_path" yaml:"api_path"`
}
type ServerConfigModel struct {
RunMode string `mapstructure:"run_mode" yaml:"run_mode"`
HttpPort int `mapstructure:"http_port" yaml:"http_port"`
ReadTimeout int `mapstructure:"read_timeout" yaml:"read_timeout"`
WriteTimeout int `mapstructure:"write_timeout" yaml:"write_timeout"`
}
type DatabaseConfigModel struct {
Type string `mapstructure:"type" yaml:"type"`
User string `mapstructure:"user" yaml:"user"`
Password string `mapstructure:"password" yaml:"password"`
Host string `mapstructure:"host" yaml:"host"`
Name string `mapstructure:"name" yaml:"name"`
Charset string `mapstructure:"charset" yaml:"charset"`
TablePrefix string `mapstructure:"table_prefix" yaml:"table_prefix"`
LogLevel string `mapstructure:"log_level" yaml:"log_level"`
}
type RedisConfigModel struct {
Host string `mapstructure:"host" yaml:"host"`
Password string `mapstructure:"password" yaml:"password"`
MaxIdle string `mapstructure:"max_idle" yaml:"max_idle"`
MaxActive string `mapstructure:"max_active" yaml:"max_active"`
IdleTimeout string `mapstructure:"idle_timeout" yaml:"idle_timeout"`
}

21
lightCore/Db.go Normal file
View File

@ -0,0 +1,21 @@
package lightCore
import (
"code.zhecent.com/gopkg/light-core/pkg/myGorm"
"gorm.io/gorm"
)
var DBEngine *gorm.DB
func InitDB() {
orm := myGorm.NewSimpleORM(
ConfigValue.Database.User,
ConfigValue.Database.Password,
ConfigValue.Database.Host,
ConfigValue.Database.Name,
ConfigValue.Database.Charset,
ConfigValue.Server.RunMode,
)
orm.SetLoggerLevel(ConfigValue.Database.LogLevel)
DBEngine = orm.ConnectMysql()
}

7
lightCore/Fairing.go Normal file
View File

@ -0,0 +1,7 @@
package lightCore
import "github.com/gin-gonic/gin"
type Fairing interface {
OnRequest(c *gin.Context) error
}

11
lightCore/GromAdapter.go Normal file
View File

@ -0,0 +1,11 @@
package lightCore
import "gorm.io/gorm"
type GormAdapter struct {
*gorm.DB
}
func NewGormAdapter(db *gorm.DB) *GormAdapter {
return &GormAdapter{DB: db}
}

24
lightCore/IClass.go Normal file
View File

@ -0,0 +1,24 @@
package lightCore
import "github.com/gin-gonic/gin"
type IClass interface {
Build(core *LightCore)
}
type ClassMounts struct {
handles []IClass
errorHandler []gin.HandlerFunc
}
func NewClassMounts(handles []IClass, errorHandler []gin.HandlerFunc) *ClassMounts {
return &ClassMounts{handles: handles, errorHandler: errorHandler}
}
func (t *ClassMounts) Handles() []IClass {
return t.handles
}
func (t *ClassMounts) ErrorHandler() []gin.HandlerFunc {
return t.errorHandler
}

10
lightCore/IRouters.go Normal file
View File

@ -0,0 +1,10 @@
package lightCore
type Routers struct {
groupPath string
cs *ClassMounts
}
func NewRouters(groupPath string, cs *ClassMounts) *Routers {
return &Routers{groupPath: groupPath, cs: cs}
}

135
lightCore/LightCore.go Normal file
View File

@ -0,0 +1,135 @@
package lightCore
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"reflect"
)
type LightCore struct {
gin *gin.Engine
g *gin.RouterGroup
props []interface{}
}
func StartEngine() *LightCore {
gin.SetMode(ConfigValue.Server.RunMode)
g := &LightCore{gin: gin.New(), props: make([]interface{}, 0)}
g.gin.Use(gin.Logger(), gin.Recovery())
return g
}
func (t *LightCore) GetGin() *gin.Engine {
return t.gin
}
func (t *LightCore) Launch() {
err := t.gin.Run(fmt.Sprintf(":%d", ConfigValue.Server.HttpPort))
if err != nil {
panic("Gin Launch Error")
}
//server := &http.Server{
// Addr: fmt.Sprintf(":%d", addr),
// Handler: t,
// MaxHeaderBytes: 1 << 20,
//}
//err := server.ListenAndServe()
//if err != nil {
// panic("Gin Launch Error")
//}
}
func (t *LightCore) Attach(f Fairing) *LightCore {
t.gin.Use(func(context *gin.Context) {
err := f.OnRequest(context)
if err != nil {
context.AbortWithStatusJSON(http.StatusOK, gin.H{"error": "onRequest"})
} else {
context.Next()
}
})
return t
}
func (t *LightCore) LoadHtml(path string) *LightCore {
t.gin.LoadHTMLGlob(path)
return t
}
func (t *LightCore) StaticFS(path string, fs http.FileSystem) *LightCore {
t.gin.StaticFS(path, fs)
return t
}
func (t *LightCore) Beans(beans ...interface{}) *LightCore {
t.props = append(t.props, beans...)
return t
}
func (t *LightCore) Handle(httpMethod, relativePath string, handler interface{}, mids ...gin.HandlerFunc) *LightCore {
if h := Convert(handler); h != nil {
if len(mids) > 0 {
mids = append(mids, h)
t.g.Handle(httpMethod, relativePath, mids...)
} else {
t.g.Handle(httpMethod, relativePath, h)
}
}
return t
}
func (t *LightCore) MountRaw(f func(s *gin.Engine)) *LightCore {
f(t.GetGin())
return t
}
func (t *LightCore) Mount(group string, errorHandlerFunc []gin.HandlerFunc, classes ...IClass) *LightCore {
t.g = t.gin.Group(group)
if len(errorHandlerFunc) > 0 {
t.g.Use(errorHandlerFunc...)
}
for _, class := range classes {
class.Build(t)
//其实就是找到相同类型的数据就赋值上去
t.setProp(class)
}
return t
}
func (t *LightCore) Mounts(routers []*Routers) *LightCore {
for _, router := range routers {
t.Mount(router.groupPath, router.cs.errorHandler, router.cs.Handles()...)
}
return t
}
func (t *LightCore) SetNoRoute(f func(context *gin.Context)) *LightCore {
t.gin.NoRoute(f)
return t
}
// 查找对应名字的属性
func (t *LightCore) getProp(tp reflect.Type) interface{} {
for _, p := range t.props {
if tp == reflect.TypeOf(p) {
return p
}
}
return nil
}
func (t *LightCore) setProp(class IClass) {
vClass := reflect.ValueOf(class).Elem()
for i := 0; i < vClass.NumField(); i++ {
f := vClass.Field(i)
if !f.IsNil() || f.Kind() != reflect.Ptr {
//已经赋值了,不需要初始化了。
continue
}
if p := t.getProp(f.Type()); p != nil {
f.Set(reflect.New(f.Type().Elem()))
f.Elem().Set(reflect.ValueOf(p).Elem())
}
}
}

5
lightCore/Model.go Normal file
View File

@ -0,0 +1,5 @@
package lightCore
type Model interface {
IsLightModel()
}

162
lightCore/Responder.go Normal file
View File

@ -0,0 +1,162 @@
package lightCore
import (
"code.zhecent.com/gopkg/light-core/pkg/myAes"
"github.com/gin-gonic/gin"
"google.golang.org/protobuf/proto"
"net/http"
"reflect"
)
var RespondList []Responder
func init() {
RespondList = []Responder{
new(EmptyResponder),
new(StringResponder),
new(ModelResponder),
new(SuccessResponder),
new(JsonErrorResponder),
new(ViewResponder),
new(ProtobufResponder),
new(ProtobufAesResponder),
new(RedirectResponder),
}
}
type Responder interface {
RespondTo() gin.HandlerFunc
}
func Convert(handler interface{}) gin.HandlerFunc {
hRef := reflect.ValueOf(handler)
for _, r := range RespondList {
rRef := reflect.ValueOf(r).Elem()
if hRef.Type().ConvertibleTo(rRef.Type()) {
rRef.Set(hRef)
return rRef.Interface().(Responder).RespondTo()
}
}
return nil
}
type StringResponder func(*gin.Context) string
func (t StringResponder) RespondTo() gin.HandlerFunc {
return func(context *gin.Context) {
context.String(http.StatusOK, t(context))
}
}
type ModelResponder func(*gin.Context) Model
func (t ModelResponder) RespondTo() gin.HandlerFunc {
return func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": "",
"data": t(context),
})
}
}
type JsonSuccess string
type SuccessResponder func(*gin.Context) JsonSuccess
func (t SuccessResponder) RespondTo() gin.HandlerFunc {
return func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": string(t(context)),
"data": []int{},
})
}
}
type JsonError error
type JsonErrorResponder func(*gin.Context) JsonError
func (t JsonErrorResponder) RespondTo() gin.HandlerFunc {
return func(context *gin.Context) {
err := t(context)
if err != nil {
context.JSON(http.StatusOK, gin.H{
"code": 400,
"msg": err.Error(),
"data": []int{},
})
} else {
context.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": "success",
"data": []int{},
})
}
}
}
type EmptyResponder func(*gin.Context)
func (t EmptyResponder) RespondTo() gin.HandlerFunc {
//func(c *gin.Context)其实就是reply
//t,提示就是方法本身其实就是reply
return func(context *gin.Context) {
//context是gin给的全新的没有任何资料的
//t(context)其实就是运行reply
t(context)
//fmt.Println("========================")
//fmt.Println(context.Writer)
//fmt.Println("========================")
}
}
type View string
type ViewResponder func(*gin.Context) View
func (t ViewResponder) RespondTo() gin.HandlerFunc {
return func(context *gin.Context) {
context.HTML(http.StatusOK, string(t(context))+".html", context.Keys)
}
}
type Protobuf proto.Message
type ProtobufResponder func(*gin.Context) Protobuf
func (t ProtobufResponder) RespondTo() gin.HandlerFunc {
return func(context *gin.Context) {
context.ProtoBuf(http.StatusOK, t(context))
}
}
type ProtobufAes proto.Message
type ProtobufAesResponder func(*gin.Context) ProtobufAes
func (t ProtobufAesResponder) RespondTo() gin.HandlerFunc {
return func(context *gin.Context) {
str, err := proto.Marshal(t(context))
if err != nil {
context.String(http.StatusBadRequest, err.Error())
} else {
decrypt, err := myAes.AesTool(context.GetString("LightAppKey"), context.GetString("LightAppIv")).Encrypt(string(str))
if err != nil {
context.String(http.StatusBadRequest, err.Error())
} else {
context.String(http.StatusOK, string(decrypt))
}
}
}
}
type Redirect string
type RedirectResponder func(*gin.Context) Redirect
func (t RedirectResponder) RespondTo() gin.HandlerFunc {
return func(context *gin.Context) {
context.Redirect(http.StatusFound, string(t(context)))
}
}

33
lightCore/Start.go Normal file
View File

@ -0,0 +1,33 @@
package lightCore
import "code.zhecent.com/gopkg/light-core/pkg/myViper"
type Start struct {
config *Config
}
func NewByConfig(config *Config) *Start {
return &Start{config: config}
}
func NewByYAML(fileName string, path string) *Start {
c := &Config{}
myViper.NewSimpleViper(c, "yaml", fileName, path).Apply()
return &Start{config: c}
}
func (t *Start) Start() {
//校验配置
if t.config.App.JwtSecret == "" {
panic("App JwtSecret Empty")
}
if t.config.Server.RunMode == "" || t.config.Server.HttpPort == 0 {
panic("Server Config Error")
}
ConfigValue = t.config
//初始化数据库
InitDB()
}

76
lightCore/Task.go Normal file
View File

@ -0,0 +1,76 @@
package lightCore
import (
"fmt"
"sync"
)
type TaskFunc func()
var taskList chan *TaskExecutor //任务列表
var once sync.Once
func getTaskList() chan *TaskExecutor {
once.Do(func() {
taskList = make(chan *TaskExecutor, 0)
})
return taskList
}
func init() {
chList := getTaskList() //得到任务列表
go func() {
for t := range chList {
doTask(t)
}
}()
}
func doTask(t *TaskExecutor) {
go func() {
defer func() {
if t.callback != nil {
t.callback()
}
}()
t.Exec()
}()
}
type TaskExecutor struct {
f TaskFunc
callback func()
}
func NewTaskExecutor(f TaskFunc, callback func()) *TaskExecutor {
return &TaskExecutor{f: f, callback: callback}
}
func (t *TaskExecutor) Exec() {
t.f()
}
func Task(f TaskFunc, callBack func()) {
if f == nil {
return
}
newF := func() {
defer func() {
if e := recover(); e != nil {
if err, ok := e.(string); ok {
fmt.Println("===================================")
fmt.Println(fmt.Sprintf("协程运行错误:%s", err))
fmt.Println("===================================")
} else {
fmt.Println("===================================")
fmt.Println(fmt.Sprintf("协程运行错误:%s", "未知"))
fmt.Println("===================================")
}
}
}()
f()
}
go func() {
getTaskList() <- NewTaskExecutor(newF, callBack) //添加任务队列
}()
}

83
pkg/myAes/aes.go Normal file
View File

@ -0,0 +1,83 @@
package myAes
import (
"bytes"
basicAES "crypto/aes"
"crypto/cipher"
"encoding/base64"
)
type Aes struct {
securityKey []byte
iv []byte
}
/**
* constructor
*/
func AesTool(securityKey string, iv string) *Aes {
return &Aes{[]byte(securityKey), []byte(iv)}
}
/**
* 加密
* @param string $plainText 明文
* @return bool|string
*/
func (a Aes) Encrypt(plainText string) (string, error) {
block, err := basicAES.NewCipher(a.securityKey)
if err != nil {
return "", err
}
plainTextByte := []byte(plainText)
blockSize := block.BlockSize()
plainTextByte = addPKCS7Padding(plainTextByte, blockSize)
cipherText := make([]byte, len(plainTextByte))
mode := cipher.NewCBCEncrypter(block, a.iv)
mode.CryptBlocks(cipherText, plainTextByte)
return base64.StdEncoding.EncodeToString(cipherText), nil
}
/**
* 解密
* @param string $cipherText 密文
* @return bool|string
*/
func (a Aes) Decrypt(cipherText string) ([]byte, error) {
block, err := basicAES.NewCipher(a.securityKey)
if err != nil {
return []byte{}, err
}
cipherDecodeText, decodeErr := base64.StdEncoding.DecodeString(cipherText)
if decodeErr != nil {
return []byte{}, decodeErr
}
mode := cipher.NewCBCDecrypter(block, a.iv)
originCipherText := make([]byte, len(cipherDecodeText))
mode.CryptBlocks(originCipherText, cipherDecodeText)
originCipherText = stripPKSC7Padding(originCipherText)
return originCipherText, nil
}
/**
* 填充算法
* @param string $source
* @return string
*/
func addPKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
paddingText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, paddingText...)
}
/**
* 移去填充算法
* @param string $source
* @return string
*/
func stripPKSC7Padding(cipherText []byte) []byte {
length := len(cipherText)
unpadding := int(cipherText[length-1])
return cipherText[:(length - unpadding)]
}

90
pkg/myAliMarket/index.go Normal file
View File

@ -0,0 +1,90 @@
package myAliMarket
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
type Client struct {
url string
appCode string
param map[string]string
fullUrl string
response string
}
func New(url string, appCode string) *Client {
return &Client{
url: url,
appCode: appCode,
}
}
func (t *Client) SetParam(param map[string]string) {
t.param = param
}
func (t *Client) getFullUrl() (string, error) {
u, err := url.Parse(t.url)
if err != nil {
return "", err
}
q := u.Query()
for k, v := range t.param {
q.Add(k, v)
}
u.RawQuery = q.Encode()
t.fullUrl = u.String()
return t.fullUrl, nil
}
func (t *Client) GetFullUrl() string {
return t.fullUrl
}
func (t *Client) GetResponse() string {
return t.response
}
func (t *Client) GetRequest(respData interface{}) error {
fullUrl, err := t.getFullUrl()
if err != nil {
return err
}
client := &http.Client{}
request, err := http.NewRequest("GET", fullUrl, nil)
if err != nil {
return errors.New("http客户端初始化失败")
}
request.Header.Add("Authorization", fmt.Sprintf("APPCODE %s", t.appCode))
response, err := client.Do(request)
if err != nil {
return errors.New("认证服务器连接失败1")
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return errors.New("认证服务器连接失败2")
}
var response2 []byte
response2, err = ioutil.ReadAll(response.Body)
if err != nil {
return errors.New("数据解析失败")
}
t.response = string(response2)
err = json.Unmarshal(response2, respData)
if err != nil {
return err
}
return nil
}

61
pkg/myAliSms/index.go Normal file
View File

@ -0,0 +1,61 @@
package myAliSms
import (
"encoding/json"
"errors"
"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
)
type Client struct {
accessKeyId string
accessSecret string
signName string
templateCode string
}
func NewClient(accessKeyId string, accessSecret string) *Client {
return &Client{accessKeyId: accessKeyId, accessSecret: accessSecret}
}
func (t *Client) SetSignName(signName string) *Client {
t.signName = signName
return t
}
func (t *Client) SetTemplateCode(code string) *Client {
t.templateCode = code
return t
}
func (t *Client) SendSms(m map[string]interface{}, phone string) error {
if t.signName == "" {
return errors.New("签名不能为空")
}
client, err := dysmsapi.NewClientWithAccessKey("cn-hangzhou", t.accessKeyId, t.accessSecret)
if err != nil {
return err
}
request := dysmsapi.CreateSendSmsRequest()
request.Scheme = "https"
request.PhoneNumbers = phone
request.SignName = t.signName
request.TemplateCode = t.templateCode
request.TemplateParam = t.mapToJson(m)
response, err := client.SendSms(request)
if err != nil {
return err
} else {
if response.Code == "OK" {
return nil
} else {
return errors.New(response.Message)
}
}
}
func (t *Client) mapToJson(TemplateParamMap map[string]interface{}) string {
mjson, _ := json.Marshal(TemplateParamMap)
return string(mjson)
}

50
pkg/myCobra/cobra.go Normal file
View File

@ -0,0 +1,50 @@
package myCobra
import (
"github.com/spf13/cobra"
)
type SimpleCmd struct {
Use string
Short string
Example string
PreRun func()
RunE func() error
cobraModel *cobra.Command
}
func (t *SimpleCmd) GetCobra() *cobra.Command {
if t.cobraModel == nil {
t.cobraModel = &cobra.Command{
Use: t.Use,
Short: t.Short,
Example: t.Example,
SilenceUsage: true,
PreRun: func(cmd *cobra.Command, args []string) {
t.PreRun()
},
RunE: func(cmd *cobra.Command, args []string) error {
return t.RunE()
},
}
}
return t.cobraModel
}
func (t *SimpleCmd) SetArgsFunc(argsFunc func(args []string) error) {
t.GetCobra().Args = func(cmd *cobra.Command, args []string) error {
return argsFunc(args)
}
}
func (t *SimpleCmd) SetStringVar(p *string, name, shorthand string, value string, usage string) {
t.GetCobra().PersistentFlags().StringVarP(p, name, shorthand, value, usage)
}
func (t *SimpleCmd) AddCommand(cmd *SimpleCmd) {
t.GetCobra().AddCommand(cmd.GetCobra())
}
func (t *SimpleCmd) Execute() error {
return t.GetCobra().Execute()
}

88
pkg/myGorm/gorm.go Normal file
View File

@ -0,0 +1,88 @@
package myGorm
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"strings"
"time"
)
type SimpleORM struct {
user string
password string
host string
name string
charset string
runMode string
loggerConfig logger.Config
loggerLevel string
}
func NewSimpleORM(user string, password string, host string, name string, charset string, runMode string) *SimpleORM {
orm := &SimpleORM{
user: user,
password: password,
host: host,
name: name,
charset: charset,
runMode: runMode,
loggerConfig: logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
Colorful: false, // 禁用彩色打印
LogLevel: logger.Info,
},
}
if runMode == "release" {
orm.loggerConfig.LogLevel = logger.Silent
}
return orm
}
func (t *SimpleORM) getDSN() string {
if t.charset == "" {
t.charset = "utf8mb4"
}
return fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=True&loc=Local",
t.user,
t.password,
t.host,
t.name,
t.charset,
)
}
func (t *SimpleORM) SetLoggerConfig(l logger.Config) {
t.loggerConfig = l
}
func (t *SimpleORM) SetLoggerLevel(level string) {
if strings.ToLower(level) == "silent" {
t.loggerConfig.LogLevel = logger.Silent
} else if strings.ToLower(level) == "error" {
t.loggerConfig.LogLevel = logger.Error
} else if strings.ToLower(level) == "warn" {
t.loggerConfig.LogLevel = logger.Warn
} else if strings.ToLower(level) == "info" {
t.loggerConfig.LogLevel = logger.Info
}
}
func (t *SimpleORM) ConnectMysql() *gorm.DB {
Db, err := gorm.Open(
mysql.Open(t.getDSN()), &gorm.Config{
Logger: logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
t.loggerConfig,
),
},
)
if err != nil {
panic("failed to connect database")
}
return Db
}

32
pkg/myHttp/header.go Normal file
View File

@ -0,0 +1,32 @@
package myHttp
func (t *Client) HasHeader(key string) bool {
for k, _ := range t.headers {
if key == k {
return true
}
}
return false
}
func (t *Client) SetHeaders(header map[string]string) *Client {
t.headers = header
return t
}
func (t *Client) AddHeader(key, value string) *Client {
t.headers[key] = value
return t
}
func (t *Client) AddHeaders(header map[string]string) *Client {
for k, v := range header {
t.headers[k] = v
}
return t
}
func (t *Client) DelHeader(key string) *Client {
delete(t.headers, key)
return t
}

22
pkg/myHttp/index.go Normal file
View File

@ -0,0 +1,22 @@
package myHttp
import (
"code.zhecent.com/gopkg/light-core/pkg/myUrl"
)
type Client struct {
url *myUrl.UrlCli
headers map[string]string
}
func NewClient(url string) (*Client, error) {
urlObj, err := myUrl.NewUrlCliWithParse(url)
if err != nil {
return nil, err
}
return &Client{url: urlObj}, nil
}
func (t *Client) GetMyUrl() *myUrl.UrlCli {
return t.url
}

57
pkg/myHttp/json.go Normal file
View File

@ -0,0 +1,57 @@
package myHttp
import (
"bytes"
"encoding/json"
"errors"
"net/http"
)
func (t *Client) PostJson(request interface{}, response interface{}) error {
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.SetEscapeHTML(false)
if err := encoder.Encode(request); err != nil {
return err
}
// HTTP请求
req, err := http.NewRequest("POST", t.url.String(), &buf)
if err != nil {
return err
}
//添加请求头
req.Header.Set("Content-Type", "application/json; charset=utf-8")
if len(t.headers) > 0 {
for key, value := range t.headers {
req.Header.Set(key, value)
}
}
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return errors.New("http.Status:" + resp.Status)
}
return json.NewDecoder(resp.Body).Decode(response)
}
func (t *Client) GetJson(response interface{}) error {
httpResp, err := http.Get(t.url.String())
if err != nil {
return err
}
defer httpResp.Body.Close()
if httpResp.StatusCode != http.StatusOK {
return errors.New("http.Status:" + httpResp.Status)
}
return json.NewDecoder(httpResp.Body).Decode(response)
}

115
pkg/myJwt/jwt.go Normal file
View File

@ -0,0 +1,115 @@
package myJwt
import (
"errors"
"github.com/golang-jwt/jwt/v5"
"time"
)
type Claims struct {
UserId int `json:"uid"`
jwt.RegisteredClaims
}
func (t Claims) toSimpleJwt() *SimpleJwt {
return &SimpleJwt{
Audience: t.Audience,
ExpiresAt: t.ExpiresAt,
Id: t.ID,
IssuedAt: t.IssuedAt,
Issuer: t.Issuer,
NotBefore: t.NotBefore,
Subject: t.Subject,
userId: t.UserId,
jwtSecret: "",
}
}
type SimpleJwt struct {
Audience jwt.ClaimStrings
ExpiresAt *jwt.NumericDate
Id string
IssuedAt *jwt.NumericDate
Issuer string
NotBefore *jwt.NumericDate
Subject string
userId int
jwtSecret string
}
func NewSimpleJwt(userId int, jwtSecret string) *SimpleJwt {
return &SimpleJwt{
userId: userId,
jwtSecret: jwtSecret,
ExpiresAt: jwt.NewNumericDate(time.Now().Add(90 * 24 * time.Hour)),
Issuer: "zhecent",
}
}
func (t *SimpleJwt) SetExpiresAt(expiresAt time.Time) {
t.ExpiresAt = jwt.NewNumericDate(expiresAt)
}
func (t *SimpleJwt) makeClaims() Claims {
return Claims{
UserId: t.userId,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: t.ExpiresAt,
Issuer: t.Issuer,
},
}
}
func (t *SimpleJwt) GetUserId() int {
return t.userId
}
func (t *SimpleJwt) GenerateToken() (string, error) {
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, t.makeClaims())
token, err := tokenClaims.SignedString([]byte(t.jwtSecret))
return token, err
}
func (t *SimpleJwt) MustGenerateToken() string {
s, e := t.GenerateToken()
if e != nil {
panic(e.Error())
}
return s
}
func ParseToken(token string, jwtSecret string) (*SimpleJwt, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(jwtSecret), nil
})
if tokenClaims != nil {
if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
return claims.toSimpleJwt(), nil
}
}
switch {
case errors.Is(err, jwt.ErrTokenMalformed):
return nil, errors.New("that's not even a token")
case errors.Is(err, jwt.ErrTokenSignatureInvalid):
// Invalid signature
return nil, errors.New("invalid signature")
case errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet):
// Token is either expired or not active yet
return nil, errors.New("timing is everything")
default:
return nil, errors.New("token校验失败")
}
}
func MustParseToken(token string, jwtSecret string) *SimpleJwt {
s, e := ParseToken(token, jwtSecret)
if e != nil {
panic(e.Error())
}
return s
}

138
pkg/myOss/index.go Normal file
View File

@ -0,0 +1,138 @@
package myOss
import (
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"io"
"net/http"
"strings"
)
type Model struct {
Path string
Bucket string
ACLType string
Endpoint string
AccessKeyID string
SecretAccessKey string
StorageClassType string
CdnUrl string
ossClient *oss.Client
ossBucket *oss.Bucket
}
func (t *Model) MustGetOssClient() *oss.Client {
if t.ossClient == nil {
client, err := oss.New(t.Endpoint, t.AccessKeyID, t.SecretAccessKey, oss.Timeout(10, 120))
if err != nil {
panic("function oss.New() Filed, err:" + err.Error())
}
t.ossClient = client
}
return t.ossClient
}
func (t *Model) MustGetDefaultOssBucket() *oss.Bucket {
if t.ossBucket == nil {
client := t.MustGetOssClient()
bucket, err := client.Bucket(t.Bucket)
if err != nil {
panic("function client.Bucket() Filed, err:" + err.Error())
}
t.ossBucket = bucket
}
return t.ossBucket
}
func (t *Model) PutObject(savePath, fileName string, reader io.Reader, contentType string) (*RespPath, error) {
err := t.MustGetDefaultOssBucket().PutObject(
fmt.Sprintf("%s/%s", savePath, fileName),
reader,
oss.ContentType(contentType),
t.GetObjectStorageClass(),
t.GetObjectAcl(),
)
return &RespPath{
Path: savePath,
Name: fileName,
Host: t.CdnUrl,
}, err
}
func (t *Model) MustPutObject(savePath, fileName string, reader io.Reader, contentType string) *RespPath {
p, err := t.PutObject(savePath, fileName, reader, contentType)
if err != nil {
panic(err.Error())
}
return p
}
func (t *Model) GetObjectMeta(key string) (http.Header, error) {
if strings.HasPrefix(key, "/") {
key = strings.TrimLeft(key, "/")
}
return t.MustGetDefaultOssBucket().GetObjectMeta(key)
}
func (t *Model) DeleteObject(key string) error {
// 删除单个文件。objectName表示删除OSS文件时需要指定包含文件后缀在内的完整路径例如abc/efg/123.jpg。
// 如需删除文件夹请将objectName设置为对应的文件夹名称。如果文件夹非空则需要将文件夹下的所有object删除后才能删除该文件夹。
//这里需要处理一下路径,如果第一个是/,要去掉
if strings.HasPrefix(key, "/") {
key = strings.TrimLeft(key, "/")
}
if t.IsFileExist(key) {
return t.MustGetDefaultOssBucket().DeleteObject(key)
}
return fmt.Errorf("文件不存在")
}
func (t *Model) IsFileExist(key string) bool {
if strings.HasPrefix(key, "/") {
key = strings.TrimLeft(key, "/")
}
exist, err := t.MustGetDefaultOssBucket().IsObjectExist(key)
if err != nil {
panic(err.Error())
}
return exist
}
func (t *Model) GetObjectStorageClass() oss.Option {
switch t.StorageClassType { // 根据配置文件进行指定存储类型
case "Standard": // 指定存储类型为标准存储
return oss.ObjectStorageClass(oss.StorageStandard)
case "IA": // 指定存储类型为很少访问存储
return oss.ObjectStorageClass(oss.StorageIA)
case "Archive": // 指定存储类型为归档存储。
return oss.ObjectStorageClass(oss.StorageArchive)
case "ColdArchive": // 指定存储类型为归档存储。
return oss.ObjectStorageClass(oss.StorageColdArchive)
default: // 无匹配结果就是标准存储
return oss.ObjectStorageClass(oss.StorageStandard)
}
}
func (t *Model) GetObjectAcl() oss.Option {
switch t.ACLType { // 根据配置文件进行指定访问权限
case "private": // 指定访问权限为私有读写
return oss.ObjectACL(oss.ACLPrivate) // 指定访问权限为公共读
case "public-read":
return oss.ObjectACL(oss.ACLPublicRead) // 指定访问权限为公共读
case "public-read-write":
return oss.ObjectACL(oss.ACLPublicReadWrite) // 指定访问权限为公共读写
case "default":
return oss.ObjectACL(oss.ACLDefault) // 指定访问权限为公共读
default:
return oss.ObjectACL(oss.ACLPrivate) // 默认为访问权限为公共读
}
}
type RespPath struct {
Path string
Name string
Host string
}

145
pkg/myPay/alipay.go Normal file
View File

@ -0,0 +1,145 @@
package myPay
import (
"context"
"errors"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/alipay"
"github.com/shopspring/decimal"
"net/http"
)
type AliPay struct {
ctx context.Context
cli *alipay.Client
params *AliPayImpl
orderNo string
amount int
description string
notifyUrl string
returnUrl string
}
func NewAliPay(params *AliPayImpl) *AliPay {
client, err := alipay.NewClient(params.AppId, params.PrivateKey, params.IsProd)
if err != nil {
panic(err.Error())
}
// 打开Debug开关输出日志默认是关闭的
if params.IsProd {
client.DebugSwitch = gopay.DebugOff
} else {
client.DebugSwitch = gopay.DebugOn
}
client.SetLocation(alipay.LocationShanghai).
SetCharset(alipay.UTF8).
SetSignType(alipay.RSA2).
AutoVerifySign([]byte(params.PublicKey))
if err := client.SetCertSnByContent([]byte(params.AppCertContent), []byte(params.AliPayRootCertContent), []byte(params.PublicKey)); err != nil {
panic(err.Error())
}
return &AliPay{params: params, cli: client, ctx: context.Background()}
}
func (t *AliPay) GetCli() *alipay.Client {
return t.cli
}
func (t *AliPay) SetCommonConfig(notifyUrl string, returnUrl string) *AliPay {
t.notifyUrl = notifyUrl
t.returnUrl = returnUrl
return t
}
func (t *AliPay) SetOrderInfo(orderNo string, amount int, description string) *AliPay {
t.orderNo = orderNo
t.amount = amount
t.description = description
return t
}
func (t *AliPay) SetCertSnByContent(appCertContent, aliPayRootCertContent []byte) error {
return t.cli.SetCertSnByContent(appCertContent, aliPayRootCertContent, []byte(t.params.PublicKey))
}
func (t *AliPay) SetCertSnByPath(appCertPath, aliPayRootCertPath, aliPayPublicCertPath string) error {
return t.cli.SetCertSnByPath(appCertPath, aliPayRootCertPath, aliPayPublicCertPath)
}
func (t *AliPay) setBodyMap() gopay.BodyMap {
if t.description == "" || t.orderNo == "" || t.notifyUrl == "" {
panic("param is empty")
}
if t.amount == 0 {
panic("amount is zero")
}
// 配置公共参数
t.cli.SetNotifyUrl(t.notifyUrl).
SetReturnUrl(t.returnUrl)
bm := make(gopay.BodyMap)
bm.Set("subject", t.description)
bm.Set("out_trade_no", t.orderNo)
bm.Set("total_amount", t.fen2Yuan(uint64(t.amount)))
return bm
}
func (t *AliPay) GetWapPay(quitUrl string) (string, error) {
bm := t.setBodyMap()
bm.Set("quit_url", quitUrl)
bm.Set("product_code", "QUICK_WAP_WAY")
return t.cli.TradeWapPay(t.ctx, bm)
}
func (t *AliPay) GetPagePay() (string, error) {
bm := t.setBodyMap()
bm.Set("product_code", "FAST_INSTANT_TRADE_PAY")
return t.cli.TradePagePay(t.ctx, bm)
}
func (t *AliPay) GetAppPay() (string, error) {
bm := t.setBodyMap()
bm.Set("product_code", "QUICK_MSECURITY_PAY")
return t.cli.TradeAppPay(t.ctx, bm)
}
func (t *AliPay) Notify(req *http.Request) (*AlipayNotifyResp, error) {
notifyReq, err := alipay.ParseNotifyToBodyMap(req)
if err != nil {
return nil, errors.New("解析回调失败")
}
if ok, err := alipay.VerifySign(t.params.PublicKey, notifyReq); err != nil || ok == false {
return nil, errors.New("sign Error")
}
return &AlipayNotifyResp{resp: notifyReq}, nil
}
func (t *AliPay) GetOrderNo() string {
return t.orderNo
}
func (t *AliPay) GetAmount() int {
return t.amount
}
type AliPayImpl struct {
AppId string
PublicKey string
PrivateKey string
IsProd bool
AppCertContent string
AliPayRootCertContent string
}
func (t *AliPay) fen2Yuan(price uint64) string {
d := decimal.New(1, 2)
result := decimal.NewFromInt(int64(price)).DivRound(d, 2).String()
return result
}

View File

@ -0,0 +1,28 @@
package myPay
import "github.com/go-pay/gopay"
type AlipayNotifyResp struct {
resp gopay.BodyMap
}
type AlipayNotifyRespInfo struct {
TradeStatus string
OutTradeNo string
SellerId string
TradeNo string
GmtPayment string
}
func (t *AlipayNotifyResp) IsSuccess() bool {
return t.resp.Get("trade_status") == "TRADE_SUCCESS"
}
func (t *AlipayNotifyResp) GetResult() *AlipayNotifyRespInfo {
return &AlipayNotifyRespInfo{
TradeStatus: t.resp.Get("trade_status"),
OutTradeNo: t.resp.Get("out_trade_no"),
SellerId: t.resp.Get("seller_id"),
TradeNo: t.resp.Get("trade_no"),
GmtPayment: t.resp.Get("gmt_payment"),
}
}

261
pkg/myPay/wechat.go Normal file
View File

@ -0,0 +1,261 @@
package myPay
import (
"context"
"errors"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/wechat/v3"
"net/http"
"time"
)
type Wechat struct {
ctx context.Context
cli *wechat.ClientV3
params *WechatPayV3Impl
orderNo string
amount int
description string
notifyUrl string
profitSharing bool
}
func NewWechat(params *WechatPayV3Impl) *Wechat {
// NewClientV3 初始化微信客户端 v3
// mchid商户ID 或者服务商模式的 sp_mchid
// serialNo商户证书的证书序列号
// apiV3KeyapiV3Key商户平台获取
// privateKey私钥 apiclient_key.pem 读取后的内容
client, err := wechat.NewClientV3(params.MchId, params.SerialNo, params.ApiV3Key, params.PKContent)
if err != nil {
panic(err.Error())
}
// 设置微信平台API证书和序列号推荐开启自动验签无需手动设置证书公钥等信息
//client.SetPlatformCert([]byte(""), "")
// 启用自动同步返回验签并定时更新微信平台API证书开启自动验签时无需单独设置微信平台API证书和序列号
client.SetPlatformCert([]byte(params.WxPkContent), params.WxPkSerialNo)
// 启用自动同步返回验签并定时更新微信平台API证书
//err = client.AutoVerifySign()
//if err != nil {
// return nil, err
//}
// 打开Debug开关输出日志默认是关闭的
if params.IsProd {
client.DebugSwitch = gopay.DebugOff
} else {
client.DebugSwitch = gopay.DebugOn
}
return &Wechat{params: params, cli: client, ctx: context.Background()}
}
func (t *Wechat) GetCli() *wechat.ClientV3 {
return t.cli
}
func (t *Wechat) SetCommonConfig(notifyUrl string) *Wechat {
t.notifyUrl = notifyUrl
return t
}
func (t *Wechat) SetOrderInfo(orderNo string, amount int, description string) *Wechat {
t.orderNo = orderNo
t.amount = amount
t.description = description
return t
}
func (t *Wechat) setBodyMap() gopay.BodyMap {
if t.description == "" || t.orderNo == "" || t.notifyUrl == "" {
panic("param is empty")
}
if t.amount == 0 {
panic("amount is zero")
}
bm := make(gopay.BodyMap)
bm.Set("description", t.description).
Set("out_trade_no", t.orderNo).
Set("time_expire", time.Now().Add(10*time.Minute).Format(time.RFC3339)).
Set("notify_url", t.notifyUrl).
SetBodyMap("amount", func(bm gopay.BodyMap) {
bm.Set("total", t.amount).Set("currency", "CNY")
})
if t.profitSharing {
bm.SetBodyMap("settle_info", func(bm gopay.BodyMap) {
bm.Set("profit_sharing", true)
})
}
return bm
}
func (t *Wechat) SetProfitSharing(b bool) *Wechat {
t.profitSharing = b
return t
}
func (t *Wechat) GetApp() (*wechat.AppPayParams, error) {
wxRsp, err := t.cli.V3TransactionApp(t.ctx, t.setBodyMap().Set("appid", t.params.AppAppid))
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return t.cli.PaySignOfApp(t.params.AppAppid, wxRsp.Response.PrepayId)
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) GetJsapi(openId string) (*wechat.JSAPIPayParams, error) {
wxRsp, err := t.cli.V3TransactionJsapi(t.ctx,
t.setBodyMap().Set("appid", t.params.MpAppid).SetBodyMap("payer", func(bm gopay.BodyMap) {
bm.Set("openid", openId)
}),
)
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return t.cli.PaySignOfJSAPI(t.params.MpAppid, wxRsp.Response.PrepayId)
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) GetJsapiForMini(openId string) (*wechat.JSAPIPayParams, error) {
wxRsp, err := t.cli.V3TransactionJsapi(t.ctx,
t.setBodyMap().Set("appid", t.params.MiniAppid).SetBodyMap("payer", func(bm gopay.BodyMap) {
bm.Set("openid", openId)
}),
)
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return t.cli.PaySignOfJSAPI(t.params.MiniAppid, wxRsp.Response.PrepayId)
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) GetNative() (*wechat.Native, error) {
wxRsp, err := t.cli.V3TransactionNative(t.ctx, t.setBodyMap().Set("appid", t.params.MpAppid))
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return wxRsp.Response, err
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) GetH5(ip string, appName string, appUrl string) (*wechat.H5Url, error) {
wxRsp, err := t.cli.V3TransactionH5(t.ctx, t.setBodyMap().Set("appid", t.params.MpAppid).SetBodyMap("scene_info", func(bm gopay.BodyMap) {
bm.Set("payer_client_ip", ip)
bm.SetBodyMap("h5_info", func(bm gopay.BodyMap) {
bm.Set("type", "Wap")
bm.Set("app_url", appUrl)
bm.Set("app_name", appName)
})
}))
if err != nil {
return nil, err
}
if wxRsp.Code == wechat.Success {
//校验签名
if err2 := wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, t.cli.WxPublicKey()); err != nil {
return nil, err2
}
//获取调起参数
return wxRsp.Response, nil
} else {
return nil, errors.New(wxRsp.Error)
}
}
func (t *Wechat) Notify(req *http.Request) (*WechatNotifyResp, error) {
notifyReq, err := wechat.V3ParseNotify(req)
if err != nil {
return nil, errors.New("解析回调失败")
}
err = notifyReq.VerifySignByPK(t.cli.WxPublicKey())
if err != nil {
return nil, errors.New("sign Error")
}
if notifyReq.EventType == "TRANSACTION.SUCCESS" {
result, err := notifyReq.DecryptPayCipherText(t.params.ApiV3Key)
if err != nil {
return nil, errors.New("解密错误")
} else {
return &WechatNotifyResp{resp: result}, nil
}
}
return nil, errors.New(notifyReq.EventType)
}
func (t *Wechat) GetOrderNo() string {
return t.orderNo
}
func (t *Wechat) GetAmount() int {
return t.amount
}
func NotifySuccess(msg string) (int, *wechat.V3NotifyRsp) {
return http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: msg}
}
func NotifyFail(msg string) (int, *wechat.V3NotifyRsp) {
return http.StatusBadRequest, &wechat.V3NotifyRsp{Code: gopay.FAIL, Message: msg}
}
type WechatPayV3Impl struct {
MpAppid string
AppAppid string
MiniAppid string
MchId string
ApiV3Key string
SerialNo string
PKContent string
WxPkSerialNo string
WxPkContent string
IsProd bool
}

View File

@ -0,0 +1,15 @@
package myPay
import "github.com/go-pay/gopay/wechat/v3"
type WechatNotifyResp struct {
resp *wechat.V3DecryptPayResult
}
func (t *WechatNotifyResp) IsSuccess() bool {
return t.resp.TradeState == "SUCCESS"
}
func (t *WechatNotifyResp) GetResult() *wechat.V3DecryptPayResult {
return t.resp
}

23
pkg/myRedis/Ierator.go Normal file
View File

@ -0,0 +1,23 @@
package myRedis
type Iterator struct {
data []interface{}
index int
}
func NewIterator(data []interface{}) *Iterator {
return &Iterator{data: data}
}
func (t *Iterator) HasNext() bool {
if t.data == nil || len(t.data) == 0 {
return false
}
return t.index < len(t.data)
}
func (t *Iterator) Next() (ret interface{}) {
ret = t.data[t.index]
t.index = t.index + 1
return
}

33
pkg/myRedis/IntResult.go Normal file
View File

@ -0,0 +1,33 @@
package myRedis
type IntResult struct {
Result int64
Err error
}
func NewIntResult(result int64, err error) *IntResult {
return &IntResult{Result: result, Err: err}
}
func (t *IntResult) Unwrap() int64 {
if t.Err != nil {
panic(t.Err)
}
return t.Result
}
func (t *IntResult) UnwrapOr(str int64) int64 {
if t.Err != nil {
return str
} else {
return t.Result
}
}
func (t *IntResult) UnwrapOrElse(f func() int64) int64 {
if t.Err != nil {
return f()
}
return t.Result
}

View File

@ -0,0 +1,25 @@
package myRedis
type InterfaceResult struct {
Result interface{}
Err error
}
func NewInterfaceResult(result interface{}, err error) *InterfaceResult {
return &InterfaceResult{Result: result, Err: err}
}
func (t *InterfaceResult) Unwrap() interface{} {
if t.Err != nil {
panic(t.Err)
}
return t.Result
}
func (t *InterfaceResult) UnwrapOr(a interface{}) interface{} {
if t.Err != nil {
return a
}
return t.Result
}

View File

@ -0,0 +1,52 @@
package myRedis
import (
"fmt"
"time"
)
const (
AttrExpr = "expr"
AttrNx = "nx"
AttrXx = "xx"
)
type empty struct {
}
type OperationAttr struct {
Name string
Value interface{}
}
type OperationAttrs []*OperationAttr
func (t OperationAttrs) Find(name string) *InterfaceResult {
for _, attr := range t {
if attr.Name == name {
return NewInterfaceResult(attr.Value, nil)
}
}
return NewInterfaceResult(nil, fmt.Errorf("OperationAttrs found error:%s", name))
}
func WithExpire(t time.Duration) *OperationAttr {
return &OperationAttr{
Name: AttrExpr,
Value: t,
}
}
func WithNX() *OperationAttr {
return &OperationAttr{
Name: AttrNx,
Value: empty{},
}
}
func WithXX() *OperationAttr {
return &OperationAttr{
Name: AttrXx,
Value: empty{},
}
}

132
pkg/myRedis/SimpleCache.go Normal file
View File

@ -0,0 +1,132 @@
package myRedis
import (
"bytes"
"encoding/gob"
"encoding/json"
"time"
)
const (
SerializerNot = ""
SerializerJson = "json"
SerializerGob = "gob"
)
type CacheGetterFunc func() interface{}
type SimpleCache struct {
Operation *StringOperation
Expire time.Duration
CacheGetter CacheGetterFunc
Serializer string //序列化方式
}
func NewSimpleCache(operation *StringOperation, expire time.Duration, serializer string) *SimpleCache {
return &SimpleCache{Operation: operation, Expire: expire, Serializer: serializer}
}
func (t *SimpleCache) SetCacheGetterFunc(f CacheGetterFunc) *SimpleCache {
t.CacheGetter = f
return t
}
// 设置缓存
func (t *SimpleCache) SetCache(key string, value interface{}) {
//if t.Serializer == SerializerNot {
//}
if t.Serializer == SerializerJson {
f := func() string {
j, e := json.Marshal(value)
if e != nil {
return e.Error()
} else {
return string(j)
}
}
t.Operation.Set(key, f(), WithExpire(t.Expire)).Unwrap()
} else if t.Serializer == SerializerGob {
f := func() string {
var buf = &bytes.Buffer{}
enc := gob.NewEncoder(buf)
if err := enc.Encode(value); err != nil {
return ""
}
return buf.String()
}
t.Operation.Set(key, f(), WithExpire(t.Expire)).Unwrap()
} else {
t.Operation.Set(key, value, WithExpire(t.Expire)).Unwrap()
}
}
func (t *SimpleCache) GetCache(key string) (ret interface{}) {
//如果没有设置的话
if t.CacheGetter == nil {
panic("没有设置CacheGetter")
}
if t.Serializer == SerializerNot {
}
if t.Serializer == SerializerJson {
f := func() string {
j, e := json.Marshal(t.CacheGetter())
if e != nil {
return e.Error()
} else {
return string(j)
}
}
ret = t.Operation.Get(key).UnwrapOrElse(func() string {
data := f()
t.Operation.Set(key, data, WithExpire(t.Expire)).Unwrap()
return data
})
}
if t.Serializer == SerializerGob {
f := func() string {
var buf = &bytes.Buffer{}
enc := gob.NewEncoder(buf)
if err := enc.Encode(t.CacheGetter()); err != nil {
return ""
}
return buf.String()
}
ret = t.Operation.Get(key).UnwrapOrElse(func() string {
data := f()
t.Operation.Set(key, data, WithExpire(t.Expire)).Unwrap()
return data
})
}
return
}
func (t *SimpleCache) DelCache(key string) int64 {
return t.Operation.Del(key).UnwrapOr(0)
}
func (t *SimpleCache) GetCacheForObject(key string, obj interface{}) interface{} {
ret := t.GetCache(key)
if ret == nil {
return nil
}
if t.Serializer == SerializerNot {
obj = ret
} else if t.Serializer == SerializerJson {
err := json.Unmarshal([]byte(ret.(string)), obj)
if err != nil {
return nil
}
} else if t.Serializer == SerializerGob {
var buf = &bytes.Buffer{}
buf.WriteString(ret.(string))
dec := gob.NewDecoder(buf)
if dec.Decode(obj) != nil {
return nil
}
}
return nil
}

View File

@ -0,0 +1,29 @@
package myRedis
type SliceResult struct {
Result []interface{}
Err error
}
func NewSliceResult(result []interface{}, err error) *SliceResult {
return &SliceResult{Result: result, Err: err}
}
func (t *SliceResult) Unwrap() []interface{} {
if t.Err != nil {
panic(t.Err)
}
return t.Result
}
func (t *SliceResult) UnwrapOr(strs []interface{}) []interface{} {
if t.Err != nil {
return strs
} else {
return t.Result
}
}
func (t *SliceResult) Iter() *Iterator {
return NewIterator(t.Result)
}

View File

@ -0,0 +1,52 @@
package myRedis
import (
"github.com/redis/go-redis/v9"
"time"
)
type StringCache struct {
Operation *StringOperation
Expire time.Duration
DefaultString string
}
func NewStringCache(redisClient *redis.Client) *StringCache {
return &StringCache{
Operation: NewStringOperation(redisClient),
Expire: time.Second * 0,
DefaultString: "",
}
}
func (t *StringCache) SetExpire(expire time.Duration) *StringCache {
t.Expire = expire
return t
}
func (t *StringCache) SetDefaultString(defaultString string) *StringCache {
t.DefaultString = defaultString
return t
}
func (t *StringCache) SetCache(key string, value string) {
t.Operation.Set(key, value, WithExpire(t.Expire))
}
func (t *StringCache) GetCache(key string) (ret string) {
ret = t.Operation.Get(key).UnwrapOrElse(func() string {
if t.DefaultString != "" {
t.SetCache(key, t.DefaultString)
}
return t.DefaultString
})
return
}
func (t *StringCache) IsExist(key string) bool {
return t.Operation.Exist(key).UnwrapOr(0) != 0
}
func (t *StringCache) DelCache(key string) int64 {
return t.Operation.Del(key).UnwrapOr(0)
}

View File

@ -0,0 +1,48 @@
package myRedis
import (
"context"
"github.com/redis/go-redis/v9"
"time"
)
type StringOperation struct {
ctx context.Context
client *redis.Client
}
func NewStringOperation(client *redis.Client) *StringOperation {
return &StringOperation{ctx: context.Background(), client: client}
}
func (t *StringOperation) Set(key string, value interface{}, attrs ...*OperationAttr) *InterfaceResult {
exp := OperationAttrs(attrs).Find(AttrExpr).UnwrapOr(0 * time.Second).(time.Duration)
nx := OperationAttrs(attrs).Find(AttrNx).UnwrapOr(nil)
if nx != nil {
return NewInterfaceResult(t.client.SetNX(t.ctx, key, value, exp).Result())
}
xx := OperationAttrs(attrs).Find(AttrXx).UnwrapOr(nil)
if xx != nil {
return NewInterfaceResult(t.client.SetXX(t.ctx, key, value, exp).Result())
}
return NewInterfaceResult(t.client.Set(t.ctx, key, value, exp).Result())
}
func (t *StringOperation) Get(key string) *StringResult {
return NewStringResult(t.client.Get(t.ctx, key).Result())
}
func (t *StringOperation) MGet(key ...string) *SliceResult {
return NewSliceResult(t.client.MGet(t.ctx, key...).Result())
}
func (t *StringOperation) Del(key string) *IntResult {
return NewIntResult(t.client.Del(t.ctx, key).Result())
}
func (t *StringOperation) Exist(key string) *IntResult {
return NewIntResult(t.client.Exists(t.ctx, key).Result())
}

View File

@ -0,0 +1,33 @@
package myRedis
type StringResult struct {
Result string
Err error
}
func NewStringResult(result string, err error) *StringResult {
return &StringResult{Result: result, Err: err}
}
func (t *StringResult) Unwrap() string {
if t.Err != nil {
panic(t.Err)
}
return t.Result
}
func (t *StringResult) UnwrapOr(str string) string {
if t.Err != nil {
return str
} else {
return t.Result
}
}
func (t *StringResult) UnwrapOrElse(f func() string) string {
if t.Err != nil {
return f()
}
return t.Result
}

33
pkg/myRedis/cli.go Normal file
View File

@ -0,0 +1,33 @@
package myRedis
import (
"github.com/redis/go-redis/v9"
"time"
)
type Client struct {
client *redis.Client
}
func NewClient(client *redis.Client) *Client {
if client == nil {
panic("redis client is nil")
}
return &Client{client: client}
}
func (t *Client) GetClient() *redis.Client {
return t.client
}
func (t *Client) NewStringCache() *StringCache {
return NewStringCache(t.client)
}
func (t *Client) NewJsonCache(expire time.Duration) *SimpleCache {
return NewSimpleCache(NewStringOperation(t.client), expire, SerializerJson)
}
func (t *Client) NewGobCache(expire time.Duration) *SimpleCache {
return NewSimpleCache(NewStringOperation(t.client), expire, SerializerGob)
}

60
pkg/myRedis/index.go Normal file
View File

@ -0,0 +1,60 @@
package myRedis
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
"log"
"sync"
)
type SimpleRedis struct {
Host string
Password string
hosts map[int]*Hosts
}
type Hosts struct {
clientOnce sync.Once
client *redis.Client
}
func NewSimpleRedis(host string, password string) *SimpleRedis {
return &SimpleRedis{Host: host, Password: password, hosts: map[int]*Hosts{}}
}
func (t *SimpleRedis) connectRedis(index int) *redis.Client {
if t.hosts[index] == nil {
t.hosts[index] = &Hosts{
clientOnce: sync.Once{},
client: nil,
}
}
t.hosts[index].clientOnce.Do(func() {
redisClient := redis.NewClient(&redis.Options{
Addr: t.Host,
Password: t.Password, // no password set
DB: index, // use default DB
//连接池容量以闲置链接数量
PoolSize: 15,
MinIdleConns: 10,
})
pong, err := redisClient.Ping(context.Background()).Result()
if err != nil {
panic(fmt.Errorf("connect error:%s", err))
}
log.Println(fmt.Sprintf("redis newClient success, index%d, pong: %s", index, pong))
t.hosts[index].client = redisClient
})
return t.hosts[index].client
}
func (t *SimpleRedis) ConnectDefaultRedis() *Client {
return t.GetRedisClient(0)
}
func (t *SimpleRedis) GetRedisClient(index int) *Client {
return NewClient(t.connectRedis(index))
}

42
pkg/myUrl/index.go Normal file
View File

@ -0,0 +1,42 @@
package myUrl
import "net/url"
type UrlCli struct {
url url.URL
params url.Values
}
func NewUrlCli(scheme string, host string) *UrlCli {
return &UrlCli{url: url.URL{Scheme: scheme, Host: host}, params: url.Values{}}
}
func NewUrlCliWithParse(data string) (*UrlCli, error) {
urlObj, err := url.Parse(data)
if err != nil {
return nil, err
}
return &UrlCli{
url: *urlObj,
params: urlObj.Query(),
}, nil
}
func (t *UrlCli) Set(m map[string]string) {
params := url.Values{}
for s, s2 := range m {
params.Set(s, s2)
}
t.params = params
}
func (t *UrlCli) Add(key, value string) *UrlCli {
t.params.Set(key, value)
return t
}
func (t *UrlCli) String() string {
baseURL := t.url
baseURL.RawQuery = t.params.Encode()
return baseURL.String()
}

31
pkg/myViper/viper.go Normal file
View File

@ -0,0 +1,31 @@
package myViper
import (
"fmt"
"github.com/spf13/viper"
)
type SimpleViper struct {
config interface{}
configType string
configName string
configPath string
}
func NewSimpleViper(config interface{}, configType string, configName string, configPath string) *SimpleViper {
return &SimpleViper{config: config, configType: configType, configName: configName, configPath: configPath}
}
func (t *SimpleViper) Apply() {
v := viper.New()
v.SetConfigFile(fmt.Sprintf("%s/%s.yaml", t.configPath, t.configName))
v.SetConfigType(t.configType)
err := v.ReadInConfig()
if err != nil {
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
if err := v.Unmarshal(t.config); err != nil {
panic(fmt.Errorf("Fatal Unmarshal error config file: %s \n", err))
}
}

8
test/start_test.go Normal file
View File

@ -0,0 +1,8 @@
package test
import (
"testing"
)
func TestStart(t *testing.T) {
}

100
util/convert.go Normal file
View File

@ -0,0 +1,100 @@
package util
import (
"math"
"reflect"
"strconv"
"strings"
"unsafe"
)
// 字符串转Int
// intStr数字的字符串
func String2Int(intStr string) (intNum int) {
intNum, _ = strconv.Atoi(intStr)
return
}
// 字符串转Int64
// intStr数字的字符串
func String2Int64(intStr string) (int64Num int64) {
intNum, _ := strconv.Atoi(intStr)
int64Num = int64(intNum)
return
}
// 字符串转Float64
// floatStr小数点数字的字符串
func String2Float64(floatStr string) (floatNum float64) {
floatNum, _ = strconv.ParseFloat(floatStr, 64)
return
}
// 字符串转Float32
// floatStr小数点数字的字符串
func String2Float32(floatStr string) (floatNum float32) {
floatNum64, _ := strconv.ParseFloat(floatStr, 32)
floatNum = float32(floatNum64)
return
}
// Int转字符串
// intNum数字字符串
func Int2String(intNum int) (intStr string) {
intStr = strconv.Itoa(intNum)
return
}
// Int64转字符串
// intNum数字字符串
func Int642String(intNum int64) (int64Str string) {
//10, 代表10进制
int64Str = strconv.FormatInt(intNum, 10)
return
}
// Float64转字符串
// floatNumfloat64数字
// prec精度位数不传则默认float数字精度
func Float64ToString(floatNum float64, prec ...int) (floatStr string) {
if len(prec) > 0 {
floatStr = strconv.FormatFloat(floatNum, 'f', prec[0], 64)
return
}
floatStr = strconv.FormatFloat(floatNum, 'f', -1, 64)
return
}
// Float32转字符串
// floatNumfloat32数字
// prec精度位数不传则默认float数字精度
func Float32ToString(floatNum float32, prec ...int) (floatStr string) {
if len(prec) > 0 {
floatStr = strconv.FormatFloat(float64(floatNum), 'f', prec[0], 32)
return
}
floatStr = strconv.FormatFloat(float64(floatNum), 'f', -1, 32)
return
}
// 二进制转10进制
func BinaryToDecimal(bit string) (num int) {
fields := strings.Split(bit, "")
lens := len(fields)
var tempF float64 = 0
for i := 0; i < lens; i++ {
floatNum := String2Float64(fields[i])
tempF += floatNum * math.Pow(2, float64(lens-i-1))
}
num = int(tempF)
return
}
// BytesToString 0 拷贝转换 slice byte 为 string
func BytesToString(b []byte) (s string) {
_bptr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
_sptr := (*reflect.StringHeader)(unsafe.Pointer(&s))
_sptr.Data = _bptr.Data
_sptr.Len = _bptr.Len
return s
}

12
util/md5.go Normal file
View File

@ -0,0 +1,12 @@
package util
import (
"crypto/md5"
"encoding/hex"
)
func EncodeMD5(value string) string {
m := md5.New()
m.Write([]byte(value))
return hex.EncodeToString(m.Sum(nil))
}

36
util/password/password.go Normal file
View File

@ -0,0 +1,36 @@
package password
import (
"crypto/md5"
"errors"
"golang.org/x/crypto/bcrypt"
)
func Encode(userPassword string) (string, error) {
md5Password := md5.Sum([]byte(userPassword))
encode, err := generatePassword(string(md5Password[:]))
if err != nil {
return "", errors.New("密码加密失败")
} else {
return string(encode), nil
}
}
func ValidateCode(userPassword string, hashed string) (isOK bool, err error) {
md5Password := md5.Sum([]byte(userPassword))
isOk, err := validatePassword(string(md5Password[:]), hashed)
return isOk, err
}
//generatePassword 给密码就行加密操作
func generatePassword(userPassword string) ([]byte, error) {
return bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost)
}
//validatePassword 密码比对
func validatePassword(userPassword string, hashed string) (isOK bool, err error) {
if err = bcrypt.CompareHashAndPassword([]byte(hashed), []byte(userPassword)); err != nil {
return false, errors.New("密码错误!")
}
return true, nil
}

42
util/random.go Normal file
View File

@ -0,0 +1,42 @@
package util
import (
"math/rand"
"time"
)
// 随机生成字符串
func RandomString(l int) string {
str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
bytes := []byte(str)
var result []byte = make([]byte, 0, l)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return BytesToString(result)
}
// 随机生成纯字符串
func RandomPureString(l int) string {
str := "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
bytes := []byte(str)
var result []byte = make([]byte, 0, l)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return BytesToString(result)
}
// 随机生成数字字符串
func RandomNumber(l int) string {
str := "0123456789"
bytes := []byte(str)
var result []byte
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return BytesToString(result)
}

104
util/string.go Normal file
View File

@ -0,0 +1,104 @@
package util
import (
"strconv"
"strings"
"unicode"
)
//判断是否是数字字符串
func IsDigit(str string) bool {
for _, x := range []rune(str) {
if !unicode.IsDigit(x) {
return false
}
}
return true
}
func Atoi(i string) int {
if i == "" {
return 0
}
j, err := strconv.Atoi(i)
if err != nil {
return 0
} else {
return j
}
}
func StringToInt(s interface{}) int {
switch i := s.(type) {
case string:
return Atoi(i)
case float32:
return int(i)
case float64:
return int(i)
case int:
return i
case uint:
return int(i)
}
return 0
}
/**
* 驼峰转蛇形 snake string
* @description XxYy to xx_yy , XxYY to xx_y_y
* @date 2020/7/30
* @param s 需要转换的字符串
* @return string
**/
func SnakeString(s string) string {
data := make([]byte, 0, len(s)*2)
j := false
num := len(s)
for i := 0; i < num; i++ {
d := s[i]
// or通过ASCII码进行大小写的转化
// 65-90A-Z97-122a-z
//判断如果字母为大写的A-Z就在前面拼接一个_
if i > 0 && d >= 'A' && d <= 'Z' && j {
data = append(data, '_')
}
if d != '_' {
j = true
}
data = append(data, d)
}
//ToLower把大写字母统一转小写
return strings.ToLower(string(data[:]))
}
/**
* 蛇形转驼峰
* @description xx_yy to XxYx xx_y_y to XxYY
* @date 2020/7/30
* @param s要转换的字符串
* @return string
**/
func CamelString(s string) string {
data := make([]byte, 0, len(s))
j := false
k := false
num := len(s) - 1
for i := 0; i <= num; i++ {
d := s[i]
if k == false && d >= 'A' && d <= 'Z' {
k = true
}
if d >= 'a' && d <= 'z' && (j || k == false) {
d = d - 32
j = false
k = true
}
if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
j = true
continue
}
data = append(data, d)
}
return string(data[:])
}

13
util/validator.go Normal file
View File

@ -0,0 +1,13 @@
package util
import "regexp"
// 识别手机号码
func IsMobile(mobile string) bool {
result, _ := regexp.MatchString(`^(1[0-9][0-9]\d{4,8})$`, mobile)
if result {
return true
} else {
return false
}
}