gorm gen 是官方推荐的模型生成方式,直接读取数据库表结构生成带 gorm: 标签的 Go 结构体,无需注释或 YAML 配置,支持自动同步字段变更、索引和默认值。

用 gorm gen 生成带 GORM 标签的结构体,不是靠注释猜
gorm gen 是官方推荐的模型生成方式,它直接读取数据库表结构,生成含 gorm: 标签的 Go 结构体,不依赖任何注释或 YAML 配置。你改了表字段类型、加了索引、设了默认值,只要重新跑一次 gormgen,结构体就同步更新——这点和手写或基于 YAML 的方案有本质区别。
常见错误现象:用 swag init 扫描时发现 @Success 200 {object} models.User 报错 “cannot find type definition”,其实不是 swag 问题,而是 models.User 没导出、没 json: tag、或者压根没生成(比如忘了运行 gormgen)。
- 必须先确保数据库表存在且可连通,
gormgen --dsn中的连接串要带parseTime=true和loc=Local,否则time.Time字段会映射失败 - 生成路径建议设为
./models,避免和swag默认扫描的./models冲突;如果已有同名包,gormgen不会覆盖,得手动删旧文件 -
FieldNullable: true要慎开:它会让所有可空字段变成指针(如*string),但 swag 解析时对指针支持不稳定,容易导致文档里字段显示为object或丢失 - 若表有外键,
gormgen默认不生成关联字段(如UserID uint不自动变成User User),需要手动补或启用WithPreload模式(但会增加结构体复杂度)
swag init 扫不到结构体?检查 package 声明和 @Model 注释位置
swag 不解析数据库结构,也不读 GORM 标签,它只认两样东西:Go 文件里的 package 声明,以及紧贴在 struct 上方的 // @Model 注释。哪怕你的 models.User 已经被 gormgen 正确生成,只要缺这个注释,@Success 200 {object} models.User 就会静默失败。
使用场景:你把模型放在 ./models/user.go,但 swag init 后 docs/swagger.json 里 components.schemas.User 是空的。
-
user.go必须是package models,不能是package main或package user -
// @Model必须紧贴 struct 定义上方,中间不能有空行,也不能被其他注释隔开 - 示例写法:
// @Model // @Description 用户模型,对应 users 表 type User struct { ID uint `json:"id" gorm:"primaryKey"` Name string `json:"name" gorm:"size:100"` Email string `json:"email" gorm:"uniqueIndex"` CreatedAt time.Time `json:"created_at"` } - 如果结构体嵌套了另一个模型(如
Profile Profile),那个Profilestruct 也得有独立的// @Model注释,否则嵌套字段不会展开
字段类型不匹配导致 Swagger 文档显示 “object” 或字段为空
Swagger UI 里点开响应体,看到的是一堆 object、字段名全空、类型全是 string,大概率是字段没加 json: tag,或用了非导出字段(小写首字母)。swag 只序列化导出字段,且只认 json: tag 里的 key 名,跟 gorm: 无关。
性能影响:字段缺失不会拖慢 API,但会导致前端无法生成 TypeScript 类型、mock 数据失效、Postman 自动填充参数失败。
- 所有需要出现在文档里的字段,必须首字母大写 + 有
json:"xxx",例如Name string `json:"name"`,不能写name string -
time.Time字段推荐加json:"created_at,string",否则前端收到的是 Unix 时间戳数字,不易读 - 不要用
*string或sql.NullString:swag 对指针和 SQL null 类型支持弱,容易跳过整个字段;宁可加omitempty(json:"name,omitempty")来控制空值省略 - 枚举字段(如 status int)想在文档里显示可选值,得额外加
// @Enum 0,1,2和// @EnumDescription "pending","active","archived",否则只显示integer
启动服务后 /swagger/index.html 打不开?别漏挂载静态文件
swag init 只生成 docs/ 目录和 swagger.json,它不自动注册 HTTP 路由。如果你用 Gin,必须显式调用 ginSwagger.WrapHandler;用 net/http,得用 http.FileServer 映射路径。漏掉这步,浏览器访问 /swagger 就是 404。
容易踩的坑:Gin 用户常把 r.GET("/swagger/*any", ...) 写在 r := gin.Default() 之后,但没注意中间件顺序——如果开了 JWT 鉴权中间件并全局注册,Swagger UI 也会被拦截,得单独放行。
- Gin 示例(必须 import
github.com/swaggo/gin-swagger和github.com/swaggo/files):r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - 路径末尾的
/*any不能少,否则子资源(如/swagger/swagger-ui-bundle.js)加载失败 - 如果项目用了模块路径(如
github.com/yourname/project),确保swag init -g cmd/main.go指向真正的入口,否则docs/docs.go里生成的包路径错,运行时报undefined: docs.SwaggerInfo - 修改模型或注释后,必须重新运行
swag init,再重启服务——swag 不热重载
gormgen 要看见表结构,swag 要看见 @Model 和 json: tag,HTTP 路由要看见 docs/ 目录。少一个“看见”,文档就断在某个环节。


















