概述

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

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

解决方案:

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

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

Default()

func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}

New() 代码我就不贴了。

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

开始今天的文章。

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

直接看代码吧。

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

entity/member.go

package entity

// 定义 Member 结构体
type Member struct {
Name string `form:"name" json:"name" binding:"required,NameValid"`
Age int `form:"age" json:"age" binding:"required,gt=10,lt=120"`
}

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

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

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

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

validator/member/member.go

package member

import (
"gopkg.in/go-playground/validator.v8"
"reflect"
) func NameValid(
v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
if s, ok := field.Interface().(string); ok {
if s == "admin" {
return false
}
}
return true
}

接下来,在路由中绑定:

router/router.go

package router

import (
"ginDemo/middleware/logger"
"ginDemo/middleware/sign"
"ginDemo/router/v1"
"ginDemo/router/v2"
"ginDemo/validator/member"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"gopkg.in/go-playground/validator.v8"
) func InitRouter(r *gin.Engine) { r.Use(logger.LoggerToFile()) // v1 版本
GroupV1 := r.Group("/v1")
{
GroupV1.Any("/product/add", v1.AddProduct)
GroupV1.Any("/member/add", v1.AddMember)
} // v2 版本
GroupV2 := r.Group("/v2").Use(sign.Sign())
{
GroupV2.Any("/product/add", v2.AddProduct)
GroupV2.Any("/member/add", v2.AddMember)
} // 绑定验证器
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("NameValid", member.NameValid)
}
}

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

router/v1/member.go

package v1

import (
"ginDemo/entity"
"github.com/gin-gonic/gin"
"net/http"
) func AddMember(c *gin.Context) { res := entity.Result{}
mem := entity.Member{} if err := c.ShouldBind(&mem); err != nil {
res.SetCode(entity.CODE_ERROR)
res.SetMessage(err.Error())
c.JSON(http.StatusForbidden, res)
c.Abort()
return
} // 处理业务(下次再分享) data := map[string]interface{}{
"name" : mem.Name,
"age" : mem.Age,
}
res.SetCode(entity.CODE_ERROR)
res.SetData(data)
c.JSON(http.StatusOK, res)
}

访问看看效果吧。

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

{
"code": -1,
"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",
"data": null
}

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

{
"code": -1,
"msg": "Key: 'Member.Age' Error:Field validation for 'Age' failed on the 'required' tag",
"data": null
}

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

{
"code": -1,
"msg": "Key: 'Member.Age' Error:Field validation for 'Age' failed on the 'required' tag",
"data": null
}

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

{
"code": -1,
"msg": "Key: 'Member.Name' Error:Field validation for 'Name' failed on the 'NameValid' tag",
"data": null
}

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

{
"code": -1,
"msg": "Key: 'Member.Age' Error:Field validation for 'Age' failed on the 'gt' tag",
"data": null
}

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

{
"code": -1,
"msg": "Key: 'Member.Age' Error:Field validation for 'Age' failed on the 'lt' tag",
"data": null
}

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

{
"code": 1,
"msg": "",
"data": {
"age": 30,
"name": "Tom"
}
}

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

if err := c.ShouldBind(&mem); err != nil {
res.SetCode(entity.CODE_ERROR)
res.SetMessage("参数验证错误")
c.JSON(http.StatusForbidden, res)
c.Abort()
return
}

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

├─ ginDemo
│ ├─ common //公共方法
│ ├── common.go
│ ├─ config //配置文件
│ ├── config.go
│ ├─ entity //实体
│ ├── ...
│ ├─ middleware //中间件
│ ├── logger
│ ├── ...
│ ├── sign
│ ├── ...
│ ├─ router //路由
│ ├── ...
│ ├─ validator //验证器
│ ├── ...
│ ├─ vendor //扩展包
│ ├── github.com
│ ├── ...
│ ├── golang.org
│ ├── ...
│ ├── gopkg.in
│ ├── ...
│ ├─ Gopkg.toml
│ ├─ Gopkg.lock
│ ├─ 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 框架

基础篇

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

