一组基础设施: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() int64snowflake.Init() / Next() int64(包级,未 Init panic)constant.CacheSysConfig / CacheSysDict / CacheSysOssConfig / CacheSysDept / ...constant.CacheTTLSysConfig=0(不过期)/ CacheTTLSysClient=30*24h / ...constant.CaptchaCodeKey / RepeatSubmitKey / RateLimitKey / OnlineTokenKeyPrefix / OssDefaultConfigKeyconstant.ConstantTopParentID=0 / ConstantEncryptHeader="ENC_" / ClientIDHeader="clientid"constant.SuperAdminUserID / AllPermission / ExcludePropertiesenum.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:1761100000000000001model.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 null无auto_increment,插入前必须由应用层发号(GORM 无等价机制);多进程部署每个进程必须配不同workerId,否则撞号(见configs/<module>.yaml);同毫秒序列号用尽(4096)自旋等下一毫秒;时钟回拨不 panic 而是等追平(旁路写入如登录日志不该打挂进程);epoch=1577836800000(2020-01-01 UTC),上线后不可再改(否则新旧 ID 大小关系错乱)。 - constant vs enum:constant 放「单值无附加信息」的标识,带附加字段且需反查的放 enum。
CacheTTLSysConfig / CacheTTLSysDict / CacheTTLSysOssConfig=0是有意不过期(写路径都带缓存维护,过期会让上传等关键路径失败)。 - enum:
BusinessType/OperatorType/BusinessStatus落库写Int(),顺序不可调整、不可插入新值,只能在末尾追加;Go const 不支持结构体,枚举实例用 var 声明,约定「所有导出枚举实例均为逻辑常量,不得赋值」(靠enum_test.go兜底);ParseXxx精确匹配,ok=false只表示「无附加信息」不能据此拒绝请求(如device_type原始字符串合法但不在枚举内);ParseUserTypeFromLoginID是子串匹配(对sys_user:1这类拼接串),与ParseUserType精确匹配语义不同,不可混用,且显式拦空串(strings.Contains(s,"")恒 true)。 - model.LoginUser 跨
pkg/satoken/loginhelper与internal/system/model/dto(Roles []*systemdto.RoleDTO),故pkg/modelimport 了internal/system/model/dto——这是pkg里少有的对internal的依赖;LoginID()要求UserType与UserID都非空,否则返回错误;存进 sa-token session 的是 JSON 串。 :::
相关页:/conventions/snowflake-jsonx、/pkg-reference/satoken、/pkg-reference/repository。