Skip to content

一组基础设施:jsonx 接管全局 JSON codec 把超大 int64 转字符串;snowflake 是雪花 ID 生成器;constant 存单值常量;enum 存带附加字段的枚举;model.LoginUser 是跨模块复用的登录用户上下文。前两者直接关系到雪花 ID 的前端/后端一致性,详见 /conventions/snowflake-jsonx

关键导出

  • jsonx.Init() 接管 gin 全局 JSON codec(ginjson.API = codec{}
  • jsonx.Marshal(v) ([]byte, error) / Unmarshal(data, v) error
  • 常量 maxSafeInteger=9007199254740991 / minSafeInteger
  • snowflake.Generator / New(workerID, datacenterID int64) (*Generator, error) / (g) Next() int64
  • snowflake.Init() / Next() int64(包级,未 Init panic)
  • constant.CacheSysConfig / CacheSysDict / CacheSysOssConfig / CacheSysDept / ...
  • constant.CacheTTLSysConfig=0(不过期)/ CacheTTLSysClient=30*24h / ...
  • constant.CaptchaCodeKey / RepeatSubmitKey / RateLimitKey / OnlineTokenKeyPrefix / OssDefaultConfigKey
  • constant.ConstantTopParentID=0 / ConstantEncryptHeader="ENC_" / ClientIDHeader="clientid"
  • constant.SuperAdminUserID / AllPermission / ExcludeProperties
  • enum.BusinessType(Other/Insert/Update/Delete/Grant/Export/Import/Force/GenCode/Clean)+ Int()/Info()
  • enum.OperatorType(Other/Manage/Mobile)+ Int()
  • enum.BusinessStatus(Success/Fail)+ Int()
  • enum.UserStatus / UserType / DeviceType / LoginType + ParseXxx(code)(T,bool) 及列举函数

model.LoginUser struct{UserID, DeptID, DeptCategory, DeptName, Token, UserType, LoginTime, ExpireTime, IPAddr, LoginLocation, Browser, OS, MenuPermission, RolePermission, Username, Nickname, Roles, DataScopeRoleMap, Posts, RoleID, ClientKey, DeviceType}

  • model.LoginID() (string, error) 形如 sys_user:1761100000000000001
  • model.ErrUserTypeEmpty / ErrUserIDEmpty

典型用法

go
// cmd/standalone/main.go:38
jsonx.Init()

// internal/system/service/message_service.go:180
b, err := jsonx.Marshal(data)

// internal/system/service/client_service.go:119
add.ID = snowflake.Next()

// internal/system/router.go:61
oplog.Log(profileLogTitle, enum.BusinessTypeUpdate)

// 比较
if user.Status == enum.UserStatusDisable.Code { /* ... */ }

// internal/auth/service/social_auth_strategy.go:70
loginUser := &model.LoginUser{UserID: ..., UserType: enum.UserTypeSys.Code, /* ... */}
token, err := loginhelper.Login(loginUser, client.DeviceType)

坑/约定

WARNING

  • jsonx int64 编解码器在 init() 注册(非 Init()——jsoniter 按类型缓存 encoder,一旦固化挤不掉。Init() 只负责接管 gin codec,必须在首个 c.JSON/参数绑定之前调用,靠包 init 顺序抢不可靠。Decode 侧同时接受数字与字符串(出参既然变字符串,前端回传详情时送来的是字符串)。api 选 ConfigCompatibleWithStandardLibrary 以只改 int64 形态不动其余行为。任何需要与出参同构的场景都必须用 jsonx.Marshal,用 encoding/json 会绕过编码器让 id 形态不一致。
  • snowflake 业务表主键都是 bigint not nullauto_increment,插入前必须由应用层发号(GORM 无等价机制);多进程部署每个进程必须配不同 workerId,否则撞号(见 configs/<module>.yaml);同毫秒序列号用尽(4096)自旋等下一毫秒;时钟回拨不 panic 而是等追平(旁路写入如登录日志不该打挂进程);epoch=1577836800000(2020-01-01 UTC),上线后不可再改(否则新旧 ID 大小关系错乱)。
  • constant vs enum:constant 放「单值无附加信息」的标识,带附加字段且需反查的放 enum。 CacheTTLSysConfig / CacheTTLSysDict / CacheTTLSysOssConfig=0 是有意不过期(写路径都带缓存维护,过期会让上传等关键路径失败)。
  • enumBusinessType/OperatorType/BusinessStatus 落库写 Int(),顺序不可调整、不可插入新值,只能在末尾追加;Go const 不支持结构体,枚举实例用 var 声明,约定「所有导出枚举实例均为逻辑常量,不得赋值」(靠 enum_test.go 兜底);ParseXxx 精确匹配, ok=false 只表示「无附加信息」不能据此拒绝请求(如 device_type 原始字符串合法但不在枚举内);ParseUserTypeFromLoginID 是子串匹配(对 sys_user:1 这类拼接串),与 ParseUserType 精确匹配语义不同,不可混用,且显式拦空串( strings.Contains(s,"") 恒 true)。
  • model.LoginUserpkg/satoken/loginhelperinternal/system/model/dtoRoles []*systemdto.RoleDTO),故 pkg/model import 了 internal/system/model/dto——这是 pkg 里少有的对 internal 的依赖;LoginID() 要求 UserTypeUserID 都非空,否则返回错误;存进 sa-token session 的是 JSON 串。 :::

相关页:/conventions/snowflake-jsonx/pkg-reference/satoken/pkg-reference/repository

基于 MIT 协议开源