[系列] Gin框架 - 数据绑定和验证的更多相关文章

  1. Gin框架 - 数据绑定和验证

    概述 上篇文章分享了 Gin 框架使用 Logrus 进行日志记录,这篇文章分享 Gin 框架的数据绑定与验证. 有读者咨询我一个问题,如何让框架的运行日志不输出控制台? 解决方案: engine : ...

  2. Gin框架 - 自定义错误处理

    目录 概述 错误处理 自定义错误处理 panic 和 recover 推荐阅读 概述 很多读者在后台向我要 Gin 框架实战系列的 Demo 源码,在这里再说明一下,源码我都更新到 GitHub 上, ...

  3. gin框架中的参数验证

    结构体验证 用gin框架的数据验证,可以不用解析数据,减少if else,会简洁许多. 处理请求方法 func structValidator(context *gin.Context) { var ...

  4. 基于gin框架和jwt-go中间件实现小程序用户登陆和token验证

    本文核心内容是利用jwt-go中间件来开发golang webapi用户登陆模块的token下发和验证,小程序登陆功能只是一个切入点,这套逻辑同样适用于其他客户端的登陆处理. 小程序登陆逻辑 小程序的 ...

  5. Gin框架系列03:换个姿势理解中间件

    什么是中间件 中间件,英译middleware,顾名思义,放在中间的物件,那么放在谁中间呢?本来,客户端可以直接请求到服务端接口. 现在,中间件横插一脚,它能在请求到达接口之前拦截请求,做一些特殊处理 ...

  6. gin框架教程:代码系列demo地址

    gin框架教程代码地址: https://github.com/jiujuan/gin-tutorial demo目录: 01quickstart 02parameter 03route 04midd ...

  7. Gin框架系列02:路由与参数

    回顾 上一节我们用Gin框架快速搭建了一个GET请求的接口,今天来学习路由和参数的获取. 请求动词 熟悉RESTful的同学应该知道,RESTful是网络应用程序的一种设计风格和开发方式,每一个URI ...

  8. gin框架学习手册

    前言 gin框架是go语言的一个框架,框架的github地址是:https://github.com/gin-gonic/gin 转载本文,请标注原文地址:https://www.cnblogs.co ...

  9. Golang语言系列-17-Gin框架

    Gin框架 Gin框架简介 package main import ( "github.com/gin-gonic/gin" "io" "net/ht ...

随机推荐

  1. 所有W版本的函数都在wchar.h文件(_wfopen),和stdlib.h文件(wcstombs),和stdio.h文件(vwprintf)

    C:\Qt\Qt5.6.2\Tools\mingw492_32\i686-w64-mingw32\include\wchar.h C:\Qt\Qt5.6.2\Tools\mingw492_32\i68 ...

  2. Qt给应用程序添加版本信息(对rc文件的设置,可利用QT内置变量)

    作者:daodaoliang 时间:2016年7月11日16:12:09 版本:V 0.0.4 邮箱:daodaoliang@yeah.net 0. 环境说明 系统环境: win10 64位 Qt环境 ...

  3. 使用VS2010开发Qt程序的4点经验(QT4到QT5的升级,更改sln文件,切换工程使用的Qt库,在VS的Solution Explorer视图中建立文件夹)

    导读 相比于Qt Creator,我更喜欢用VS2010来进行开发.虽然启动时间相对较慢,但是VS下强大的快捷键和丰富的插件,以及使用多年的经验,都让我觉得在开发过程中得心应手.其中最重要的一点是,有 ...

  4. Flutter学习笔记(2)--Dart语言简介

    Dart简介: Dart诞生于2011年10月10日,Dart是一种"结构化的web编程"语言,Dart虽然是谷歌开发的计算机编程语言,但后来被ECMA认定位标准,这门语言用于We ...

  5. jvm(4)---垃圾回收(哪些对象可以被回收)

    1.java堆中几乎放着所有对象的实例,那么什么样子的对象才是可以被回收的呢? 1.1.引用计数法: 给对象添加一个引用计数器,当有地方引用的时候,计数器就+1,引用失效就-1:任何时候当计数器为0, ...

  6. 「中高级前端必须了解的」JS中的内存管理

    前言 像C语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()用于分配内存和释放内存. 而对于JavaScript来说,会在创建变量(对象,字符串等)时分配内存,并且在不 ...

  7. Enum的简单扩展

    1 添加一个描述的Attribute public enum MessageResult { [System.ComponentModel.Description("未通过")] ...

  8. Qt实现炫酷启动图-动态进度条

    目录 一.简述 二.动效进度条 1.光效进度条 2.延迟到达进度条 3.接口说明 三.启动图 1.实现思路 2.背景图切换 四.测试 1.构造启动图 2.背景图 3.其他信息 4.事件循环 五.源码 ...

  9. JDK1.8集合之HashMap

    目录 简介 内部实现 类的属性 Node数组 重要方法 put()和putVal()方法 get()和getNode()方法 resize()方法 容量设置为2的幂的优点 计算Hash时候 扩容时候 ...

  10. 关于ffmpeg /iis 8.5 服务器下,视频截取第一帧参数配置

    ffmpeg 视频截取第一帧参数配置: 网站找了很多资料,但是都不能满足要求,然后自己写下解决过程. 首先看自己PHP 版本,安全选项里面 php5.4  跟php5.6 是不一样的.去除里面的sys ...