parent
8f83981e08
commit
6e30eb041d
@ -0,0 +1,6 @@
|
|||||||
|
/.idea/
|
||||||
|
.idea/
|
||||||
|
.idea
|
||||||
|
/storage/logs/*
|
||||||
|
/storage/uploaded/*
|
||||||
|
/public/storage
|
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 张奇峰
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -0,0 +1,25 @@
|
|||||||
|
package destroy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"goskeleton/app/core/event_manage"
|
||||||
|
"goskeleton/app/global/consts"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 用于系统信号的监听
|
||||||
|
go func() {
|
||||||
|
c := make(chan os.Signal)
|
||||||
|
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM) // 监听可能的退出信号
|
||||||
|
received := <-c //接收信号管道中的值
|
||||||
|
variable.ZapLog.Warn(consts.ProcessKilled, zap.String("信号值", received.String()))
|
||||||
|
(event_manage.CreateEventManageFactory()).FuzzyCall(variable.EventDestroyPrefix)
|
||||||
|
close(c)
|
||||||
|
os.Exit(1)
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"goskeleton/app/global/consts"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
"goskeleton/app/service/upload_file"
|
||||||
|
"goskeleton/app/utils/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Upload struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件上传是一个独立模块,给任何业务返回文件上传后的存储路径即可。
|
||||||
|
// 开始上传
|
||||||
|
func (u *Upload) StartUpload(context *gin.Context) {
|
||||||
|
savePath := variable.BasePath + variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath")
|
||||||
|
if r, finnalSavePath := upload_file.Upload(context, savePath); r == true {
|
||||||
|
response.Success(context, consts.CurdStatusOkMsg, finnalSavePath)
|
||||||
|
} else {
|
||||||
|
response.Fail(context, consts.FilesUploadFailCode, consts.FilesUploadFailMsg, "")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package cors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 允许跨域
|
||||||
|
func Next() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
method := c.Request.Method
|
||||||
|
c.Header("Access-Control-Allow-Origin", "*")
|
||||||
|
c.Header("Access-Control-Allow-Headers", "Access-Control-Allow-Headers,Authorization,User-Agent, Keep-Alive, Content-Type, X-Requested-With,X-CSRF-Token,AccessToken,Token")
|
||||||
|
c.Header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, OPTIONS")
|
||||||
|
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
|
||||||
|
c.Header("Access-Control-Allow-Credentials", "true")
|
||||||
|
|
||||||
|
// 放行所有OPTIONS方法
|
||||||
|
if method == "OPTIONS" {
|
||||||
|
c.AbortWithStatus(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package my_jwt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
"goskeleton/app/global/my_errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 使用工厂创建一个 JWT 结构体
|
||||||
|
func CreateMyJWT(signKey string) *JwtSign {
|
||||||
|
if len(signKey) <= 0 {
|
||||||
|
signKey = "goskeleton"
|
||||||
|
}
|
||||||
|
return &JwtSign{
|
||||||
|
[]byte(signKey),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个 JWT验签 结构体
|
||||||
|
type JwtSign struct {
|
||||||
|
SigningKey []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateToken 生成一个token
|
||||||
|
func (j *JwtSign) CreateToken(claims CustomClaims) (string, error) {
|
||||||
|
// 生成jwt格式的header、claims 部分
|
||||||
|
tokenPartA := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
// 继续添加秘钥值,生成最后一部分
|
||||||
|
return tokenPartA.SignedString(j.SigningKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析Token
|
||||||
|
func (j *JwtSign) ParseToken(tokenString string) (*CustomClaims, error) {
|
||||||
|
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return j.SigningKey, nil
|
||||||
|
})
|
||||||
|
if token == nil {
|
||||||
|
return nil, errors.New(my_errors.ErrorsTokenInvalid)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if ve, ok := err.(*jwt.ValidationError); ok {
|
||||||
|
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
|
||||||
|
return nil, errors.New(my_errors.ErrorsTokenMalFormed)
|
||||||
|
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
|
||||||
|
return nil, errors.New(my_errors.ErrorsTokenNotActiveYet)
|
||||||
|
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
|
||||||
|
// 如果 TokenExpired ,只是过期(格式都正确),我们认为他是有效的,接下可以允许刷新操作
|
||||||
|
token.Valid = true
|
||||||
|
goto labelHere
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(my_errors.ErrorsTokenInvalid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
labelHere:
|
||||||
|
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
|
||||||
|
return claims, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(my_errors.ErrorsTokenInvalid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新token
|
||||||
|
func (j *JwtSign) RefreshToken(tokenString string, extraAddSeconds int64) (string, error) {
|
||||||
|
|
||||||
|
if CustomClaims, err := j.ParseToken(tokenString); err == nil {
|
||||||
|
CustomClaims.ExpiresAt = time.Now().Unix() + extraAddSeconds
|
||||||
|
return j.CreateToken(*CustomClaims)
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package data_type
|
||||||
|
|
||||||
|
type Page struct {
|
||||||
|
Page float64 `form:"page" json:"page" binding:"min=1"` // 必填,页面值>=1
|
||||||
|
Limit float64 `form:"limit" json:"limit" binding:"min=1"` // 必填,每页条数值>=1
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package register_validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"goskeleton/app/core/container"
|
||||||
|
"goskeleton/app/global/consts"
|
||||||
|
"goskeleton/app/http/validator/api/home"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 各个业务模块验证器必须进行注册(初始化),程序启动时会自动加载到容器
|
||||||
|
func ApiRegisterValidator() {
|
||||||
|
//创建容器
|
||||||
|
containers := container.CreateContainersFactory()
|
||||||
|
|
||||||
|
// key 按照前缀+模块+验证动作 格式,将各个模块验证注册在容器
|
||||||
|
var key string
|
||||||
|
|
||||||
|
// 注册门户类表单参数验证器
|
||||||
|
key = consts.ValidatorPrefix + "HomeNews"
|
||||||
|
containers.Set(key, home.News{})
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package factory
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"goskeleton/app/core/container"
|
||||||
|
"goskeleton/app/global/my_errors"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
"goskeleton/app/http/validator/core/interf"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 表单参数验证器工厂(请勿修改)
|
||||||
|
func Create(key string) func(context *gin.Context) {
|
||||||
|
|
||||||
|
if value := container.CreateContainersFactory().Get(key); value != nil {
|
||||||
|
if val, isOk := value.(interf.ValidatorInterface); isOk {
|
||||||
|
return val.CheckParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variable.ZapLog.Error(my_errors.ErrorsValidatorNotExists + ", 验证器模块:" + key)
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package interf
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
// 验证器接口,每个验证器必须实现该接口,请勿修改
|
||||||
|
type ValidatorInterface interface {
|
||||||
|
CheckParams(context *gin.Context)
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package users
|
||||||
|
|
||||||
|
type BaseField struct {
|
||||||
|
UserName string `form:"user_name" json:"user_name" binding:"required,min=1"` // 必填、对于文本,表示它的长度>=1
|
||||||
|
Pass string `form:"pass" json:"pass" binding:"required,min=6,max=20"` // 密码为 必填,长度>=6
|
||||||
|
}
|
||||||
|
|
||||||
|
type Id struct {
|
||||||
|
Id float64 `form:"id" json:"id" binding:"required,min=1"`
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package curd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"goskeleton/app/model"
|
||||||
|
"goskeleton/app/utils/md5_encrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateUserCurdFactory() *UsersCurd {
|
||||||
|
return &UsersCurd{model.CreateUserFactory("")}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UsersCurd struct {
|
||||||
|
userModel *model.UsersModel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UsersCurd) Register(userName, pass, userIp string) bool {
|
||||||
|
pass = md5_encrypt.Base64Md5(pass) // 预先处理密码加密,然后存储在数据库
|
||||||
|
return u.userModel.Register(userName, pass, userIp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UsersCurd) Store(name string, pass string, realName string, phone string, remark string) bool {
|
||||||
|
|
||||||
|
pass = md5_encrypt.Base64Md5(pass) // 预先处理密码加密,然后存储在数据库
|
||||||
|
return u.userModel.Store(name, pass, realName, phone, remark)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UsersCurd) Update(id int, name string, pass string, realName string, phone string, remark string, clientIp string) bool {
|
||||||
|
//预先处理密码加密等操作,然后进行更新
|
||||||
|
pass = md5_encrypt.Base64Md5(pass) // 预先处理密码加密,然后存储在数据库
|
||||||
|
return u.userModel.Update(id, name, pass, realName, phone, remark, clientIp)
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package on_open_success
|
||||||
|
|
||||||
|
// ClientMoreParams 为客户端成功上线后设置更多的参数
|
||||||
|
// ws 客户端成功上线以后,可以通过客户端携带的唯一参数,在数据库查询更多的其他关键信息,设置在 *Client 结构体上
|
||||||
|
// 这样便于在后续获取在线客户端时快速获取其他关键信息,例如:进行消息广播时记录日志可能需要更多字段信息等
|
||||||
|
type ClientMoreParams struct {
|
||||||
|
UserParams1 string `json:"user_params_1"` // 字段名称以及类型由 开发者自己定义
|
||||||
|
UserParams2 string `json:"user_params_2"`
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package casbin_v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/casbin/casbin/v2"
|
||||||
|
"github.com/casbin/casbin/v2/model"
|
||||||
|
gormadapter "github.com/casbin/gorm-adapter/v3"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"goskeleton/app/global/my_errors"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//创建 casbin Enforcer(执行器)
|
||||||
|
func InitCasbinEnforcer() (*casbin.SyncedEnforcer, error) {
|
||||||
|
var tmpDbConn *gorm.DB
|
||||||
|
var Enforcer *casbin.SyncedEnforcer
|
||||||
|
switch strings.ToLower(variable.ConfigGormv2Yml.GetString("Gormv2.UseDbType")) {
|
||||||
|
case "mysql":
|
||||||
|
if variable.GormDbMysql == nil {
|
||||||
|
return nil, errors.New(my_errors.ErrorCasbinCanNotUseDbPtr)
|
||||||
|
}
|
||||||
|
tmpDbConn = variable.GormDbMysql
|
||||||
|
case "sqlserver", "mssql":
|
||||||
|
if variable.GormDbSqlserver == nil {
|
||||||
|
return nil, errors.New(my_errors.ErrorCasbinCanNotUseDbPtr)
|
||||||
|
}
|
||||||
|
tmpDbConn = variable.GormDbSqlserver
|
||||||
|
case "postgre", "postgresql", "postgres":
|
||||||
|
if variable.GormDbPostgreSql == nil {
|
||||||
|
return nil, errors.New(my_errors.ErrorCasbinCanNotUseDbPtr)
|
||||||
|
}
|
||||||
|
tmpDbConn = variable.GormDbPostgreSql
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := variable.ConfigYml.GetString("Casbin.TablePrefix")
|
||||||
|
tbName := variable.ConfigYml.GetString("Casbin.TableName")
|
||||||
|
|
||||||
|
a, err := gormadapter.NewAdapterByDBUseTableName(tmpDbConn, prefix, tbName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New(my_errors.ErrorCasbinCreateAdaptFail)
|
||||||
|
}
|
||||||
|
modelConfig := variable.ConfigYml.GetString("Casbin.ModelConfig")
|
||||||
|
|
||||||
|
if m, err := model.NewModelFromString(modelConfig); err != nil {
|
||||||
|
return nil, errors.New(my_errors.ErrorCasbinNewModelFromStringFail + err.Error())
|
||||||
|
} else {
|
||||||
|
if Enforcer, err = casbin.NewSyncedEnforcer(m, a); err != nil {
|
||||||
|
return nil, errors.New(my_errors.ErrorCasbinCreateEnforcerFail)
|
||||||
|
}
|
||||||
|
_ = Enforcer.LoadPolicy()
|
||||||
|
AutoLoadSeconds := variable.ConfigYml.GetDuration("Casbin.AutoLoadPolicySeconds")
|
||||||
|
Enforcer.StartAutoLoadPolicy(time.Second * AutoLoadSeconds)
|
||||||
|
return Enforcer, nil
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package cur_userinfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
"goskeleton/app/http/middleware/my_jwt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetCurrentUserId 获取当前用户的id
|
||||||
|
// @context 请求上下文
|
||||||
|
func GetCurrentUserId(context *gin.Context) (int64, bool) {
|
||||||
|
tokenKey := variable.ConfigYml.GetString("Token.BindContextKeyName")
|
||||||
|
currentUser, exist := context.MustGet(tokenKey).(my_jwt.CustomClaims)
|
||||||
|
return currentUser.UserId, exist
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package gorm_v2
|
||||||
|
|
||||||
|
// 数据库参数配置,结构体
|
||||||
|
// 用于解决复杂的业务场景连接到多台服务器部署的 mysql、sqlserver、postgresql 数据库
|
||||||
|
// 具体用法参见常用开发模块:多源数据库的操作
|
||||||
|
|
||||||
|
type ConfigParams struct {
|
||||||
|
Write ConfigParamsDetail
|
||||||
|
Read ConfigParamsDetail
|
||||||
|
}
|
||||||
|
type ConfigParamsDetail struct {
|
||||||
|
Host string
|
||||||
|
DataBase string
|
||||||
|
Port int
|
||||||
|
Prefix string
|
||||||
|
User string
|
||||||
|
Pass string
|
||||||
|
Charset string
|
||||||
|
}
|
@ -0,0 +1,174 @@
|
|||||||
|
package gorm_v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
gormLog "gorm.io/gorm/logger"
|
||||||
|
"gorm.io/gorm/utils"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 自定义日志格式, 对 gorm 自带日志进行拦截重写
|
||||||
|
func createCustomGormLog(sqlType string, options ...Options) gormLog.Interface {
|
||||||
|
var (
|
||||||
|
infoStr = "%s\n[info] "
|
||||||
|
warnStr = "%s\n[warn] "
|
||||||
|
errStr = "%s\n[error] "
|
||||||
|
traceStr = "%s\n[%.3fms] [rows:%v] %s"
|
||||||
|
traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s"
|
||||||
|
traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s"
|
||||||
|
)
|
||||||
|
logConf := gormLog.Config{
|
||||||
|
SlowThreshold: time.Second * variable.ConfigGormv2Yml.GetDuration("Gormv2."+sqlType+".SlowThreshold"),
|
||||||
|
LogLevel: gormLog.Warn,
|
||||||
|
Colorful: false,
|
||||||
|
}
|
||||||
|
log := &logger{
|
||||||
|
Writer: logOutPut{},
|
||||||
|
Config: logConf,
|
||||||
|
infoStr: infoStr,
|
||||||
|
warnStr: warnStr,
|
||||||
|
errStr: errStr,
|
||||||
|
traceStr: traceStr,
|
||||||
|
traceWarnStr: traceWarnStr,
|
||||||
|
traceErrStr: traceErrStr,
|
||||||
|
}
|
||||||
|
for _, val := range options {
|
||||||
|
val.apply(log)
|
||||||
|
}
|
||||||
|
return log
|
||||||
|
}
|
||||||
|
|
||||||
|
type logOutPut struct{}
|
||||||
|
|
||||||
|
func (l logOutPut) Printf(strFormat string, args ...interface{}) {
|
||||||
|
logRes := fmt.Sprintf(strFormat, args...)
|
||||||
|
logFlag := "gorm_v2 日志:"
|
||||||
|
detailFlag := "详情:"
|
||||||
|
if strings.HasPrefix(strFormat, "[info]") || strings.HasPrefix(strFormat, "[traceStr]") {
|
||||||
|
variable.ZapLog.Info(logFlag, zap.String(detailFlag, logRes))
|
||||||
|
} else if strings.HasPrefix(strFormat, "[error]") || strings.HasPrefix(strFormat, "[traceErr]") {
|
||||||
|
variable.ZapLog.Error(logFlag, zap.String(detailFlag, logRes))
|
||||||
|
} else if strings.HasPrefix(strFormat, "[warn]") || strings.HasPrefix(strFormat, "[traceWarn]") {
|
||||||
|
variable.ZapLog.Warn(logFlag, zap.String(detailFlag, logRes))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试从外部重写内部相关的格式化变量
|
||||||
|
type Options interface {
|
||||||
|
apply(*logger)
|
||||||
|
}
|
||||||
|
type OptionFunc func(log *logger)
|
||||||
|
|
||||||
|
func (f OptionFunc) apply(log *logger) {
|
||||||
|
f(log)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义 6 个函数修改内部变量
|
||||||
|
func SetInfoStrFormat(format string) Options {
|
||||||
|
return OptionFunc(func(log *logger) {
|
||||||
|
log.infoStr = format
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetWarnStrFormat(format string) Options {
|
||||||
|
return OptionFunc(func(log *logger) {
|
||||||
|
log.warnStr = format
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetErrStrFormat(format string) Options {
|
||||||
|
return OptionFunc(func(log *logger) {
|
||||||
|
log.errStr = format
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetTraceStrFormat(format string) Options {
|
||||||
|
return OptionFunc(func(log *logger) {
|
||||||
|
log.traceStr = format
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func SetTracWarnStrFormat(format string) Options {
|
||||||
|
return OptionFunc(func(log *logger) {
|
||||||
|
log.traceWarnStr = format
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetTracErrStrFormat(format string) Options {
|
||||||
|
return OptionFunc(func(log *logger) {
|
||||||
|
log.traceErrStr = format
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type logger struct {
|
||||||
|
gormLog.Writer
|
||||||
|
gormLog.Config
|
||||||
|
infoStr, warnStr, errStr string
|
||||||
|
traceStr, traceErrStr, traceWarnStr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogMode log mode
|
||||||
|
func (l *logger) LogMode(level gormLog.LogLevel) gormLog.Interface {
|
||||||
|
newlogger := *l
|
||||||
|
newlogger.LogLevel = level
|
||||||
|
return &newlogger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info print info
|
||||||
|
func (l logger) Info(_ context.Context, msg string, data ...interface{}) {
|
||||||
|
if l.LogLevel >= gormLog.Info {
|
||||||
|
l.Printf(l.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn print warn messages
|
||||||
|
func (l logger) Warn(_ context.Context, msg string, data ...interface{}) {
|
||||||
|
if l.LogLevel >= gormLog.Warn {
|
||||||
|
l.Printf(l.warnStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error print error messages
|
||||||
|
func (l logger) Error(_ context.Context, msg string, data ...interface{}) {
|
||||||
|
if l.LogLevel >= gormLog.Error {
|
||||||
|
l.Printf(l.errStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace print sql message
|
||||||
|
func (l logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
|
||||||
|
if l.LogLevel <= gormLog.Silent {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed := time.Since(begin)
|
||||||
|
switch {
|
||||||
|
case err != nil && l.LogLevel >= gormLog.Error && (!errors.Is(err, gormLog.ErrRecordNotFound) || !l.IgnoreRecordNotFoundError):
|
||||||
|
sql, rows := fc()
|
||||||
|
if rows == -1 {
|
||||||
|
l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-1", sql)
|
||||||
|
} else {
|
||||||
|
l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
|
||||||
|
}
|
||||||
|
case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= gormLog.Warn:
|
||||||
|
sql, rows := fc()
|
||||||
|
slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold)
|
||||||
|
if rows == -1 {
|
||||||
|
l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-1", sql)
|
||||||
|
} else {
|
||||||
|
l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
|
||||||
|
}
|
||||||
|
case l.LogLevel == gormLog.Info:
|
||||||
|
sql, rows := fc()
|
||||||
|
if rows == -1 {
|
||||||
|
l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-1", sql)
|
||||||
|
} else {
|
||||||
|
l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package error_record
|
||||||
|
|
||||||
|
import "goskeleton/app/global/variable"
|
||||||
|
|
||||||
|
// ErrorDeal 记录错误
|
||||||
|
func ErrorDeal(err error) error {
|
||||||
|
if err != nil {
|
||||||
|
variable.ZapLog.Error(err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package publish_subscribe
|
||||||
|
|
||||||
|
import (
|
||||||
|
amqp "github.com/rabbitmq/amqp091-go"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 等 go 泛型稳定以后,生产者和消费者初始化参数的设置,本段代码就可以继续精简
|
||||||
|
// 目前 apply(*producer) 的参数只能固定为生产者或者消费者其中之一的具体类型
|
||||||
|
|
||||||
|
// 1.生产者初始化参数定义
|
||||||
|
|
||||||
|
// OptionsProd 定义动态设置参数接口
|
||||||
|
type OptionsProd interface {
|
||||||
|
apply(*producer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionFunc 以函数形式实现上面的接口
|
||||||
|
type OptionFunc func(*producer)
|
||||||
|
|
||||||
|
func (f OptionFunc) apply(prod *producer) {
|
||||||
|
f(prod)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProdMsgDelayParams 开发者设置生产者初始化时的参数
|
||||||
|
func SetProdMsgDelayParams(enableMsgDelayPlugin bool) OptionsProd {
|
||||||
|
return OptionFunc(func(p *producer) {
|
||||||
|
p.enableDelayMsgPlugin = enableMsgDelayPlugin
|
||||||
|
p.exchangeType = "x-delayed-message"
|
||||||
|
p.args = amqp.Table{
|
||||||
|
"x-delayed-type": "fanout",
|
||||||
|
}
|
||||||
|
p.exchangeName = variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.DelayedExchangeName")
|
||||||
|
// 延迟消息队列,交换机、消息全部设置为持久
|
||||||
|
p.durable = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.消费者端初始化参数定义
|
||||||
|
|
||||||
|
// OptionsConsumer 定义动态设置参数接口
|
||||||
|
type OptionsConsumer interface {
|
||||||
|
apply(*consumer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionsConsumerFunc 以函数形式实现上面的接口
|
||||||
|
type OptionsConsumerFunc func(*consumer)
|
||||||
|
|
||||||
|
func (f OptionsConsumerFunc) apply(cons *consumer) {
|
||||||
|
f(cons)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsMsgDelayParams 开发者设置消费者端初始化时的参数
|
||||||
|
func SetConsMsgDelayParams(enableDelayMsgPlugin bool) OptionsConsumer {
|
||||||
|
return OptionsConsumerFunc(func(c *consumer) {
|
||||||
|
c.enableDelayMsgPlugin = enableDelayMsgPlugin
|
||||||
|
c.exchangeType = "x-delayed-message"
|
||||||
|
c.exchangeName = variable.ConfigYml.GetString("RabbitMq.PublishSubscribe.DelayedExchangeName")
|
||||||
|
// 延迟消息队列,交换机、消息全部设置为持久
|
||||||
|
c.durable = true
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package routing
|
||||||
|
|
||||||
|
import (
|
||||||
|
amqp "github.com/rabbitmq/amqp091-go"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 等 go 泛型稳定以后,生产者和消费者初始化参数的设置,本段代码就可以继续精简
|
||||||
|
// 目前 apply(*producer) 的参数只能固定为生产者或者消费者其中之一的具体类型
|
||||||
|
|
||||||
|
// 1.生产者初始化参数定义
|
||||||
|
|
||||||
|
// OptionsProd 定义动态设置参数接口
|
||||||
|
type OptionsProd interface {
|
||||||
|
apply(*producer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionFunc 以函数形式实现上面的接口
|
||||||
|
type OptionFunc func(*producer)
|
||||||
|
|
||||||
|
func (f OptionFunc) apply(prod *producer) {
|
||||||
|
f(prod)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProdMsgDelayParams 开发者设置生产者初始化时的参数
|
||||||
|
func SetProdMsgDelayParams(enableMsgDelayPlugin bool) OptionsProd {
|
||||||
|
return OptionFunc(func(p *producer) {
|
||||||
|
p.enableDelayMsgPlugin = enableMsgDelayPlugin
|
||||||
|
p.exchangeType = "x-delayed-message"
|
||||||
|
p.args = amqp.Table{
|
||||||
|
"x-delayed-type": "direct",
|
||||||
|
}
|
||||||
|
p.exchangeName = variable.ConfigYml.GetString("RabbitMq.Routing.DelayedExchangeName")
|
||||||
|
// 延迟消息队列,交换机、消息全部设置为持久
|
||||||
|
p.durable = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.消费者端初始化参数定义
|
||||||
|
|
||||||
|
// OptionsConsumer 定义动态设置参数接口
|
||||||
|
type OptionsConsumer interface {
|
||||||
|
apply(*consumer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionsConsumerFunc 以函数形式实现上面的接口
|
||||||
|
type OptionsConsumerFunc func(*consumer)
|
||||||
|
|
||||||
|
func (f OptionsConsumerFunc) apply(cons *consumer) {
|
||||||
|
f(cons)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsMsgDelayParams 开发者设置消费者端初始化时的参数
|
||||||
|
func SetConsMsgDelayParams(enableDelayMsgPlugin bool) OptionsConsumer {
|
||||||
|
return OptionsConsumerFunc(func(c *consumer) {
|
||||||
|
c.enableDelayMsgPlugin = enableDelayMsgPlugin
|
||||||
|
c.exchangeType = "x-delayed-message"
|
||||||
|
c.exchangeName = variable.ConfigYml.GetString("RabbitMq.Routing.DelayedExchangeName")
|
||||||
|
// 延迟消息队列,交换机、消息全部设置为持久
|
||||||
|
c.durable = true
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package topics
|
||||||
|
|
||||||
|
import (
|
||||||
|
amqp "github.com/rabbitmq/amqp091-go"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 等 go 泛型稳定以后,生产者和消费者初始化参数的设置,本段代码就可以继续精简
|
||||||
|
// 目前 apply(*producer) 的参数只能固定为生产者或者消费者其中之一的具体类型
|
||||||
|
|
||||||
|
// 1.生产者初始化参数定义
|
||||||
|
|
||||||
|
// OptionsProd 定义动态设置参数接口
|
||||||
|
type OptionsProd interface {
|
||||||
|
apply(*producer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionFunc 以函数形式实现上面的接口
|
||||||
|
type OptionFunc func(*producer)
|
||||||
|
|
||||||
|
func (f OptionFunc) apply(prod *producer) {
|
||||||
|
f(prod)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProdMsgDelayParams 开发者设置生产者初始化时的参数
|
||||||
|
func SetProdMsgDelayParams(enableMsgDelayPlugin bool) OptionsProd {
|
||||||
|
return OptionFunc(func(p *producer) {
|
||||||
|
p.enableDelayMsgPlugin = enableMsgDelayPlugin
|
||||||
|
p.exchangeType = "x-delayed-message"
|
||||||
|
p.args = amqp.Table{
|
||||||
|
"x-delayed-type": "topic",
|
||||||
|
}
|
||||||
|
p.exchangeName = variable.ConfigYml.GetString("RabbitMq.Topics.DelayedExchangeName")
|
||||||
|
// 延迟消息队列,交换机、消息全部设置为持久
|
||||||
|
p.durable = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.消费者端初始化参数定义
|
||||||
|
|
||||||
|
// OptionsConsumer 定义动态设置参数接口
|
||||||
|
type OptionsConsumer interface {
|
||||||
|
apply(*consumer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionsConsumerFunc 以函数形式实现上面的接口
|
||||||
|
type OptionsConsumerFunc func(*consumer)
|
||||||
|
|
||||||
|
func (f OptionsConsumerFunc) apply(cons *consumer) {
|
||||||
|
f(cons)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsMsgDelayParams 开发者设置消费者端初始化时的参数
|
||||||
|
func SetConsMsgDelayParams(enableDelayMsgPlugin bool) OptionsConsumer {
|
||||||
|
return OptionsConsumerFunc(func(c *consumer) {
|
||||||
|
c.enableDelayMsgPlugin = enableDelayMsgPlugin
|
||||||
|
c.exchangeType = "x-delayed-message"
|
||||||
|
c.exchangeName = variable.ConfigYml.GetString("RabbitMq.Topics.DelayedExchangeName")
|
||||||
|
// 延迟消息队列,交换机、消息全部设置为持久
|
||||||
|
c.durable = true
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package snow_flake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"goskeleton/app/global/consts"
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
"goskeleton/app/utils/snow_flake/snowflake_interf"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 创建一个雪花算法生成器(生成工厂)
|
||||||
|
func CreateSnowflakeFactory() snowflake_interf.InterfaceSnowFlake {
|
||||||
|
return &snowflake{
|
||||||
|
timestamp: 0,
|
||||||
|
machineId: variable.ConfigYml.GetInt64("SnowFlake.SnowFlakeMachineId"),
|
||||||
|
sequence: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type snowflake struct {
|
||||||
|
sync.Mutex
|
||||||
|
timestamp int64
|
||||||
|
machineId int64
|
||||||
|
sequence int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成分布式ID
|
||||||
|
func (s *snowflake) GetId() int64 {
|
||||||
|
s.Lock()
|
||||||
|
defer func() {
|
||||||
|
s.Unlock()
|
||||||
|
}()
|
||||||
|
now := time.Now().UnixNano() / 1e6
|
||||||
|
if s.timestamp == now {
|
||||||
|
s.sequence = (s.sequence + 1) & consts.SequenceMask
|
||||||
|
if s.sequence == 0 {
|
||||||
|
for now <= s.timestamp {
|
||||||
|
now = time.Now().UnixNano() / 1e6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.sequence = 0
|
||||||
|
}
|
||||||
|
s.timestamp = now
|
||||||
|
r := (now-consts.StartTimeStamp)<<consts.TimestampShift | (s.machineId << consts.MachineIdShift) | (s.sequence)
|
||||||
|
return r
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package snowflake_interf
|
||||||
|
|
||||||
|
type InterfaceSnowFlake interface {
|
||||||
|
GetId() int64
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
type Hub struct {
|
||||||
|
//上线注册
|
||||||
|
Register chan *Client
|
||||||
|
//下线注销
|
||||||
|
UnRegister chan *Client
|
||||||
|
//所有在线客户端的内存地址
|
||||||
|
Clients map[*Client]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateHubFactory() *Hub {
|
||||||
|
return &Hub{
|
||||||
|
Register: make(chan *Client),
|
||||||
|
UnRegister: make(chan *Client),
|
||||||
|
Clients: make(map[*Client]bool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Hub) Run() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case client := <-h.Register:
|
||||||
|
h.Clients[client] = true
|
||||||
|
case client := <-h.UnRegister:
|
||||||
|
if _, ok := h.Clients[client]; ok {
|
||||||
|
_ = client.Conn.Close()
|
||||||
|
delete(h.Clients, client)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package ymlconfig_interf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type YmlConfigInterf interface {
|
||||||
|
ConfigFileChangeListen()
|
||||||
|
Clone(fileName string) YmlConfigInterf
|
||||||
|
Get(keyName string) interface{}
|
||||||
|
GetString(keyName string) string
|
||||||
|
GetBool(keyName string) bool
|
||||||
|
GetInt(keyName string) int
|
||||||
|
GetInt32(keyName string) int32
|
||||||
|
GetInt64(keyName string) int64
|
||||||
|
GetFloat64(keyName string) float64
|
||||||
|
GetDuration(keyName string) time.Duration
|
||||||
|
GetStringSlice(keyName string) []string
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
_ "goskeleton/bootstrap"
|
||||||
|
"goskeleton/routers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 这里可以存放门户类网站入口
|
||||||
|
func main() {
|
||||||
|
router := routers.InitApiRouter()
|
||||||
|
_ = router.Run(variable.ConfigYml.GetString("HttpServer.Api.Port"))
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "goskeleton/bootstrap"
|
||||||
|
cmd "goskeleton/command"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 开发非http接口类服务入口
|
||||||
|
func main() {
|
||||||
|
// 设置运行模式为 cli(console)
|
||||||
|
cmd.Execute()
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"goskeleton/app/global/variable"
|
||||||
|
_ "goskeleton/bootstrap"
|
||||||
|
"goskeleton/routers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 这里可以存放后端路由(例如后台管理系统)
|
||||||
|
func main() {
|
||||||
|
router := routers.InitWebRouter()
|
||||||
|
_ = router.Run(variable.ConfigYml.GetString("HttpServer.Web.Port"))
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package demo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 定义子命令
|
||||||
|
var subCmd = &cobra.Command{
|
||||||
|
Use: "subCmd",
|
||||||
|
Short: "subCmd 命令简要介绍",
|
||||||
|
Long: `命令使用详细介绍`,
|
||||||
|
Args: cobra.ExactArgs(1), // 限制非flag参数的个数 = 1 ,超过1个会报错
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Printf("%s\n", args[0])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册子命令
|
||||||
|
func init() {
|
||||||
|
Demo1.AddCommand(subCmd)
|
||||||
|
// 子命令仍然可以定义 flag 参数,相关语法参见 demo.go 文件
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"goskeleton/command/demo"
|
||||||
|
"goskeleton/command/demo_simple"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// cli 命令基于 https://github.com/spf13/cobra 封装
|
||||||
|
// RootCmd represents the base command when called without any subcommands
|
||||||
|
|
||||||
|
var RootCmd = &cobra.Command{
|
||||||
|
Use: "Cli",
|
||||||
|
Short: "A brief description of your application",
|
||||||
|
Long: `A longer description that spans multiple lines and likely contains
|
||||||
|
examples and usage of using your application. For example:
|
||||||
|
|
||||||
|
Cobra is a CLI library for Go that empowers applications.
|
||||||
|
This application is a tool to generate the needed files
|
||||||
|
to quickly create a Cobra application.`,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||||
|
// This is called by main.main(). It only needs to happen once to the RootCmd.
|
||||||
|
func Execute() {
|
||||||
|
if err := RootCmd.Execute(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
// 如果子命令是存在于子目录,那么就需要在入口统一添加;
|
||||||
|
// 如果和 root.go 同目录,则不需要像下一行一样添加
|
||||||
|
RootCmd.AddCommand(demo.Demo1)
|
||||||
|
RootCmd.AddCommand(demo_simple.DemoSimple)
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,297 @@
|
|||||||
|
--
|
||||||
|
-- PostgreSQL database dump
|
||||||
|
--
|
||||||
|
|
||||||
|
-- Dumped from database version 10.17
|
||||||
|
-- Dumped by pg_dump version 10.17
|
||||||
|
|
||||||
|
-- Started on 2021-08-04 12:22:01
|
||||||
|
|
||||||
|
SET statement_timeout = 0;
|
||||||
|
SET lock_timeout = 0;
|
||||||
|
SET idle_in_transaction_session_timeout = 0;
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
SET standard_conforming_strings = on;
|
||||||
|
SELECT pg_catalog.set_config('search_path', '', false);
|
||||||
|
SET check_function_bodies = false;
|
||||||
|
SET xmloption = content;
|
||||||
|
SET client_min_messages = warning;
|
||||||
|
SET row_security = off;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 5 (class 2615 OID 16570)
|
||||||
|
-- Name: web; Type: SCHEMA; Schema: -; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SCHEMA web;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER SCHEMA web OWNER TO postgres;
|
||||||
|
|
||||||
|
SET default_tablespace = '';
|
||||||
|
|
||||||
|
SET default_with_oids = false;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 200 (class 1259 OID 16609)
|
||||||
|
-- Name: tb_auth_casbin_rule; Type: TABLE; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE web.tb_auth_casbin_rule (
|
||||||
|
id integer NOT NULL,
|
||||||
|
ptype character varying(100) DEFAULT 'p'::character varying NOT NULL,
|
||||||
|
p0 character varying(100) DEFAULT ''::character varying NOT NULL,
|
||||||
|
p1 character varying(100) DEFAULT ''::character varying NOT NULL,
|
||||||
|
p2 character varying(100) DEFAULT ''::character varying NOT NULL,
|
||||||
|
p3 character varying(100) DEFAULT ''::character varying NOT NULL,
|
||||||
|
p4 character varying(100) DEFAULT ''::character varying NOT NULL,
|
||||||
|
p5 character varying(100) DEFAULT ''::character varying NOT NULL,
|
||||||
|
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
v0 character varying(100),
|
||||||
|
v1 character varying(100),
|
||||||
|
v2 character varying(100),
|
||||||
|
v3 character varying(100),
|
||||||
|
v4 character varying(100),
|
||||||
|
v5 character varying(100)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE web.tb_auth_casbin_rule OWNER TO postgres;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 199 (class 1259 OID 16607)
|
||||||
|
-- Name: tb_auth_casbin_rule_id_seq; Type: SEQUENCE; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE web.tb_auth_casbin_rule_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE web.tb_auth_casbin_rule_id_seq OWNER TO postgres;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2856 (class 0 OID 0)
|
||||||
|
-- Dependencies: 199
|
||||||
|
-- Name: tb_auth_casbin_rule_id_seq; Type: SEQUENCE OWNED BY; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE web.tb_auth_casbin_rule_id_seq OWNED BY web.tb_auth_casbin_rule.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 202 (class 1259 OID 16629)
|
||||||
|
-- Name: tb_oauth_access_tokens; Type: TABLE; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE web.tb_oauth_access_tokens (
|
||||||
|
id integer NOT NULL,
|
||||||
|
fr_user_id integer DEFAULT 0,
|
||||||
|
client_id integer DEFAULT 1,
|
||||||
|
token character varying(500) DEFAULT ''::character varying NOT NULL,
|
||||||
|
action_name character varying(100) DEFAULT ''::character varying NOT NULL,
|
||||||
|
scopes character varying(100) DEFAULT '*'::character varying NOT NULL,
|
||||||
|
revoked smallint DEFAULT 0 NOT NULL,
|
||||||
|
client_ip character varying(20) DEFAULT ''::character varying,
|
||||||
|
expires_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE web.tb_oauth_access_tokens OWNER TO postgres;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 201 (class 1259 OID 16627)
|
||||||
|
-- Name: tb_oauth_access_tokens_id_seq; Type: SEQUENCE; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE web.tb_oauth_access_tokens_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE web.tb_oauth_access_tokens_id_seq OWNER TO postgres;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2857 (class 0 OID 0)
|
||||||
|
-- Dependencies: 201
|
||||||
|
-- Name: tb_oauth_access_tokens_id_seq; Type: SEQUENCE OWNED BY; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE web.tb_oauth_access_tokens_id_seq OWNED BY web.tb_oauth_access_tokens.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 198 (class 1259 OID 16591)
|
||||||
|
-- Name: tb_users; Type: TABLE; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE web.tb_users (
|
||||||
|
id integer NOT NULL,
|
||||||
|
user_name character varying(30) DEFAULT ''::character varying NOT NULL,
|
||||||
|
pass character varying(128) DEFAULT ''::character varying NOT NULL,
|
||||||
|
real_name character varying(30) DEFAULT ''::character varying,
|
||||||
|
phone character(11) DEFAULT ''::bpchar,
|
||||||
|
status smallint DEFAULT 1,
|
||||||
|
remark character varying(120) DEFAULT ''::character varying,
|
||||||
|
last_login_time timestamp without time zone,
|
||||||
|
last_login_ip character varying(20) DEFAULT ''::character varying,
|
||||||
|
login_times integer DEFAULT 0,
|
||||||
|
created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE web.tb_users OWNER TO postgres;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 197 (class 1259 OID 16589)
|
||||||
|
-- Name: tb_users_id_seq; Type: SEQUENCE; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE web.tb_users_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE web.tb_users_id_seq OWNER TO postgres;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2858 (class 0 OID 0)
|
||||||
|
-- Dependencies: 197
|
||||||
|
-- Name: tb_users_id_seq; Type: SEQUENCE OWNED BY; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE web.tb_users_id_seq OWNED BY web.tb_users.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2696 (class 2604 OID 16612)
|
||||||
|
-- Name: tb_auth_casbin_rule id; Type: DEFAULT; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY web.tb_auth_casbin_rule ALTER COLUMN id SET DEFAULT nextval('web.tb_auth_casbin_rule_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2708 (class 2604 OID 16632)
|
||||||
|
-- Name: tb_oauth_access_tokens id; Type: DEFAULT; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY web.tb_oauth_access_tokens ALTER COLUMN id SET DEFAULT nextval('web.tb_oauth_access_tokens_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2685 (class 2604 OID 16594)
|
||||||
|
-- Name: tb_users id; Type: DEFAULT; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY web.tb_users ALTER COLUMN id SET DEFAULT nextval('web.tb_users_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2848 (class 0 OID 16609)
|
||||||
|
-- Dependencies: 200
|
||||||
|
-- Data for Name: tb_auth_casbin_rule; Type: TABLE DATA; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2850 (class 0 OID 16629)
|
||||||
|
-- Dependencies: 202
|
||||||
|
-- Data for Name: tb_oauth_access_tokens; Type: TABLE DATA; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2846 (class 0 OID 16591)
|
||||||
|
-- Dependencies: 198
|
||||||
|
-- Data for Name: tb_users; Type: TABLE DATA; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2859 (class 0 OID 0)
|
||||||
|
-- Dependencies: 199
|
||||||
|
-- Name: tb_auth_casbin_rule_id_seq; Type: SEQUENCE SET; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT pg_catalog.setval('web.tb_auth_casbin_rule_id_seq', 1, false);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2860 (class 0 OID 0)
|
||||||
|
-- Dependencies: 201
|
||||||
|
-- Name: tb_oauth_access_tokens_id_seq; Type: SEQUENCE SET; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT pg_catalog.setval('web.tb_oauth_access_tokens_id_seq', 2, true);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2861 (class 0 OID 0)
|
||||||
|
-- Dependencies: 197
|
||||||
|
-- Name: tb_users_id_seq; Type: SEQUENCE SET; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT pg_catalog.setval('web.tb_users_id_seq', 8, true);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2721 (class 2606 OID 16626)
|
||||||
|
-- Name: tb_auth_casbin_rule tb_auth_casbin_rule_pkey; Type: CONSTRAINT; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY web.tb_auth_casbin_rule
|
||||||
|
ADD CONSTRAINT tb_auth_casbin_rule_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2723 (class 2606 OID 16647)
|
||||||
|
-- Name: tb_oauth_access_tokens tb_oauth_access_tokens_pkey; Type: CONSTRAINT; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY web.tb_oauth_access_tokens
|
||||||
|
ADD CONSTRAINT tb_oauth_access_tokens_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2718 (class 2606 OID 16606)
|
||||||
|
-- Name: tb_users tb_users_pkey; Type: CONSTRAINT; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY web.tb_users
|
||||||
|
ADD CONSTRAINT tb_users_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- TOC entry 2719 (class 1259 OID 16662)
|
||||||
|
-- Name: idx_web_tb_auth_casbin_rule; Type: INDEX; Schema: web; Owner: postgres
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX idx_web_tb_auth_casbin_rule ON web.tb_auth_casbin_rule USING btree (ptype, v0, v1, v2, v3, v4, v5);
|
||||||
|
|
||||||
|
|
||||||
|
-- Completed on 2021-08-04 12:22:02
|
||||||
|
|
||||||
|
--
|
||||||
|
-- PostgreSQL database dump complete
|
||||||
|
--
|
||||||
|
|
@ -0,0 +1,52 @@
|
|||||||
|
-- 创建数据库,例如: db_goskeleton
|
||||||
|
USE [master]
|
||||||
|
IF NOT EXISTS(SELECT 1 FROM sysdatabases WHERE NAME=N'db_goskeleton')
|
||||||
|
BEGIN
|
||||||
|
CREATE DATABASE db_goskeleton
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
use db_goskeleton ;
|
||||||
|
-- 创建用户表
|
||||||
|
CREATE TABLE [dbo].[tb_users](
|
||||||
|
[id] [int] IDENTITY(1,1) NOT NULL,
|
||||||
|
[user_name] [nvarchar](50) NOT NULL ,
|
||||||
|
[pass] [varchar](128) NOT NULL ,
|
||||||
|
[real_name] [nvarchar](30) DEFAULT (''),
|
||||||
|
[phone] [char](11) DEFAULT (''),
|
||||||
|
[status] [tinyint] DEFAULT (1),
|
||||||
|
[remark] [nvarchar](120) DEFAULT (''),
|
||||||
|
[last_login_time] [datetime] DEFAULT (getdate()),
|
||||||
|
[last_login_ip] [varchar](128) DEFAULT (''),
|
||||||
|
[login_times] [int] DEFAULT ((0)),
|
||||||
|
[created_at] [datetime] DEFAULT (getdate()),
|
||||||
|
[updated_at] [datetime] DEFAULT (getdate())
|
||||||
|
);
|
||||||
|
-- -- 创建token表
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[tb_oauth_access_tokens](
|
||||||
|
[id] [int] IDENTITY(1,1) NOT NULL,
|
||||||
|
[fr_user_id] [int] DEFAULT ((0)),
|
||||||
|
[client_id] [int] DEFAULT ((0)),
|
||||||
|
[token] [varchar](500) DEFAULT (''),
|
||||||
|
[action_name] [varchar](50) DEFAULT ('login') ,
|
||||||
|
[scopes] [varchar](128) DEFAULT ('*') ,
|
||||||
|
[revoked] [tinyint] DEFAULT ((0)),
|
||||||
|
[client_ip] [varchar](128) DEFAULT (''),
|
||||||
|
[created_at] [datetime] DEFAULT (getdate()) ,
|
||||||
|
[updated_at] [datetime] DEFAULT (getdate()) ,
|
||||||
|
[expires_at] [datetime] DEFAULT (getdate()) ,
|
||||||
|
[remark] [nchar](120) DEFAULT ('')
|
||||||
|
) ;
|
||||||
|
|
||||||
|
-- -- 创建 tb_casbin 接口鉴权表
|
||||||
|
CREATE TABLE [dbo].[tb_auth_casbin_rule](
|
||||||
|
[id] [int] IDENTITY(1,1) NOT NULL,
|
||||||
|
[ptype] [varchar](100) DEFAULT ('p'),
|
||||||
|
[v0] [varchar](100) DEFAULT (''),
|
||||||
|
[v1] [varchar](100) DEFAULT (''),
|
||||||
|
[v2] [varchar](100) DEFAULT (''),
|
||||||
|
[v3] [varchar](100) DEFAULT (''),
|
||||||
|
[v4] [varchar](100) DEFAULT (''),
|
||||||
|
[v5] [varchar](100) DEFAULT (''),
|
||||||
|
[remark] [nchar](120) DEFAULT ('')
|
||||||
|
) ;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue