开始前的准备
1
| $ go get github.com/thedevsaddam/govalidator
|
简单好用的go验证包,可以自定义验证规则和错误信息
创建controller
app/http/controllers/api/v1/base_api_controller.go
1 2
| type BaseController struct { }
|
和前面一样,先创建一个Controller基类
app/http/controllers/api/v1/auth/signup_controller.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| type SignupController struct { v1.BaseController }
func (sc *SignupController) IsPhoneExist(c *gin.Context) {
request := requests.SignupPhoneExistRequest{}
if err := c.ShouldBindJSON(&request); err != nil { c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{ "error": err.Error(), })
fmt.Println(err.Error())
return }
errs := requests.ValidateSignupPhoneExist(&request, c)
if len(errs) > 0 { c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{ "error": errs, }) return }
c.JSON(http.StatusOK, gin.H{ "exist": user.IsPhoneExist(request.Phone), }) }
func (sc *SignupController) IsEmailExist(c *gin.Context) {
request := requests.SignupEmailExistRequest{}
if err := c.ShouldBindJSON(&request); err != nil { c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{ "error": err.Error(), }) fmt.Println(err.Error()) return }
errs := requests.ValidateSignupEmailExist(&request, c) if len(errs) > 0 { c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{ "errors": errs, }) return }
c.JSON(http.StatusOK, gin.H{ "exist": user.IsEmailExist(request.Email), }) }
|
部分验证包中的结构体和相关函数还未创建
控制器中的逻辑:
- 解析前端的数据到用户模型
- 验证这些数据是否符合规范
- 从数据库检查数据是否已经存在
ShouldBindJSON
把上下文中的json信息解析到结构体中
创建验证函数
app/requests/signup_request.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| type SignupPhoneExistRequest struct { Phone string `json:"phone,omitempty" valid:"phone"` }
func ValidateSignupPhoneExist(data interface{}, c *gin.Context) map[string][]string { rules := govalidator.MapData{ "phone": []string{"required", "digits:11"}, }
messages := govalidator.MapData{ "phone": []string{ "required:手机号为必填项,参数名称 phone", "digits:手机号长度必须为 11 位的数字", }, }
opts := govalidator.Options{ Data: data, Rules: rules, TagIdentifier: "valid", Messages: messages, }
return govalidator.New(opts).ValidateStruct() }
|
定制自己所需的验证信息,最后返回的错误信息保存在一个map中
验证邮箱的代码与验证手机类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| type SignupEmailExistRequest struct { Email string `json:"email,omitempty" valid:"email"` }
func ValidateSignupEmailExist(data interface{}, c *gin.Context) map[string][]string {
rules := govalidator.MapData{ "email": []string{"required", "min:4", "max:30", "email"}, }
messages := govalidator.MapData{ "email": []string{ "required:Email 为必填项", "min:Email 长度需大于 4", "max:Email 长度需小于 30", "email:Email 格式不正确,请提供有效的邮箱地址", }, }
opts := govalidator.Options{ Data: data, Rules: rules, TagIdentifier: "valid", Messages: messages, }
return govalidator.New(opts).ValidateStruct() }
|
通过这两个例子,我相信你可以大致理解这个包的用法,还是要提醒一点,在模仿代码过程中细节还是很容易出错的,你可以看看有没有以下问题
…
分配路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| v1 := router.Group("/v1") { v1.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "hello": "world", }) }) authGroup := v1.Group("/auth") { suc := new(auth.SignupController)
authGroup.POST("/signup/phone/exist", suc.IsPhoneExist) authGroup.POST("/signup/email/exist", suc.IsEmailExist) } }
|
测试
我们在apifox中创建这两个auth文件夹,然后把这两个接口都放在其中
这是一个长度只有10位的错误手机号,请求结果如下
我们向末尾多添加一个0,结果如下
之后我们可以在数据库中手动创建包含这个手机号的用户然后再尝试,这些测试就交给你们自己了