This commit is contained in:
oneao committed 2025-11-11 16:35:32 +08:00
1 parent 098a061308
commit 994321d049
40 files changed
+1401 -359

No files matched your search

@@ -1,14 +1,15 @@
package auth
import (
"base-go-v2/internal/api/money"
"base-go-v2/internal/db"
response "base-go-v2/internal/reponse"
"base-go-v2/internal/router"
"base-go-v2/internal/routinex"
"base-go-v2/internal/utils/idgen"
"base-go-v2/internal/utils/jwtx"
"base-go-v2/internal/utils/mapx"
"base-go-v2/internal/utils/timex"
"base-go-v2/internal/utils/uid"
)
func InitAuthRouter(r *router.Router) {
@@ -85,7 +86,7 @@ func loginDefault(c *router.Context) error {
Send()
}
userId := user.GetInt("id")
userId := user.GetInt64("id")
// 创建 Access Token 和 Refresh Token
accessToken, err := jwtx.CreateAccessToken(userId)
@@ -99,8 +100,8 @@ func loginDefault(c *router.Context) error {
// 返回数据
respData := mapx.New().
SetIntToString("userId", userId).
SetKV(
"userId", userId,
"username", user.GetString("username"),
"seqNo", user.GetInt("seq_no"),
"gender", user.GetInt("gender"),
@@ -140,9 +141,10 @@ func registerDefault(c *router.Context) error {
return response.Fail(c).Message("该账号已被注册").Send()
}
userId := idgen.NextId()
// 构造新用户数据
newUserData := mapx.New().SetKV(
"id", uid.NextID(),
"id", userId,
"account", account,
"password", password,
)
@@ -150,10 +152,16 @@ func registerDefault(c *router.Context) error {
// 插入新用户
insertedRows, err := db.InsertOne("user_info", newUserData)
if err != nil {
return response.Fail(c).Message("注册失败").Send()
}
if insertedRows != 1 {
return response.Fail(c).Message("注册失败").Send()
}
err = money.InitDefaultCategories(userId)
if err != nil {
return c.AddError(err)
}
return response.Success(c).Message("注册成功").Send()
}
@@ -21,7 +21,7 @@ func AuthMiddleware() router.HandlerFunc {
// Access Token 有效
if tokenVerify.IsValid {
c.Set("user_id", tokenVerify.Claims.UserID)
c.SetUserID(tokenVerify.Claims.UserID)
return nil
}
@@ -4,7 +4,7 @@ import (
"base-go-v2/internal/logx"
"base-go-v2/internal/router"
"base-go-v2/internal/routinex"
"base-go-v2/internal/utils/uid"
"base-go-v2/internal/utils/idgen"
"time"
)
@@ -20,7 +20,7 @@ func LoggerMiddleware() router.HandlerFunc {
start := time.Now() // 记录开始时间
// 生成 trackID 并存入 routinex
trackID := uid.NextID()
trackID := idgen.NextId()
routinex.Set(logx.TrackID, trackID)
// 执行业务逻辑,并捕获错误
@@ -0,0 +1,79 @@
package money
import (
"base-go-v2/internal/db"
response "base-go-v2/internal/reponse"
"base-go-v2/internal/router"
"base-go-v2/internal/utils/idgen"
"base-go-v2/internal/utils/mapx"
"fmt"
)
func InitMoneyRouter(r *router.Router) {
group := r.Group("money")
group.GET("/category", getUserCategory)
//group := r.Group("auth")
}
// InitDefaultCategories 初始化系统默认分类到用户分类表
func InitDefaultCategories(userID int64) error {
fmt.Println("进入 InitDefaultCategories ===")
// 1. 查询系统分类表
sysCategories, err := db.FindAll("money_sys_category", "sort_number")
if err != nil {
return err
}
fmt.Printf("系统分类数量: %d\n", len(sysCategories))
// 2. 构建批量插入数据
userCategories := make([]mapx.M, 0, len(sysCategories))
for i, row := range sysCategories {
m := mapx.New().SetKV(
"id", idgen.NextId(),
"user_id", userID,
"name", row.GetString("name"),
"icon", row.GetString("icon"),
"type", row.GetInt("type"),
"sort_number", row.GetInt("sort_number"),
)
fmt.Printf("用户分类 %d: %+v\n", i+1, m)
userCategories = append(userCategories, m)
}
// 3. 批量插入到用户分类表
if _, err := db.InsertBatch("money_user_category", userCategories); err != nil {
return err
}
fmt.Println("初始化用户分类成功!")
return nil
}
func getUserCategory(c *router.Context) error {
userId := c.GetUserID()
// 查询当前用户的分类
userCategories, err := db.Find("money_user_category", mapx.New().Set("user_id", userId), "sort_number ASC")
if err != nil {
return c.AddError(err)
}
// 按 type 分组
result := map[string][]mapx.M{
"income": {},
"expense": {},
}
for _, cat := range userCategories {
switch cat.GetInt("type") {
case 0:
result["income"] = append(result["income"], cat)
case 1:
result["expense"] = append(result["expense"], cat)
}
}
return response.Success(c).Data(result).Send()
}
@@ -3,6 +3,7 @@ package api
import (
"base-go-v2/internal/api/auth"
"base-go-v2/internal/api/middleware"
"base-go-v2/internal/api/money"
"base-go-v2/internal/config"
"base-go-v2/internal/router"
)
@@ -17,5 +18,7 @@ func InitAppRouter() *router.Router {
r.Use(middleware.AuthMiddleware()).ExcludePaths("/auth/**")
auth.InitAuthRouter(r)
money.InitMoneyRouter(r)
return r
}
@@ -3,12 +3,14 @@ package db
import (
"fmt"
"strings"
"base-go-v2/internal/utils/mapx"
)
// ---------------- 内部辅助函数 ----------------
// buildInsertSQL 构建插入 SQL 和参数
func buildInsertSQL(table string, data map[string]interface{}, returning string) (string, []interface{}) {
func buildInsertSQL(table string, data mapx.M, returning string) (string, []interface{}) {
columns := make([]string, 0, len(data))
placeholders := make([]string, 0, len(data))
values := make([]interface{}, 0, len(data))
@@ -34,7 +36,7 @@ func buildInsertSQL(table string, data map[string]interface{}, returning string)
// ---------------- 公共方法 ----------------
// InsertOne 插入单条记录,返回受影响行数
func InsertOne(table string, data map[string]interface{}) (int64, error) {
func InsertOne(table string, data mapx.M) (int64, error) {
tx, err := DB.Beginx()
if err != nil {
return 0, err
@@ -55,7 +57,7 @@ func InsertOne(table string, data map[string]interface{}) (int64, error) {
}
// InsertBatch 批量插入,返回总受影响行数
func InsertBatch(table string, dataList []map[string]interface{}) (int64, error) {
func InsertBatch(table string, dataList []mapx.M) (int64, error) {
if len(dataList) == 0 {
return 0, nil
}
@@ -90,7 +92,7 @@ func InsertBatch(table string, dataList []map[string]interface{}) (int64, error)
}
// InsertOneReturnPK 插入单条记录,返回主键值
func InsertOneReturnPK(table string, pkColumn string, data map[string]interface{}) (int64, error) {
func InsertOneReturnPK(table string, pkColumn string, data mapx.M) (int64, error) {
tx, err := DB.Beginx()
if err != nil {
return 0, err
@@ -113,7 +115,7 @@ func InsertOneReturnPK(table string, pkColumn string, data map[string]interface{
}
// InsertBatchReturnPK 批量插入多条记录,返回主键数组
func InsertBatchReturnPK(table string, pkColumn string, dataList []map[string]interface{}) ([]int64, error) {
func InsertBatchReturnPK(table string, pkColumn string, dataList []mapx.M) ([]int64, error) {
if len(dataList) == 0 {
return nil, nil
}
@@ -3,8 +3,8 @@ package logx
import (
"base-go-v2/internal/config"
"base-go-v2/internal/routinex"
"base-go-v2/internal/utils/idgen"
"base-go-v2/internal/utils/strutil"
"base-go-v2/internal/utils/uid"
"fmt"
"os"
"path/filepath"
@@ -63,7 +63,7 @@ func (c *trackCore) Check(entry zapcore.Entry, ce *zapcore.CheckedEntry) *zapcor
func (c *trackCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
val := routinex.Get(TrackID)
if val == nil {
val = uid.NextID()
val = idgen.NextId()
routinex.Set(TrackID, val) // 保证同一请求复用同一 trackID
}
@@ -126,6 +126,32 @@ func (c *Context) Get(key string) (interface{}, bool) {
return val, ok
}
// SetUserID 存储 userId
func (c *Context) SetUserID(userID int64) {
c.Set("user_id", userID)
}
// GetUserID 获取 userId
func (c *Context) GetUserID() int64 {
val, ok := c.Get("user_id")
if !ok || val == nil {
return 0
}
switch v := val.(type) {
case int64:
return v
case int:
return int64(v)
case uint64:
return int64(v)
case uint:
return int64(v)
default:
return 0
}
}
// JSON 返回 JSON 响应,支持返回 error
func (c *Context) JSON(statusCode int, data interface{}) error {
c.RequestCtx.SetStatusCode(statusCode)
@@ -0,0 +1,83 @@
package idgen
import (
"strconv"
"time"
)
type DefaultIdGenerator struct {
Options *IdGeneratorOptions
SnowWorker ISnowWorker
IdGeneratorException IdGeneratorException
}
func NewDefaultIdGenerator(options *IdGeneratorOptions) *DefaultIdGenerator {
if options == nil {
panic("dig.Options error.")
}
// 1.BaseTime
minTime := int64(631123200000) // time.Now().AddDate(-30, 0, 0).UnixNano() / 1e6
if options.BaseTime < minTime || options.BaseTime > time.Now().UnixNano()/1e6 {
panic("BaseTime error.")
}
// 2.WorkerIdBitLength
if options.WorkerIdBitLength <= 0 {
panic("WorkerIdBitLength error.(range:[1, 21])")
}
if options.WorkerIdBitLength+options.SeqBitLength > 22 {
panic("error:WorkerIdBitLength + SeqBitLength <= 22")
}
// 3.WorkerId
maxWorkerIdNumber := uint16(1<<options.WorkerIdBitLength) - 1
if maxWorkerIdNumber == 0 {
maxWorkerIdNumber = 63
}
if options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber {
panic("WorkerId error. (range:[0, " + strconv.FormatUint(uint64(maxWorkerIdNumber), 10) + "]")
}
// 4.SeqBitLength
if options.SeqBitLength < 2 || options.SeqBitLength > 21 {
panic("SeqBitLength error. (range:[2, 21])")
}
// 5.MaxSeqNumber
maxSeqNumber := uint32(1<<options.SeqBitLength) - 1
if maxSeqNumber == 0 {
maxSeqNumber = 63
}
if options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber {
panic("MaxSeqNumber error. (range:[1, " + strconv.FormatUint(uint64(maxSeqNumber), 10) + "]")
}
// 6.MinSeqNumber
if options.MinSeqNumber < 5 || options.MinSeqNumber > maxSeqNumber {
panic("MinSeqNumber error. (range:[5, " + strconv.FormatUint(uint64(maxSeqNumber), 10) + "]")
}
var snowWorker ISnowWorker
switch options.Method {
case 1:
snowWorker = NewSnowWorkerM1(options)
case 2:
snowWorker = NewSnowWorkerM2(options)
default:
snowWorker = NewSnowWorkerM1(options)
}
if options.Method == 1 {
time.Sleep(time.Duration(500) * time.Microsecond)
}
return &DefaultIdGenerator{
Options: options,
SnowWorker: snowWorker,
}
}
func (dig DefaultIdGenerator) NewLong() int64 {
return dig.SnowWorker.NextId()
}
@@ -0,0 +1,5 @@
package idgen
type IIdGenerator interface {
NewLong() uint64
}
@@ -0,0 +1,5 @@
package idgen
type ISnowWorker interface {
NextId() int64
}
@@ -0,0 +1,12 @@
package idgen
import "fmt"
type IdGeneratorException struct {
message string
error error
}
func (e IdGeneratorException) IdGeneratorException(message ...interface{}) {
fmt.Println(message)
}
@@ -0,0 +1,25 @@
package idgen
type IdGeneratorOptions struct {
Method uint16 // 雪花计算方法,(1-漂移算法|2-传统算法),默认1
BaseTime int64 // 基础时间(ms单位),不能超过当前系统时间
WorkerId uint16 // 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
WorkerIdBitLength byte // 机器码位长,默认值6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过22)
SeqBitLength byte // 序列数位长,默认值6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过22)
MaxSeqNumber uint32 // 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1])
MinSeqNumber uint32 // 最小序列数(含),默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位
TopOverCostCount uint32 // 最大漂移次数(含),默认2000,推荐范围500-10000(与计算能力有关)
}
func NewIdGeneratorOptions(workerId uint16) *IdGeneratorOptions {
return &IdGeneratorOptions{
Method: 1,
WorkerId: workerId,
BaseTime: 1582136402000,
WorkerIdBitLength: 6,
SeqBitLength: 6,
MaxSeqNumber: 0,
MinSeqNumber: 5,
TopOverCostCount: 2000,
}
}
@@ -0,0 +1,19 @@
package idgen
type OverCostActionArg struct {
ActionType int32
TimeTick int64
WorkerId uint16
OverCostCountInOneTerm int32
GenCountInOneTerm int32
TermIndex int32
}
func (ocaa OverCostActionArg) OverCostActionArg(workerId uint16, timeTick int64, actionType int32, overCostCountInOneTerm int32, genCountWhenOverCost int32, index int32) {
ocaa.ActionType = actionType
ocaa.TimeTick = timeTick
ocaa.WorkerId = workerId
ocaa.OverCostCountInOneTerm = overCostCountInOneTerm
ocaa.GenCountInOneTerm = genCountWhenOverCost
ocaa.TermIndex = index
}
@@ -0,0 +1,243 @@
package idgen
import (
"sync"
"time"
)
// SnowWorkerM1 .
type SnowWorkerM1 struct {
BaseTime int64 //基础时间
WorkerId uint16 //机器码
WorkerIdBitLength byte //机器码位长
SeqBitLength byte //自增序列数位长
MaxSeqNumber uint32 //最大序列数(含)
MinSeqNumber uint32 //最小序列数(含)
TopOverCostCount uint32 //最大漂移次数
_TimestampShift byte
_CurrentSeqNumber uint32
_LastTimeTick int64
_TurnBackTimeTick int64
_TurnBackIndex byte
_IsOverCost bool
_OverCostCountInOneTerm uint32
_GenCountInOneTerm uint32
_TermIndex uint32
sync.Mutex
}
// NewSnowWorkerM1 .
func NewSnowWorkerM1(options *IdGeneratorOptions) ISnowWorker {
var workerIdBitLength byte
var seqBitLength byte
var maxSeqNumber uint32
// 1.BaseTime
var baseTime int64
if options.BaseTime != 0 {
baseTime = options.BaseTime
} else {
baseTime = 1582136402000
}
// 2.WorkerIdBitLength
if options.WorkerIdBitLength == 0 {
workerIdBitLength = 6
} else {
workerIdBitLength = options.WorkerIdBitLength
}
// 3.WorkerId
var workerId = options.WorkerId
// 4.SeqBitLength
if options.SeqBitLength == 0 {
seqBitLength = 6
} else {
seqBitLength = options.SeqBitLength
}
// 5.MaxSeqNumber
if options.MaxSeqNumber <= 0 {
maxSeqNumber = (1 << seqBitLength) - 1
} else {
maxSeqNumber = options.MaxSeqNumber
}
// 6.MinSeqNumber
var minSeqNumber = options.MinSeqNumber
// 7.Others
var topOverCostCount = options.TopOverCostCount
if topOverCostCount == 0 {
topOverCostCount = 2000
}
timestampShift := (byte)(workerIdBitLength + seqBitLength)
currentSeqNumber := minSeqNumber
return &SnowWorkerM1{
BaseTime: baseTime,
WorkerIdBitLength: workerIdBitLength,
WorkerId: workerId,
SeqBitLength: seqBitLength,
MaxSeqNumber: maxSeqNumber,
MinSeqNumber: minSeqNumber,
TopOverCostCount: topOverCostCount,
_TimestampShift: timestampShift,
_CurrentSeqNumber: currentSeqNumber,
_LastTimeTick: 0,
_TurnBackTimeTick: 0,
_TurnBackIndex: 0,
_IsOverCost: false,
_OverCostCountInOneTerm: 0,
_GenCountInOneTerm: 0,
_TermIndex: 0,
}
}
// DoGenIDAction .
func (m1 *SnowWorkerM1) DoGenIdAction(arg *OverCostActionArg) {
}
func (m1 *SnowWorkerM1) BeginOverCostAction(useTimeTick int64) {
}
func (m1 *SnowWorkerM1) EndOverCostAction(useTimeTick int64) {
if m1._TermIndex > 10000 {
m1._TermIndex = 0
}
}
func (m1 *SnowWorkerM1) BeginTurnBackAction(useTimeTick int64) {
}
func (m1 *SnowWorkerM1) EndTurnBackAction(useTimeTick int64) {
}
func (m1 *SnowWorkerM1) NextOverCostId() int64 {
currentTimeTick := m1.GetCurrentTimeTick()
if currentTimeTick > m1._LastTimeTick {
m1.EndOverCostAction(currentTimeTick)
m1._LastTimeTick = currentTimeTick
m1._CurrentSeqNumber = m1.MinSeqNumber
m1._IsOverCost = false
m1._OverCostCountInOneTerm = 0
m1._GenCountInOneTerm = 0
return m1.CalcId(m1._LastTimeTick)
}
if m1._OverCostCountInOneTerm >= m1.TopOverCostCount {
m1.EndOverCostAction(currentTimeTick)
m1._LastTimeTick = m1.GetNextTimeTick()
m1._CurrentSeqNumber = m1.MinSeqNumber
m1._IsOverCost = false
m1._OverCostCountInOneTerm = 0
m1._GenCountInOneTerm = 0
return m1.CalcId(m1._LastTimeTick)
}
if m1._CurrentSeqNumber > m1.MaxSeqNumber {
m1._LastTimeTick++
m1._CurrentSeqNumber = m1.MinSeqNumber
m1._IsOverCost = true
m1._OverCostCountInOneTerm++
m1._GenCountInOneTerm++
return m1.CalcId(m1._LastTimeTick)
}
m1._GenCountInOneTerm++
return m1.CalcId(m1._LastTimeTick)
}
// NextNormalID .
func (m1 *SnowWorkerM1) NextNormalId() int64 {
currentTimeTick := m1.GetCurrentTimeTick()
if currentTimeTick < m1._LastTimeTick {
if m1._TurnBackTimeTick < 1 {
m1._TurnBackTimeTick = m1._LastTimeTick - 1
m1._TurnBackIndex++
// 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序
// 最多4次回拨(防止回拨重叠)
if m1._TurnBackIndex > 4 {
m1._TurnBackIndex = 1
}
m1.BeginTurnBackAction(m1._TurnBackTimeTick)
}
// time.Sleep(time.Duration(1) * time.Millisecond)
return m1.CalcTurnBackId(m1._TurnBackTimeTick)
}
// 时间追平时,_TurnBackTimeTick清零
if m1._TurnBackTimeTick > 0 {
m1.EndTurnBackAction(m1._TurnBackTimeTick)
m1._TurnBackTimeTick = 0
}
if currentTimeTick > m1._LastTimeTick {
m1._LastTimeTick = currentTimeTick
m1._CurrentSeqNumber = m1.MinSeqNumber
return m1.CalcId(m1._LastTimeTick)
}
if m1._CurrentSeqNumber > m1.MaxSeqNumber {
m1.BeginOverCostAction(currentTimeTick)
m1._TermIndex++
m1._LastTimeTick++
m1._CurrentSeqNumber = m1.MinSeqNumber
m1._IsOverCost = true
m1._OverCostCountInOneTerm = 1
m1._GenCountInOneTerm = 1
return m1.CalcId(m1._LastTimeTick)
}
return m1.CalcId(m1._LastTimeTick)
}
// CalcID .
func (m1 *SnowWorkerM1) CalcId(useTimeTick int64) int64 {
result := int64(useTimeTick<<m1._TimestampShift) + int64(m1.WorkerId<<m1.SeqBitLength) + int64(m1._CurrentSeqNumber)
m1._CurrentSeqNumber++
return result
}
// CalcTurnBackID .
func (m1 *SnowWorkerM1) CalcTurnBackId(useTimeTick int64) int64 {
result := int64(useTimeTick<<m1._TimestampShift) + int64(m1.WorkerId<<m1.SeqBitLength) + int64(m1._TurnBackIndex)
m1._TurnBackTimeTick--
return result
}
// GetCurrentTimeTick .
func (m1 *SnowWorkerM1) GetCurrentTimeTick() int64 {
var millis = time.Now().UnixNano() / 1e6
return millis - m1.BaseTime
}
// GetNextTimeTick .
func (m1 *SnowWorkerM1) GetNextTimeTick() int64 {
tempTimeTicker := m1.GetCurrentTimeTick()
for tempTimeTicker <= m1._LastTimeTick {
tempTimeTicker = m1.GetCurrentTimeTick()
}
return tempTimeTicker
}
// NextId .
func (m1 *SnowWorkerM1) NextId() int64 {
m1.Lock()
defer m1.Unlock()
if m1._IsOverCost {
return m1.NextOverCostId()
} else {
return m1.NextNormalId()
}
}
@@ -0,0 +1,37 @@
package idgen
import (
"fmt"
"strconv"
)
type SnowWorkerM2 struct {
*SnowWorkerM1
}
func NewSnowWorkerM2(options *IdGeneratorOptions) ISnowWorker {
return &SnowWorkerM2{
NewSnowWorkerM1(options).(*SnowWorkerM1),
}
}
func (m2 SnowWorkerM2) NextId() int64 {
m2.Lock()
defer m2.Unlock()
currentTimeTick := m2.GetCurrentTimeTick()
if m2._LastTimeTick == currentTimeTick {
m2._CurrentSeqNumber++
if m2._CurrentSeqNumber > m2.MaxSeqNumber {
m2._CurrentSeqNumber = m2.MinSeqNumber
currentTimeTick = m2.GetNextTimeTick()
}
} else {
m2._CurrentSeqNumber = m2.MinSeqNumber
}
if currentTimeTick < m2._LastTimeTick {
fmt.Println("Time error for {0} milliseconds", strconv.FormatInt(m2._LastTimeTick-currentTimeTick, 10))
}
m2._LastTimeTick = currentTimeTick
result := int64(currentTimeTick<<m2._TimestampShift) + int64(m2.WorkerId<<m2.SeqBitLength) + int64(m2._CurrentSeqNumber)
return result
}
@@ -0,0 +1,29 @@
package idgen
import (
"sync"
)
var singletonMutex sync.Mutex
var idGenerator *DefaultIdGenerator
// SetIdGenerator .
func SetIdGenerator(options *IdGeneratorOptions) {
singletonMutex.Lock()
idGenerator = NewDefaultIdGenerator(options)
singletonMutex.Unlock()
}
// NextId .
func NextId() int64 {
if idGenerator == nil {
singletonMutex.Lock()
defer singletonMutex.Unlock()
if idGenerator == nil {
options := NewIdGeneratorOptions(1)
idGenerator = NewDefaultIdGenerator(options)
}
}
return idGenerator.NewLong()
}
@@ -9,7 +9,7 @@ import (
// CustomClaims 自定义 payload,可扩展其他信息
type CustomClaims struct {
UserID int `json:"user_id"` // 改为 int
UserID int64 `json:"user_id"` // 改为 int
jwt.RegisteredClaims
}
@@ -21,17 +21,17 @@ type TokenResult struct {
}
// CreateAccessToken 创建 Access Token,只返回 token 和 error
func CreateAccessToken(userID int) (string, error) {
func CreateAccessToken(userID int64) (string, error) {
return createToken(userID, config.App.JWT.AccessExpiry)
}
// CreateRefreshToken 创建 Refresh Token,只返回 token 和 error
func CreateRefreshToken(userID int) (string, error) {
func CreateRefreshToken(userID int64) (string, error) {
return createToken(userID, config.App.JWT.RefreshExpiry)
}
// 内部方法,根据过期时间生成 token
func createToken(userID int, expiry time.Duration) (string, error) {
func createToken(userID int64, expiry time.Duration) (string, error) {
claims := &CustomClaims{
UserID: userID,
RegisteredClaims: jwt.RegisteredClaims{
@@ -13,6 +13,10 @@ func New() M {
return M{}
}
func NewArr() {
//return make([]M, 0, len())
}
// Set 设置单个键值,支持链式调用
func (m M) Set(key string, value interface{}) M {
m[key] = value
@@ -78,33 +82,68 @@ func (m M) GetString(key string) string {
return ""
}
// GetInt 获取整数类型
func (m M) GetInt(key string) int {
if v, ok := m[key]; ok {
// 核心获取整数的方法,返回 int64
func (m M) getIntValue(key string) int64 {
if v, ok := m[key]; ok && v != nil {
switch val := v.(type) {
case int:
return val
return int64(val)
case int8:
return int(val)
return int64(val)
case int16:
return int(val)
return int64(val)
case int32:
return int(val)
return int64(val)
case int64:
return int(val)
return val
case uint:
return int64(val)
case uint8:
return int64(val)
case uint16:
return int64(val)
case uint32:
return int64(val)
case uint64:
return int64(val) // 注意溢出
case float32:
return int(val)
return int64(val)
case float64:
return int(val)
return int64(val)
case string:
if i, err := strconv.ParseInt(val, 10, 64); err == nil {
return int(i)
return i
}
}
}
return 0
}
// GetInt 返回默认 int 类型
func (m M) GetInt(key string) int {
return int(m.getIntValue(key))
}
// GetInt64 返回 int64
func (m M) GetInt64(key string) int64 {
return m.getIntValue(key)
}
// GetInt32 返回 int32
func (m M) GetInt32(key string) int32 {
return int32(m.getIntValue(key))
}
// GetInt16 返回 int16
func (m M) GetInt16(key string) int16 {
return int16(m.getIntValue(key))
}
// GetInt8 返回 int8
func (m M) GetInt8(key string) int8 {
return int8(m.getIntValue(key))
}
// Merge 合并另一个 M,后者会覆盖前者同名字段
func (m M) Merge(other M) M {
for k, v := range other {
@@ -1,90 +0,0 @@
package uid
import (
"base-go-v2/internal/config"
"sync"
"sync/atomic"
"time"
)
const (
datacenterBits = uint64(5)
workerBits = uint64(5)
sequenceBits = uint64(12)
maxSequence = -1 ^ (-1 << sequenceBits)
workerShift = sequenceBits
datacenterShift = sequenceBits + workerBits
timestampShift = sequenceBits + workerBits + datacenterBits
epoch = int64(1672531200000) // 2023-01-01
)
type Snowflake struct {
lastStamp uint64 // 上一次时间戳 (毫秒)
sequence uint64 // 序列号
dcID uint64
workerID uint64
}
var (
sfInstance *Snowflake
once sync.Once
)
// lazy 初始化实例
func initInstance() {
var dcID, wID uint64
dcID = config.App.Snowflake.DatacenterID
wID = config.App.Snowflake.WorkerID
sfInstance = &Snowflake{
dcID: dcID,
workerID: wID,
}
}
// NextID 生成全局唯一 ID,无锁版本
func NextID() uint64 {
once.Do(initInstance)
for {
now := uint64(time.Now().UnixNano() / 1e6)
last := atomic.LoadUint64(&sfInstance.lastStamp)
seq := atomic.LoadUint64(&sfInstance.sequence)
if now < last {
// 系统时钟回拨,等待
now = waitNextMillis(last)
}
if now == last {
seq = (seq + 1) & uint64(maxSequence)
if seq == 0 {
now = waitNextMillis(last)
}
} else {
seq = 0
}
if atomic.CompareAndSwapUint64(&sfInstance.lastStamp, last, now) {
atomic.StoreUint64(&sfInstance.sequence, seq)
id := ((now - uint64(epoch)) << timestampShift) |
(sfInstance.dcID << datacenterShift) |
(sfInstance.workerID << workerShift) |
seq
return id
}
}
}
// 等待下一个毫秒
func waitNextMillis(last uint64) uint64 {
now := uint64(time.Now().UnixNano() / 1e6)
for now <= last {
now = uint64(time.Now().UnixNano() / 1e6)
}
return now
}