gin项目应严格采用internal四层分层结构:handler→service→repository→model单向依赖,cmd存放启动入口,configs按环境分层覆盖,middleware与router按作用域分级,pkg仅放跨项目复用组件,纯api项目应删除templates和static目录。

要让Gin项目随着功能增长仍能快速定位代码、安全修改逻辑、方便多人协作,就必须在初始化阶段就确立清晰的目录边界和职责归属,而不是等接口堆满main.go才去拆分。
核心分层:internal里四层必须隔离
所有业务代码必须放在【internal】目录下,这是Go语言强制的私有包机制——外部模块无法导入internal里的任何包,从源头杜绝了业务逻辑被意外复用或误调用。
内部按职责严格划分为四层,顺序不能颠倒:
- handler(控制器):只做三件事——解析请求参数、校验格式、调用service方法;不写SQL、不处理业务规则、不构造返回体。
- service(服务):承载真实业务逻辑,比如“注册时检查手机号是否已存在→生成邀请码→发短信→记录行为日志”;它调用repository,但绝不碰HTTP上下文。
- repository(数据访问):只负责与数据库/缓存交互,方法名必须是Create/FindByID/Update/Delete这类动词开头;禁止在repository里写条件判断或组合查询逻辑。
- model(数据模型):仅定义struct,字段名与数据库列名一致,带GORM或Ent标签;不放方法、不嵌套逻辑、不引用其他包。
这四层之间只能单向依赖:handler → service → repository → model。反向调用直接编译失败。
配置与入口:cmd和configs各司其职
项目启动入口必须独立于业务逻辑,放在cmd/api/main.go中。它只做四件事:加载configs、初始化DB/Redis/Logger、注册router、调用r.Run()。
configs目录下存放YAML文件,至少包含app.yaml(通用配置)、dev.yaml(开发覆盖项)、prod.yaml(生产覆盖项)。使用viper.LoadConfigFile时,【必须先读app.yaml,再按环境名叠加覆盖】,否则dev环境会漏掉数据库超时设置。
不要把config结构体定义写在main.go里——统一抽到pkg/config/config.go中,用NewConfig()返回指针,避免多处重复解析。
中间件与路由:按作用域分级存放
全局中间件(如logger、recovery、CORS)放在middleware/根目录,每个文件对应一个功能,命名即功能,如logger.go、auth.go。
路由注册分两级:
方法一:总入口router/router.go集中注册所有分组,再通过router/v1/user.go、router/v1/order.go等按业务模块拆分子路由文件。
方法二:更推荐按版本隔离——router/v1/下只放v1相关路由,router/v2/留空备用;每个版本目录内含routes.go(注册本版所有路由)和middleware/子目录(仅该版本专用中间件,如v1需要JWT而v2改用Session)。
注意:认证类中间件必须在router层绑定,不能塞进handler里手动调用,否则panic时无法捕获错误堆栈。
工具与复用:pkg不是垃圾桶,是发射台
pkg目录只放真正可跨项目复用的代码:比如封装好的zap日志组件、基于viper的通用配置加载器、统一响应结构体Response{Code,Msg,Data}及其JSON序列化方法。
业务强相关的工具函数(如“生成订单号”“计算用户积分”)绝不能放进pkg——它们属于service层职责,硬塞pkg会导致业务逻辑泄露到外部项目,破坏内聚性。
第三方库扩展(如GORM分页插件、Redis锁工具)可放在pkg/gormx、pkg/redisx下,但必须提供完整单元测试和README说明使用约束。
静态资源与模板:前后端分离时直接删掉
如果项目纯API(无HTML渲染),【直接删除templates/和static/目录】,连同gin.HTML渲染相关代码一并移除,避免后续误配导致404或路径泄露。
若需返回HTML(如管理后台首页),templates/下按功能分文件夹:admin/login.tmpl、user/profile.tmpl;static/中css/js/images严格按域名前缀隔离,防止CDN缓存污染。











