go语言web开发系列之三:gin用go-playground/validator做参数的校验

一,演示项目的相关信息

1,项目地址:

https://github.com/liuhongdi/digv03

2,功能说明:使用校验器(validator)实现对参数的校验

3,项目结构:如图:

说明:刘宏缔的go森林是一个专注golang的博客,
          地址:https://blog.csdn.net/weixin_43881017

说明:作者:刘宏缔 邮箱: 371125307@qq.com

二,sql说明

  1.  
    CREATE TABLE `article` (
  2.  
    `articleId` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  3.  
    `type` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '类型',
  4.  
    `subject` varchar(500) NOT NULL DEFAULT '' COMMENT '标题',
  5.  
    `addTime` datetime NOT NULL DEFAULT '2020-11-19 00:00:00' COMMENT '添加时间',
  6.  
    `isHot` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否热榜,0:非热,1,热',
  7.  
    `url` varchar(500) NOT NULL DEFAULT '' COMMENT '链接地址',
  8.  
    `domain` varchar(100) NOT NULL DEFAULT '' COMMENT '域',
  9.  
    `userId` bigint unsigned NOT NULL DEFAULT '0' COMMENT '推荐用户',
  10.  
    `approvalStaffId` int unsigned NOT NULL DEFAULT '0' COMMENT '批准员工',
  11.  
    `digSum` int unsigned NOT NULL DEFAULT '0' COMMENT '被顶的次数',
  12.  
    `commentSum` int unsigned NOT NULL DEFAULT '0' COMMENT '被评论的次数',
  13.  
    `isPublish` tinyint NOT NULL DEFAULT '0' COMMENT '0,未发布,1,已发布',
  14.  
    PRIMARY KEY (`articleId`),
  15.  
    KEY `isPublish` (`isPublish`)
  16.  
    ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='文章表'

插入6条演示数据:

  1.  
    INSERT INTO `article` (`articleId`, `type`, `subject`, `addTime`, `isHot`, `url`, `domain`, `userId`, `approvalStaffId`, `digSum`, `commentSum`, `isPublish`) VALUES
  2.  
    (1, 0, '【最近,南非发现一座大油田】石油和天然气两种重要资源是南非储量的最短板,“贫油”的帽子也一直扣在南非的头上摘不下来。可就在最近,在南非海域进行油气勘探已久的道达尔透露了其新的勘探成果:在距离南非南部海岸约175公里的奥特尼夸盆地的11B/12B地区,再次发现了重要的凝析气,可能蕴藏着大量天然气及原油。', '2020-11-19 00:00:00', 1, 'https://mp.weixin.qq.com/s/1btbmouH-2KuIHUMoucq2w', '', 1, 1, 0, 0, 1),
  3.  
    (2, 1, '让喵喵来开启周五的早晨吧!', '2020-11-19 00:00:00', 0, 'https://m.weibo.cn/status/4573112073720433?', 'm.weibo.cn', 0, 0, 0, 0, 1),
  4.  
    (3, 0, '汤姆·赫兰德、黛茜·雷德利、麦斯·米科尔森、尼克·乔纳斯主演的《混沌漫步》公开预告。影片由《明日边缘》导演道格·里曼执导,暂时定档明年1月22日上映。', '2020-11-19 00:00:00', 1, 'http://news.mtime.com/2020/11/19/1604795.html', 'news.mtime.com', 0, 0, 0, 0, 1),
  5.  
    (4, 1, '扫地机器人这个东西确实方便,大多数时候把房间扫的比较干净,但还有很多边边角角清扫不上,希望厂家能够在app上显示出机器人的路线图,明确告知哪些路段没有照顾到,要不然就再开发一个项目经理机器人,跟在扫地机器人屁股后面监督。//@大窑儿:可以弄个步数排行榜,让机器人们互相点赞,揣摩,攀比,内卷,无意义竞争。', '2020-11-19 00:00:00', 0, '', '', 0, 0, 0, 0, 1),
  6.  
    (5, 0, '【世卫组织建议医生不要使用瑞德西韦治疗新冠】世卫组织指导小组表示,证据显示,瑞德西韦对提高新冠肺炎患者的存活率没有显著影响。这项建议发表在上周五的《英国医学杂志》中。', '2020-11-19 00:00:00', 0, 'https://www.thepaper.cn/newsDetail_forward_10067542', 'thepaper.cn', 0, 0, 0, 0, 1),
  7.  
    (6, 0, '11月19日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增确诊病例17例,均为境外输入病例(福建6例,上海4例,陕西3例,广东2例,北京1例,四川1例);无新增死亡病例;新增疑似病例1例,为本土病例(在天津)。', '2020-11-19 00:00:00', 0, 'http://m.news.cctv.com/2020/11/20/ARTIIR9o72TuDF80s6hY2IvD201120.shtml', 'm.news.cctv.com', 0, 0, 0, 0, 1);

三,go代码说明

1,pkg/validCheck/convert.go

  1.  
    package validCheck
  2.  
     
  3.  
    import (
  4.  
    "strconv"
  5.  
    )
  6.  
     
  7.  
    type StrTo string
  8.  
     
  9.  
    func (s StrTo) String() string {
  10.  
    return string(s)
  11.  
    }
  12.  
     
  13.  
    func (s StrTo) Int() (int, error) {
  14.  
    v, err := strconv.Atoi(s.String())
  15.  
    return v, err
  16.  
    }
  17.  
     
  18.  
    func (s StrTo) MustInt() int {
  19.  
    v, _ := s.Int()
  20.  
    return v
  21.  
    }
  22.  
     
  23.  
    func (s StrTo) UInt32() (uint32, error) {
  24.  
    v, err := strconv.Atoi(s.String())
  25.  
    return uint32(v), err
  26.  
    }
  27.  
     
  28.  
    func (s StrTo) UInt64() (uint64, error) {
  29.  
    v, err := strconv.Atoi(s.String())
  30.  
    return uint64(v), err
  31.  
    }
  32.  
     
  33.  
    func (s StrTo) MustUInt32() uint32 {
  34.  
    curInt32, _ := strconv.Atoi(s.String())
  35.  
    if (curInt32 < 0) {
  36.  
    return 0;
  37.  
    }
  38.  
    v, _ := s.UInt32()
  39.  
    return v
  40.  
    }
  41.  
     
  42.  
    func (s StrTo) MustUInt64() uint64 {
  43.  
    //fmt.Println(s)
  44.  
    curInt64, _ := strconv.ParseInt(s.String(), 10, 64);
  45.  
    if (curInt64 < 0) {
  46.  
    return 0;
  47.  
    }
  48.  
    v, _ := s.UInt64()
  49.  
    //fmt.Println(v)
  50.  
    return v
  51.  
    }

2,pkg/validCheck/requestValid.go

  1.  
    package validCheck
  2.  
     
  3.  
    import (
  4.  
    "github.com/gin-gonic/gin"
  5.  
    ut "github.com/go-playground/universal-translator"
  6.  
    val "github.com/go-playground/validator/v10"
  7.  
    "strings"
  8.  
    )
  9.  
     
  10.  
    type ValidError struct {
  11.  
    Key string
  12.  
    Message string
  13.  
    }
  14.  
     
  15.  
    type ValidErrors []*ValidError
  16.  
     
  17.  
    func (v *ValidError) Error() string {
  18.  
    return v.Message
  19.  
    }
  20.  
     
  21.  
    func (v ValidErrors) Error() string {
  22.  
    return strings.Join(v.Errors(), ",")
  23.  
    }
  24.  
     
  25.  
    func (v ValidErrors) Errors() []string {
  26.  
    var errs []string
  27.  
    for _, err := range v {
  28.  
    errs = append(errs, err.Error())
  29.  
    }
  30.  
     
  31.  
    return errs
  32.  
    }
  33.  
    //判断变量是否符合要求
  34.  
    func BindAndValid(c *gin.Context, v interface{}) (bool, ValidErrors) {
  35.  
    var errs ValidErrors
  36.  
    err := c.ShouldBind(v)
  37.  
    if err != nil {
  38.  
    v := c.Value("trans")
  39.  
    trans, _ := v.(ut.Translator)
  40.  
    verrs, ok := err.(val.ValidationErrors)
  41.  
    if !ok {
  42.  
    errs = append(errs, &ValidError{
  43.  
    Key: "field",
  44.  
    Message: err.Error(),
  45.  
    })
  46.  
    return false, errs
  47.  
    }
  48.  
    for key, value := range verrs.Translate(trans) {
  49.  
    errs = append(errs, &ValidError{
  50.  
    Key: key,
  51.  
    Message: value,
  52.  
    })
  53.  
    }
  54.  
     
  55.  
    return false, errs
  56.  
    }
  57.  
    return true, nil
  58.  
    }

3,request/article.go

  1.  
    package request
  2.  
     
  3.  
    type ArticleRequest struct {
  4.  
    ID uint64 `form:"id" binding:"required,gte=1"`
  5.  
    //State uint8 `form:"state,default=1" binding:"oneof=0 1"`
  6.  
    }
  7.  
     
  8.  
    type ArticleListRequest struct {
  9.  
    Page int `form:"page" binding:"gte=1"`
  10.  
    //State uint8 `form:"state,default=1" binding:"oneof=0 1"`
  11.  
    }

说明:验证的规则写在这里

4,controller/articleController.go

  1.  
    package controller
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    "github.com/gin-gonic/gin"
  6.  
    "github.com/liuhongdi/digv03/global"
  7.  
    "github.com/liuhongdi/digv03/pkg/page"
  8.  
    "github.com/liuhongdi/digv03/pkg/validCheck"
  9.  
    "github.com/liuhongdi/digv03/request"
  10.  
    "github.com/liuhongdi/digv03/service"
  11.  
    )
  12.  
     
  13.  
    type ArticleController struct{}
  14.  
     
  15.  
    func NewArticleController() ArticleController {
  16.  
    return ArticleController{}
  17.  
    }
  18.  
    //得到一篇文章的详情
  19.  
    func (a *ArticleController) GetOne(c *gin.Context) {
  20.  
    result := global.NewResult(c)
  21.  
    param := request.ArticleRequest{ID: validCheck.StrTo(c.Param("id")).MustUInt64()}
  22.  
    valid, errs := validCheck.BindAndValid(c, &param)
  23.  
    if !valid {
  24.  
    result.Error(400,errs.Error())
  25.  
    return
  26.  
    }
  27.  
     
  28.  
    articleOne,err := service.GetOneArticle(param.ID);
  29.  
    if err != nil {
  30.  
    result.Error(404,"数据查询错误")
  31.  
    } else {
  32.  
    result.Success(&articleOne);
  33.  
    }
  34.  
    return
  35.  
    }
  36.  
     
  37.  
    //得到多篇文章,按分页返回
  38.  
    func (a *ArticleController) GetList(c *gin.Context) {
  39.  
    result := global.NewResult(c)
  40.  
    pageInt := 0
  41.  
    //is exist?
  42.  
    curPage := c.Query("page")
  43.  
    //if curPage not exist
  44.  
    if (len(curPage) == 0) {
  45.  
    pageInt = 1
  46.  
    } else {
  47.  
    param := request.ArticleListRequest{Page: validCheck.StrTo(c.Param("page")).MustInt()}
  48.  
    valid, errs := validCheck.BindAndValid(c, &param)
  49.  
    if !valid {
  50.  
    result.Error(400,errs.Error())
  51.  
    return
  52.  
    }
  53.  
    pageInt = param.Page
  54.  
    }
  55.  
     
  56.  
    pageSize := 2;
  57.  
    pageOffset := (pageInt-1) * pageSize
  58.  
     
  59.  
    articles,err := service.GetArticleList(pageOffset,pageSize)
  60.  
    if err != nil {
  61.  
    result.Error(404,"数据查询错误");
  62.  
    fmt.Println(err.Error())
  63.  
    } else {
  64.  
    //sum,_ := dao.SelectcountAll()
  65.  
    sum,_ := service.GetArticleSum()
  66.  
    pageInfo,_ := page.GetPageInfo(pageInt,pageSize,sum)
  67.  
    result.Success(gin.H{"list":&articles,"pageinfo":pageInfo});
  68.  
    }
  69.  
    return
  70.  
    }

四,测试

1,正常访问:

http://127.0.0.1:8080/article/getone/1

返回:

2,输入非法数据:

http://127.0.0.1:8080/article/getone/a

返回:

五,查看库的版本

  1.  
    module github.com/liuhongdi/digv03
  2.  
     
  3.  
    go 1.15
  4.  
     
  5.  
    require (
  6.  
    github.com/gin-gonic/gin v1.6.3
  7.  
    github.com/go-playground/universal-translator v0.17.0
  8.  
    github.com/go-playground/validator/v10 v10.2.0
  9.  
    github.com/jinzhu/gorm v1.9.16
  10.  
    )
原文地址:https://www.cnblogs.com/ExMan/p/14312168.html