在Golang中使用Gin和Gorm实现创建与更新操作共用同一结构体
在Golang中使用Gin和Gorm实现创建与更新操作共用同一结构体 免责声明:本人是Go语言新手
我的用户结构体如下:
type User struct {
ID uint32 `json:"id"`
FirstName string `json:"firstName" binding:"required"`
LastName string `json:"lastName"`
Email string `json:"email" binding:"required,email,uniqueModelValue=users email"`
Active bool `json:"active"`
Password string `json:"password,omitempty" binding:"required,gte=8"`
UserType string `json:"userType" binding:"oneof=admin backoffice principal staff parent student"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
/POST /users 处理程序
func Create(ctx *gin.Context) {
user := models.User{}
//验证
if err := ctx.ShouldBind(&user); err != nil {
response.Error(ctx, err)
return
}
db, _ := database.GetDB()
db.Create(&user)
// 从响应中移除密码
user.Password = ""
response.Success(ctx, user)
}
我想使用相同的结构体创建一个更新处理程序,有没有办法可以使用相同的结构体来实现?
请注意,结构体在许多字段(如firstName、email等)上都有必需的绑定标签。而在更新时,我可能不会传递这些字段。
我想出了类似这样的方案:
/PUT /users/ 处理程序
func Update(ctx *gin.Context) {
userID := ctx.Param("userId")
user := models.User{}
db, _ := database.GetDB()
if err := db.First(&user, userID).Error; err != nil {
response.Error(ctx, err)
return
}
updateUser := models.User{}
if err := ctx.BindJSON(&updateUser); err != nil {
response.Error(ctx, err)
}
//fmt.Printf("%v", updateUser)
db.Model(&user).Updates(updateUser)
response.Success(ctx, user)
}
这显然会失败,因为缺少必需的验证。例如,如果我尝试只更新lastName。
更多关于在Golang中使用Gin和Gorm实现创建与更新操作共用同一结构体的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于在Golang中使用Gin和Gorm实现创建与更新操作共用同一结构体的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中,使用Gin和Gorm实现创建与更新操作共用同一结构体时,可以通过自定义验证标签或使用结构体标签控制验证行为。以下是解决方案:
1. 创建自定义验证标签
为更新操作添加omitempty验证标签:
type User struct {
ID uint32 `json:"id"`
FirstName string `json:"firstName" binding:"required,omitempty"`
LastName string `json:"lastName" binding:"omitempty"`
Email string `json:"email" binding:"required,email,uniqueModelValue=users email,omitempty"`
Active bool `json:"active"`
Password string `json:"password,omitempty" binding:"required,gte=8,omitempty"`
UserType string `json:"userType" binding:"oneof=admin backoffice principal staff parent student,omitempty"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
2. 使用ShouldBindJSON替代ShouldBind
在更新处理程序中使用ShouldBindJSON并配合binding:"-"标签:
type UserUpdate struct {
FirstName string `json:"firstName" binding:"-"`
LastName string `json:"lastName" binding:"-"`
Email string `json:"email" binding:"-"`
Active *bool `json:"active" binding:"-"`
Password string `json:"password,omitempty" binding:"-"`
UserType string `json:"userType" binding:"-"`
}
func Update(ctx *gin.Context) {
userID := ctx.Param("userId")
db, _ := database.GetDB()
// 获取现有用户
existingUser := models.User{}
if err := db.First(&existingUser, userID).Error; err != nil {
response.Error(ctx, err)
return
}
// 绑定更新数据
updateData := UserUpdate{}
if err := ctx.ShouldBindJSON(&updateData); err != nil {
response.Error(ctx, err)
return
}
// 手动更新非零值字段
if updateData.FirstName != "" {
existingUser.FirstName = updateData.FirstName
}
if updateData.LastName != "" {
existingUser.LastName = updateData.LastName
}
if updateData.Email != "" {
existingUser.Email = updateData.Email
}
if updateData.Active != nil {
existingUser.Active = *updateData.Active
}
if updateData.Password != "" {
existingUser.Password = updateData.Password
}
if updateData.UserType != "" {
existingUser.UserType = updateData.UserType
}
// 保存更新
if err := db.Save(&existingUser).Error; err != nil {
response.Error(ctx, err)
return
}
// 从响应中移除密码
existingUser.Password = ""
response.Success(ctx, existingUser)
}
3. 使用map[string]interface{}进行部分更新
func Update(ctx *gin.Context) {
userID := ctx.Param("userId")
db, _ := database.GetDB()
// 获取现有用户
existingUser := models.User{}
if err := db.First(&existingUser, userID).Error; err != nil {
response.Error(ctx, err)
return
}
// 使用map接收更新数据
updateData := make(map[string]interface{})
if err := ctx.ShouldBindJSON(&updateData); err != nil {
response.Error(ctx, err)
return
}
// 移除不应更新的字段
delete(updateData, "id")
delete(updateData, "createdAt")
delete(updateData, "updatedAt")
// 如果密码为空,移除密码字段
if password, ok := updateData["password"]; ok && password == "" {
delete(updateData, "password")
}
// 执行更新
if err := db.Model(&existingUser).Updates(updateData).Error; err != nil {
response.Error(ctx, err)
return
}
// 重新查询获取完整数据
db.First(&existingUser, userID)
existingUser.Password = ""
response.Success(ctx, existingUser)
}
4. 使用指针字段处理可选更新
type User struct {
ID uint32 `json:"id"`
FirstName *string `json:"firstName,omitempty" binding:"required"`
LastName *string `json:"lastName,omitempty"`
Email *string `json:"email,omitempty" binding:"required,email,uniqueModelValue=users email"`
Active *bool `json:"active,omitempty"`
Password *string `json:"password,omitempty" binding:"required,gte=8"`
UserType *string `json:"userType,omitempty" binding:"oneof=admin backoffice principal staff parent student"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
func Update(ctx *gin.Context) {
userID := ctx.Param("userId")
db, _ := database.GetDB()
// 获取现有用户
existingUser := models.User{}
if err := db.First(&existingUser, userID).Error; err != nil {
response.Error(ctx, err)
return
}
// 绑定更新数据
updateUser := models.User{}
if err := ctx.ShouldBindJSON(&updateUser); err != nil {
response.Error(ctx, err)
return
}
// 使用Updates自动处理指针字段
if err := db.Model(&existingUser).Updates(&updateUser).Error; err != nil {
response.Error(ctx, err)
return
}
// 重新查询获取完整数据
db.First(&existingUser, userID)
if existingUser.Password != nil {
existingUser.Password = nil
}
response.Success(ctx, existingUser)
}
这些方法允许你在创建和更新操作中使用同一结构体,同时处理更新时的可选字段验证问题。

