Gin框架

梦想与她 提交于 2020-12-04 03:00:39

概述

上篇文章分享了 Gin 框架使用 Logrus 进行日志记录,这篇文章分享 Gin 框架的数据绑定与验证。

有读者咨询我一个问题,如何让框架的运行日志不输出控制台?

解决方案:

  
    
  
  
  1. engine := gin.Default() //修改成如下

  2. engine := gin.New()


我是怎么知道的?看框架代码。


Default()

  
    
  
  
  1. func Default() *Engine {

  2. debugPrintWARNINGDefault()

  3. engine := New()

  4. engine.Use(Logger(), Recovery())

  5. return engine

  6. }


New() 代码我就不贴了。

我们看到 Default() 使用了两个中间件 Logger(),Recovery(),如果不想使用,那就直接使用 New() 就可以了。


开始今天的文章。


比如,请求 v1/member/add 新增会员方法, nameage 为必填,同时 name 不能等于 admin 字符串,10 <= age <= 120。


直接看代码吧。


首先,先定义一个结构体。

entity/member.go

  
    
  
  
  1. package entity


  2. // 定义 Member 结构体

  3. type Member struct {

  4. Name string `form:"name" json:"name" binding:"required,NameValid"`

  5. Age int `form:"age" json:"age" binding:"required,gt=10,lt=120"`

  6. }


binding 中 required,这个是框架自带的, NameValid,这个是自己定义的。

问题一:框架自带的 binding 参数还有哪些?

问题二:自定义验证方法,怎么写?


接下来要说的就是问题二,写一个验证方法。

validator/member/member.go

  
    
  
  
  1. package member


  2. import (

  3. "gopkg.in/go-playground/validator.v8"

  4. "reflect"

  5. )


  6. func NameValid(

  7. v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,

  8. field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,

  9. ) bool {

  10. if s, ok := field.Interface().(string); ok {

  11. if s == "admin" {

  12. return false

  13. }

  14. }

  15. return true

  16. }


接下来,在路由中绑定:

router/router.go

  
    
  
  
  1. package router


  2. import (

  3. "ginDemo/middleware/logger"

  4. "ginDemo/middleware/sign"

  5. "ginDemo/router/v1"

  6. "ginDemo/router/v2"

  7. "ginDemo/validator/member"

  8. "github.com/gin-gonic/gin"

  9. "github.com/gin-gonic/gin/binding"

  10. "gopkg.in/go-playground/validator.v8"

  11. )


  12. func InitRouter(r *gin.Engine) {


  13. r.Use(logger.LoggerToFile())


  14. // v1 版本

  15. GroupV1 := r.Group("/v1")

  16. {

  17. GroupV1.Any("/product/add", v1.AddProduct)

  18. GroupV1.Any("/member/add", v1.AddMember)

  19. }


  20. // v2 版本

  21. GroupV2 := r.Group("/v2").Use(sign.Sign())

  22. {

  23. GroupV2.Any("/product/add", v2.AddProduct)

  24. GroupV2.Any("/member/add", v2.AddMember)

  25. }


  26. // 绑定验证器

  27. if v, ok := binding.Validator.Engine().(*validator.Validate); ok {

  28. v.RegisterValidation("NameValid", member.NameValid)

  29. }

  30. }


最后,看一下调用的代码。

router/v1/member.go

  
    
  
  
  1. package v1


  2. import (

  3. "ginDemo/entity"

  4. "github.com/gin-gonic/gin"

  5. "net/http"

  6. )


  7. func AddMember(c *gin.Context) {


  8. res := entity.Result{}

  9. mem := entity.Member{}


  10. if err := c.ShouldBind(&mem); err != nil {

  11. res.SetCode(entity.CODE_ERROR)

  12. res.SetMessage(err.Error())

  13. c.JSON(http.StatusForbidden, res)

  14. c.Abort()

  15. return

  16. }


  17. // 处理业务(下次再分享)


  18. data := map[string]interface{}{

  19. "name" : mem.Name,

  20. "age" : mem.Age,

  21. }

  22. res.SetCode(entity.CODE_ERROR)

  23. res.SetData(data)

  24. c.JSON(http.StatusOK, res)

  25. }


