GoFiber+GORM如何实现Many2Many嵌套反序列化数据POST接口
问题根因
- 用
map[string]string接收请求体无法承接数组、对象类的嵌套JSON值,本身就不适合处理带嵌套结构的请求 - 前端传参中
price、quantity字段用了字符串格式,和结构体定义的float64、int类型不匹配,直接绑定会触发类型错误 - 提供的请求JSON样例存在字段拼写错误,库存项的
color字段被误写为action,会导致颜色值绑定丢失 - GORM的Many2Many关联不需要手动操作中间表,只要将关联的结构体切片正确填充到主模型字段,调用
Create方法时会自动完成主表、关联表、中间表的数据写入
实现方案
两种方案按需选择,优先选第一种,逻辑更简洁。
方案1:前端配合修正传参类型(推荐)
让前端调整JSON格式,将price、quantity字段的引号去掉,传原生数值类型,格式参考:
{ "code": "SS2022VNMNYU7W", "title": "Title Demo", "description": "Description Demo", "image": "path", "price": 100, "stock": [ {"size": "m", "color": "red", "quantity": 50}, {"size": "m", "color": "yellow", "quantity": 50}, {"size": "l", "color": "red", "quantity": 20}, {"size": "l", "color": "blue", "quantity": 30} ] }
处理函数直接绑定到Product结构体即可,不需要手动做类型转换,动态长度的库存数组会自动解析:
func CreateProduct(c *fiber.Ctx) error { product := new(models.Product) if err := c.BodyParser(product); err != nil { return c.Status(400).JSON(fiber.Map{"error": "参数解析失败: " + err.Error()}) } // 自动处理多对多关联写入:新增商品记录、新增所有库存记录、在中间表写入二者关联关系 // 如果库存表加了(size,color)联合唯一索引,加下面这句避免重复插入报错 // err := database.DB.Clauses(clause.OnConflict{DoNothing: true}).Create(product).Error if err := database.DB.Create(product).Error; err != nil { return c.Status(500).JSON(fiber.Map{"error": "创建失败: " + err.Error()}) } return c.JSON(product) }
方案2:后端兼容字符串格式数值(无需改前端)
如果无法协调前端修改传参格式,就自定义请求结构体承接前端传的字符串类型数值,手动做类型转换后再组装数据库模型,不管库存数组传多少条都能动态处理:
import "strconv" // 定义和前端传参类型完全匹配的请求结构体 type CreateProductReq struct { Code string `json:"code"` Title string `json:"title"` Description string `json:"description"` Image string `json:"image"` Price string `json:"price"` Stocks []struct { Size string `json:"size"` Color string `json:"color"` Quantity string `json:"quantity"` } `json:"stock"` } func CreateProduct(c *fiber.Ctx) error { var req CreateProductReq if err := c.BodyParser(&req); err != nil { return c.Status(400).JSON(fiber.Map{"error": "参数解析失败: " + err.Error()}) } // 转换价格为float64 price, err := strconv.ParseFloat(req.Price, 64) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "价格格式错误"}) } // 组装商品模型,动态遍历转换库存数据 product := models.Product{ Code: req.Code, Title: req.Title, Description: req.Description, Image: req.Image, Price: price, Stocks: make([]models.Stock, 0, len(req.Stocks)), } for _, s := range req.Stocks { qty, err := strconv.Atoi(s.Quantity) if err != nil { return c.Status(400).JSON(fiber.Map{"error": "库存数量格式错误"}) } product.Stocks = append(product.Stocks, models.Stock{ Size: s.Size, Color: s.Color, Quantity: qty, }) } if err := database.DB.Create(&product).Error; err != nil { return c.Status(500).JSON(fiber.Map{"error": "创建失败: " + err.Error()}) } return c.JSON(product) }
注意事项
- 代码运行前要确保已经执行过GORM的
AutoMigrate,保证products、stocks、product_stocks三张表正常创建,关联外键生成正确 - 如果业务场景下库存项是可复用的(不同商品共用同一个尺码+颜色的库存记录),不要直接用上面的自动创建逻辑,需要先根据
size和color查询已存在的Stock记录,不存在再新建,避免生成重复库存数据 - 结构体中
Stocks字段的gorm标签已经正确配置了多对多关联关系,不需要额外手动指定中间表操作逻辑
内容的提问来源于stack exchange,提问作者Zirene Nguyễn
相关产品推荐
相关产品推荐

