Skip to content

工具函数与核心组件 ​

本文汇总后端可被各业务复用的「基础/扩展能力」:util/ 工具包、core/ 核心组件、plugin/ 通用能力、通用控制器。二次开发最常直接调用这些设施,避免重复实现。

一、util 工具包(server/util/) ​

util 只放跨业务通用工具,邮件/短信/验证码/OSS 等插件能力位于 plugin/(见第三节)。

文件 / 目录能力(真实签名)
tools.goToolsUtil:MakeUuidV7()、StrMd5()、RandomString()、Random(min,max)、Contains[T comparable]、Round(val,n)、JsonToObj[T] / ObjToJson
verify.goVerifyUtil:VerifyJSON / VerifyBody / VerifyQuery / VerifyJSONArray / VerifyFile,绑定 + 校验一体,失败统一翻译为 response.ParamsValidError
string.goStringUtil:命名风格转换(ToSnakeCase 等),配合 golang.org/x/text/cases
array.goTreeItem[T] 泛型接口 + ListToTree[T](items, rootParentID):扁平列表 → 树结构(区域树 / 菜单树通用)
cache.goCacheUtil{Name}:以 Name:field 为键的 Redis 缓存封装,SetCache/GetCache,默认 1h TTL
redis.goRedisUtil(redisUtil):Set/Get/Del/Exists/HSet/HGet/HGetAll/LPush/RPop/BRPop/Expire/TTL 等常用原子操作,业务侧通用键值/哈希/队列操作入口
redis_lock.goNewRedisLock(key, expire) + Lock()/Unlock():SET NX PX + Lua 校验持有的分布式锁,用于定时任务/防并发
jwt.go三实例:AdminJWTUtil(后台)、WebJWTUtil(C 端)、JWTUtil(兼容别名);UserClaims{ UserID, TokenVersion, TokenType };GenerateAccessToken/GenerateRefreshToken/ParseToken/…
null_time.goNullTimeUtil:面向 x_null.Time 的构造与格式化,常量 DateFormat / TimeFormat,方法 Now()、ParseTime(t)、TodayZero() 等
url.goUrlUtil:HashUrl(id,name)、ToAbsoluteUrl(u)、GetFileExt(name)、BuildFileSavePath(name)(YYYYMMDD/HH/{id后2位}/{uuidv7}{ext})、ReplaceExt(path,newExt)
ip.goIP 归属地解析(ip2region)
server.go服务器信息采集(CPU / 内存 / 磁盘)
uaparser.goUser-Agent 解析(浏览器 / 系统 / 设备)
convert_util/convert_util.Copy(&dst, src):结构体字段拷贝 + 类型转换(模型 → DTO 的默认手段)
excel_util/Excel 导入 / 导出(详见 导入导出excel.md)
img_util/图片处理:缩放、水印、缩略图
file_util/基于 os.OpenRoot 的安全文件读写:ReadFile/WriteFile/… + Close();根目录固定为运行目录,禁止 ../ 逃逸与绝对路径
validation/Gin 绑定 + 校验器集中配置(详见下)

validation 包(util/validation/) ​

单一入口,bootstrap.go 启动时调用一次;对同一引擎幂等。

  • register.go → Register():从 binding.Validator.Engine() 拿到 *validator.Validate,串起下面两步。
  • null.go → register_null():RegisterCustomTypeFunc(validateValuer, x_null.String{}, x_null.Int64{}, x_null.Float64{}, x_null.Time{}),让 binding:"required" 等标签对可空类型依然生效。
  • lang.go → ValidMsg(errs):中文错误翻译(go-playground/validator + ut bundle),并对 map 结果排序保证同一错误顺序稳定。

典型用法 ​

go
// 生成 UUIDv7
id := util.ToolsUtil.MakeUuidV7()

// 控制器:绑定 + 校验 + 统一失败出口(约定见 core/response)
if response.IsFail(c, util.VerifyUtil.VerifyQuery(c, &req)) { return }
data, err := XxxService.List(page, req)
response.JSON(c, data, err)

// Redis 分布式锁(定时任务防并发)
lock := util.NewRedisLock("cron:xxx", 10*time.Second)
if lock.Lock() {
    defer lock.Unlock()
    // 临界区
}

二、core 核心组件(server/core/) ​

全局单例 ​

文件说明
db.goGORM 初始化,暴露全局 core.DB(*gorm.DB)
redis.goRedis 客户端初始化,全局 core.Redis(*redis.Client,v9)
logger.goZap 日志初始化,全局 core.Logger,支持分级与文件切割
queue.go队列门面:包初始化时基于 Redis 构造全局 core.Queue(queue.Queue)与 core.QueueDelay(queue_delay.DelayedQueue),业务侧直接复用,无需自行 new
ws.goWebSocket 门面,转发到 core/ws.Manager(详见 WebSocket.md)

子包 ​

目录内容
core/request/PageReq{ PageNo int, PageSize int }(form:"pageNo,default=1" / pageSize,default=20,validate:"omitempty,gte=1" / gt=0,lte=60)——只有这两字段,Order/Sort 由业务需要时自行扩展
core/response/统一响应与错误码(详见下)
core/ws/client.go、manager.go、room.go、interface.go——连接、房间、按用户/房间/全局推送、集群广播
core/pubsub/interface.go、config.go、redis.go、registry.go——mitt 风格 On/Off/Emit,Redis 后端跨实例广播
core/queue/interface.go、config.go、redis.go——工作队列(BRPOP 并发消费),IoT iot:ingest 即走此通道
core/queue_delay/interface.go、config.go、redis.go——延迟/定时投递队列(Redis ZSET 到期轮询),用于订单超时、延时通知

