binding
和 msg
是结构体标签(struct tags),主要用于数据验证和错误信息提示。它们通常与 Gin 框架的 ShouldBindJSON
配合使用,以及用于处理表单验证。
下面详细解释:
- 基本用法示例:
type LoginForm struct {
Username string `json:"username" binding:"required" msg:"用户名不能为空"`
Password string `json:"password" binding:"required,min=6" msg:"密码不能为空且长度至少6位"`
Age int `json:"age" binding:"required,gte=18" msg:"年龄必须大于或等于18岁"`
Email string `json:"email" binding:"required,email" msg:"请输入有效的邮箱地址"`
}
- 在 Gin 中使用:
func Login(c *gin.Context) {
var form LoginForm
if err := c.ShouldBindJSON(&form); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 处理登录逻辑...
}
- 常用的 binding 验证规则:
type User struct {
// required: 必填
Name string `binding:"required"`
// min,max: 字符串长度或数字范围
Password string `binding:"min=6,max=20"`
// email: 邮箱格式
Email string `binding:"email"`
// oneof: 枚举值
Role string `binding:"oneof=admin user guest"`
// gte,lte: 大于等于,小于等于
Age int `binding:"gte=18,lte=100"`
// url: URL格式
Website string `binding:"url"`
// 正则表达式
Phone string `binding:"required,regexp=^1[3-9]\\d{9}$"`
}
- 自定义验证器:
type RegisterForm struct {
Password string `binding:"required,CustomPassword"`
Phone string `binding:"required,CustomPhone"`
}
func customValidator() {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 注册自定义验证器
v.RegisterValidation("CustomPassword", ValidatePassword)
v.RegisterValidation("CustomPhone", ValidatePhone)
}
}
func ValidatePassword(fl validator.FieldLevel) bool {
password := fl.Field().String()
// 自定义密码验证逻辑
return len(password) >= 8
}
- 使用 msg 标签自定义错误信息:
type CreateUserForm struct {
Username string `json:"username" binding:"required" msg:"用户名不能为空"`
Password string `json:"password" binding:"required,min=6" msg:"密码长度最少6位"`
}
// 处理错误信息的辅助函数
func getValidMsg(err error, obj interface{}) string {
// 通过反射获取 struct 类型
getObj := reflect.TypeOf(obj)
// 如果是指针,则获取其基础类型
if getObj.Kind() == reflect.Ptr {
getObj = getObj.Elem()
}
// 将错误信息转换为验证器错误
if errs, ok := err.(validator.ValidationErrors); ok {
// 遍历每一个错误
for _, e := range errs {
// 获取对应字段
if f, exist := getObj.FieldByName(e.Field()); exist {
// 获取 msg 标签内容
msg := f.Tag.Get("msg")
if msg != "" {
return msg
}
}
}
}
return err.Error()
}
- 在控制器中使用:
func CreateUser(c *gin.Context) {
var form CreateUserForm
if err := c.ShouldBindJSON(&form); err != nil {
// 获取自定义错误信息
errMsg := getValidMsg(err, form)
c.JSON(400, gin.H{"error": errMsg})
return
}
// 处理业务逻辑...
}
- 组合验证规则:
type Product struct {
// 多个验证规则用逗号分隔
Name string `binding:"required,min=2,max=50" msg:"产品名称长度必须在2-50之间"`
Price float64 `binding:"required,gte=0" msg:"价格必须大于或等于0"`
// 条件验证:当 Status 为 "active" 时,Description 必填
Status string `binding:"required,oneof=active inactive" msg:"状态必须是 active 或 inactive"`
Description string `binding:"required_if=Status active" msg:"当状态为active时,描述必填"`
}
- 跨字段验证:
type ChangePassword struct {
Password string `binding:"required" msg:"密码不能为空"`
ConfirmPassword string `binding:"required,eqfield=Password" msg:"两次输入的密码不一致"`
}
- 初始化验证器:
func InitValidator() {
// 注册验证器
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 注册自定义验证器
v.RegisterValidation("custom_validation", CustomValidationFunc)
// 注册自定义错误信息翻译器
zhTranslations.RegisterDefaultTranslations(v, trans)
}
}
这些标签主要用于:
- 数据验证(binding)
- 自定义错误信息(msg)
- 参数绑定
- 表单验证
- API 接口参数验证
通过合理使用这些标签,可以:
- 减少手动编写验证代码
- 提供更友好的错误提示
- 确保数据的完整性和有效性
- 提高代码的可维护性