访问看看效果吧。

访问:http://localhost:8080/v1/member/add

  
    
  
  
  1. {

  2. "code": -1,

  3. "msg": "Key: 'Member.Name' Error:Field validation for 'Name' failed on the 'required' tag\nKey: 'Member.Age' Error:Field validation for 'Age' failed on the 'required' tag",

  4. "data": null

  5. }


访问:http://localhost:8080/v1/member/add?name=1

  
    
  
  
  1. {

  2. "code": -1,

  3. "msg": "Key: 'Member.Age' Error:Field validation for 'Age' failed on the 'required' tag",

  4. "data": null

  5. }


访问:http://localhost:8080/v1/member/add?age=1

  
    
  
  
  1. {

  2. "code": -1,

  3. "msg": "Key: 'Member.Age' Error:Field validation for 'Age' failed on the 'required' tag",

  4. "data": null

  5. }


访问:http://localhost:8080/v1/member/add?name=admin&age=1

  
    
  
  
  1. {

  2. "code": -1,

  3. "msg": "Key: 'Member.Name' Error:Field validation for 'Name' failed on the 'NameValid' tag",

  4. "data": null

  5. }


访问:http://localhost:8080/v1/member/add?name=1&age=1

  
    
  
  
  1. {

  2. "code": -1,

  3. "msg": "Key: 'Member.Age' Error:Field validation for 'Age' failed on the 'gt' tag",

  4. "data": null

  5. }


访问:http://localhost:8080/v1/member/add?name=1&age=121

  
    
  
  
  1. {

  2. "code": -1,

  3. "msg": "Key: 'Member.Age' Error:Field validation for 'Age' failed on the 'lt' tag",

  4. "data": null

  5. }


访问:http://localhost:8080/v1/member/add?name=Tom&age=30

  
    
  
  
  1. {

  2. "code": 1,

  3. "msg": "",

  4. "data": {

  5. "age": 30,

  6. "name": "Tom"

  7. }

  8. }


为避免返回信息过多,错误提示咱们也可以统一。

  
    
  
  
  1. if err := c.ShouldBind(&mem); err != nil {

  2. res.SetCode(entity.CODE_ERROR)

  3. res.SetMessage("参数验证错误")

  4. c.JSON(http.StatusForbidden, res)

  5. c.Abort()

  6. return

  7. }


这一次目录结构调整了一些,在这里说一下:

  
    
  
  
  1. ├─ ginDemo

  2. ├─ common //公共方法

  3. ├── common.go

  4. ├─ config //配置文件

  5. ├── config.go

  6. ├─ entity //实体

  7. ├── ...

  8. ├─ middleware //中间件

  9. ├── logger

  10. ├── ...

  11. ├── sign

  12. ├── ...

  13. ├─ router //路由

  14. ├── ...

  15. ├─ validator //验证器

  16. ├── ...

  17. ├─ vendor //扩展包

  18. ├── github.com

  19. ├── ...

  20. ├── golang.org

  21. ├── ...

  22. ├── gopkg.in

  23. ├── ...

  24. ├─ Gopkg.toml

  25. ├─ Gopkg.lock

  26. ├─ main.go


signlogger 调整为中间件,并放到 middleware 中间件 目录。

新增了 common 公共方法目录。

新增了 validator 验证器目录。

新增了 entity 实体目录。


具体代码我会放到 GitHub,有感兴趣的可以去看:https://github.com/xinliangnote/Go。


上面还遗漏了 问题一 没解决,框架自带的 binding 参数还有哪些?

从框架源码了解到验证使用的是:

gopkg.in/go-playground/validator.v8

文档地址为:

https://godoc.org/gopkg.in/go-playground/validator.v8

去探索文档吧,里面有很多验证规则。


推荐阅读

Gin 框架

基础篇

本文欢迎转发,转发请注明作者和出处,谢谢!

本文分享自微信公众号 - 新亮笔记(XinLiangTalk)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!