统一响应(core/response) ​

约定:HTTP 状态码恒为 200,成败一律以 body.code 表达;失败响应不携带 data;未识别错误只落日志、对外返回统一文案。

go
// 响应结构
type Response struct { Code int `json:"code"`; Message string `json:"message"`; Data any `json:"data"` }
type PageResp  struct { Count int64; PageNo int; PageSize int; Lists any }

// 出口函数
response.Ok(c, data...)                    // 成功(data 可选)
response.Send(c, code, msg, data)          // 最底层发送
response.JSON(c, data, err)                // 统一出口:err==nil 返回 data,否则翻译错误
response.IsFail(c, err) bool               // 守卫式:err!=nil 直接响应失败并 return true
response.Fail(c, err)                      // 中间件等非 service 场景直接失败
response.FailMsg(c, msg)                   // 指定文案(默认 code=300)
response.NotFound(c, msg) / NoRoute(c)     // 404

// service 侧错误构造
response.CheckErr(err, "统计规则链失败")     // 记日志 + 上抛 SystemError(带文案)
response.CheckDBErr(err, "岗位不存在!", "详情获取失败") // 分流「记录不存在 / 其它 DB 错误」

RespType 同时实现 error 接口,可 return response.AssertArgumentError.SetMessage("...") 从 service 直接上抛,由 JSON/IsFail 翻译成 {code, message}。预置码常用:Success(200) / Failed(300) / ParamsValidError(310) / AssertArgumentError(313) / TokenInvalid(333) / NoPermission(403) / SystemError(500) 等;Resolve(err) 还会自动识别 MySQL 1062/1048/1452/1451 与 gorm.ErrRecordNotFound。

三、plugin 通用能力(server/plugin/) ​

跨业务、可能替换服务商 / 引擎的能力统一以「插件」形式落地,util 不重复实现:

目录能力
plugin/email/email.go SMTP 发送,code.go 邮箱验证码(限频 / Redis 存储),配套 app/queue/email_code.go 走异步队列投递
plugin/sms/code.go 短信验证码(服务商对接位)
plugin/wechat/微信开放能力封装
plugin/ipapk/parser.go ip2region 归属地解析(util/ip.go 的底层)
plugin/aj-captcha-go/行为验证码:滑块 / 文字点选,captcha_service + captcha_config + 内存/Redis 双缓存实现
plugin/storage/文件存储引擎(见下节)

四、存储引擎(plugin/storage/) ​

驱动工厂 + 单例,统一 StorageEngine 接口:

go
// plugin/storage/storage_interface.go
type StorageEngine interface {
    PutObject(key string, data io.Reader, size int64) (string, error)
    ObjectExists(key string) (bool, error)             // 秒传判断
    GetObjectURL(key string) (string, error)
    // 分片上传
    InitMultipartUpload(key string) (string, error)
    UploadPart(key, uploadId string, partNumber int, data io.Reader, size int64) (string, error)
    CompleteMultipartUpload(key, uploadId string, parts []MultipartPart) (string, error)
    AbortMultipartUpload(key, uploadId string) error
    ListParts(key, uploadId string) ([]MultipartPart, error)
}
文件角色
storage_factory.goGetStorageEngine():sync.Once 单例,当前固定返回本地存储(storage_local.go),OSS 通过 storage_oss.go 预留
storage.go顶层 StorageDriver.Upload(file) 便捷入口
storage_local.go本地磁盘实现
storage_oss.go阿里云 OSS(S3 兼容)实现
presign.go预签名 URL(前端直传)
cron_cleanup.go分片临时目录清理:CleanChunkTmpDir() 定时任务每小时整点调用,删除超过 ChunkExpireHour(默认 24h)的分片目录
  • 存储路径:util.UrlUtil.BuildFileSavePath(name) 统一生成 YYYYMMDD/HH/{uuidv7 后 2 位}/{uuidv7}{ext}(用 id 后 2 位分桶,缓解目录锁争抢)。
  • 访问前缀:/api/uploads/<hashId>/<fileName>,由 util.UrlUtil.HashUrl 拼接;路由 routes/api.go 做静态映射,实际文件流由 common_controller/upload.go 中的 FileHandler.Serve 按哈希 ID 读物理文件流式返回(自动 MIME、Cache-Control 长缓存)。
  • 秒传:ObjectExists(key)。

详解见 存储引擎。

五、WebSocket 与事件总线 ​

已独立成篇,这里只做入口指路:

  • WebSocket:连接管理、按用户 / 房间 / 全局推送、集群广播、在线人数统计、连接强制关闭。IoT 大屏推送即基于此(房间 iot:device:{id} / iot:map:{spaceId})。
  • 事件总线 pubsub:mitt 风格 On/Off/Emit,Redis 后端跨实例广播,与 core/queue(工作队列)用途不同。

六、通用控制器(app/controller/admin_ctl/common_controller/) ​

文件功能
upload.go文件上传(本地/OSS 驱动 + 秒传),并内含 FileHandler.Serve(/api/uploads/:id 文件流响应)
upload_chunk.goS3 风格分片直传:初始化 / 上传分片 / 完成 / 列举 / 中止
album.go相册分组与图片素材管理
captcha.go行为验证码获取 / 校验(plugin/aj-captcha-go)
ge_tui.go个推移动推送(PushToSingleBatchCID,按 CID 批量推)
index.go后台首页统计

WebSocket 升级处理器位于 app/controller/ws.go(controller 层),对接 core/ws.Manager。

以上能力均可在新业务模块中直接复用,无需重复实现。