最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Gin框架中參數(shù)校驗(yàn)優(yōu)化詳解

 更新時(shí)間:2023年08月24日 08:37:13   作者:Coder慌  
這篇文章主要為大家詳細(xì)介紹了Gin框架中參數(shù)校驗(yàn)優(yōu)化的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下

原始方式

gin使用的是 github.com/go-playground/validator 該組件進(jìn)行入?yún)⑿r?yàn),如下是gin中常用的參數(shù)校驗(yàn)方式:

type AccountCreateForm struct {
    Id       uint64 `json:"id"`
    Name     string `json:"name" binding:"required,max=16"` // 使用required和max限制入?yún)楸靥铐?xiàng)與最大長(zhǎng)度不能超過16字符
    Username string `json:"username" binding:"required"`
    Password string `json:"password"`
}

該種方式有如下幾個(gè)不好使的地方:

錯(cuò)誤提示不友好,如果不做任何處理,默認(rèn)參數(shù)校驗(yàn)不通過會(huì)返回如下錯(cuò)誤提示

不支持正則表達(dá)式

不支持自定義錯(cuò)誤描述

改進(jìn)

自定義validatorx(validator擴(kuò)展工具包)

注冊(cè)翻譯器,新增對(duì)校驗(yàn)錯(cuò)誤進(jìn)行轉(zhuǎn)譯方法

package validatorx
import (
	"mayfly-go/pkg/utils/stringx"
	"mayfly-go/pkg/utils/structx"
	"reflect"
	"strings"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	zh_trans "github.com/go-playground/validator/v10/translations/zh"
)
const CustomMsgTagName = "msg"
var (
    trans ut.Translator
)
func Init() {
    // 獲取gin的校驗(yàn)器
    validate, ok := binding.Validator.Engine().(*validator.Validate)
    if !ok {
        return
    }
    // 修改返回字段key的格式
    validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
        // 如果存在校驗(yàn)錯(cuò)誤提示消息,則使用字段名,后續(xù)需要通過該字段名獲取相應(yīng)錯(cuò)誤消息
        if _, ok := fld.Tag.Lookup(CustomMsgTagName); ok {
            return fld.Name
        }
        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
        if name == "-" {
            return ""
        }
        return name
    })
    // 注冊(cè)翻譯器
    zh := zh.New()
    uni := ut.New(zh, zh)
    trans, _ = uni.GetTranslator("zh")
    // 注冊(cè)翻譯器
    zh_trans.RegisterDefaultTranslations(validate, trans)
    // 注冊(cè)自定義正則表達(dá)式校驗(yàn)器
    validate.RegisterValidation(CustomPatternTagName, patternValidFunc)
    // 注冊(cè)自定義正則校驗(yàn)規(guī)則
    RegisterCustomPatterns()
}
// Translate 翻譯錯(cuò)誤信息
func Translate(data any, err error) map[string][]string {
    var result = make(map[string][]string)
    errors := err.(validator.ValidationErrors)
    for _, err := range errors {
        fieldName := err.Field()
        // 判斷該字段是否設(shè)置了自定義的錯(cuò)誤描述信息,存在則使用自定義錯(cuò)誤信息進(jìn)行提示
        if field, ok := structx.IndirectType(reflect.TypeOf(data)).FieldByName(fieldName); ok {
            if errMsg, ok := field.Tag.Lookup(CustomMsgTagName); ok {
                customMsg := getCustomErrMsg(err.Tag(), errMsg)
                if customMsg != "" {
                    result[fieldName] = append(result[fieldName], customMsg)
                    continue
                }
            }
        }
        // 如果是自定義正則校驗(yàn)規(guī)則,則使用自定義的錯(cuò)誤描述信息
        if err.Tag() == CustomPatternTagName {
            result[fieldName] = append(result[fieldName], fieldName+patternErrMsg[err.Param()])
            continue
        }
        result[fieldName] = append(result[fieldName], err.Translate(trans))
    }
    return result
}
// 獲取自定義的錯(cuò)誤提示消息
//
// @param validTag 校驗(yàn)標(biāo)簽,如required等
// @param customMsg 自定義錯(cuò)誤消息
func getCustomErrMsg(validTag, customMsg string) string {
    // 解析 msg:"required=用戶名不能為空,min=用戶名長(zhǎng)度不能小于8位"
    msgs := strings.Split(customMsg, ",")
    for _, msg := range msgs {
        tagAndMsg := strings.Split(stringx.Trim(msg), "=")
        if len(tagAndMsg) > 1 && validTag == stringx.Trim(tagAndMsg[0]) {
            // 獲取valid tag對(duì)應(yīng)的錯(cuò)誤消息
            return stringx.Trim(tagAndMsg[1])
        }
    }
    return customMsg
}
// Translate 翻譯錯(cuò)誤信息為字符串
func Translate2Str(data any, err error) string {
    res := Translate(data, err)
    errMsgs := make([]string, 0)
    for _, v := range res {
        errMsgs = append(errMsgs, v...)
    }
    return strings.Join(errMsgs, ", ")
}

自定義正則表達(dá)式校驗(yàn)方式

package validatorx
import (
	"mayfly-go/pkg/global"
	"regexp"
	"github.com/go-playground/validator/v10"
)
const CustomPatternTagName = "pattern"
var (
	regexpMap     map[string]*regexp.Regexp  // key:正則表達(dá)式名稱   value:正則表達(dá)式
	patternErrMsg map[string]string         // key:正則表達(dá)式名稱   value:校驗(yàn)不通過時(shí)的錯(cuò)誤消息提示
)
// 注冊(cè)自定義正則表達(dá)式校驗(yàn)規(guī)則
func RegisterCustomPatterns() {
	// 賬號(hào)用戶名校驗(yàn),使用該種方式可以復(fù)用正則表達(dá)式以及錯(cuò)誤提示
    // 使用方式如:Username string `json:"username" binding:"pattern=account_username"`
	RegisterPattern("account_username", "^[a-zA-Z0-9_]{5,20}$", "只允許輸入5-20位大小寫字母、數(shù)字、下劃線")
}
// 注冊(cè)自定義正則表達(dá)式
func RegisterPattern(patternName string, regexpStr string, errMsg string) {
	if regexpMap == nil {
		regexpMap = make(map[string]*regexp.Regexp, 0)
		patternErrMsg = make(map[string]string)
	}
	regexpMap[patternName] = regexp.MustCompile(regexpStr)
	patternErrMsg[patternName] = errMsg
}
// 自定義正則表達(dá)式校驗(yàn)器函數(shù)
func patternValidFunc(f validator.FieldLevel) bool {
	reg := regexpMap[f.Param()]
	if reg == nil {
		global.Log.Warnf("%s的正則校驗(yàn)規(guī)則不存在!", f.Param())
		return false
	}
	return reg.MatchString(f.Field().String())
}

錯(cuò)誤轉(zhuǎn)譯

對(duì)入?yún)⑦M(jìn)行校驗(yàn),檢驗(yàn)不通過時(shí)將錯(cuò)誤進(jìn)行轉(zhuǎn)譯,轉(zhuǎn)譯為漢字或自定義的錯(cuò)誤描述等。

// 綁定并校驗(yàn)請(qǐng)求結(jié)構(gòu)體參數(shù)
func BindJsonAndValid[T any](g *gin.Context, data T) T {
    if err := g.ShouldBindJSON(data); err != nil {
        // 統(tǒng)一recover處理
        panic(ConvBindValidationError(data, err))
    } else {
        return data
    }
}
// 綁定請(qǐng)求體中的json至form結(jié)構(gòu)體,并拷貝至另一結(jié)構(gòu)體
func BindJsonAndCopyTo[T any](g *gin.Context, form any, toStruct T) T {
	BindJsonAndValid(g, form)
	structx.Copy(toStruct, form)
	return toStruct
}
// 轉(zhuǎn)譯參數(shù)校驗(yàn)錯(cuò)誤,并將參數(shù)校驗(yàn)錯(cuò)誤為業(yè)務(wù)異常錯(cuò)誤(統(tǒng)一recover處理)
func ConvBindValidationError(data any, err error) error {
    if e, ok := err.(validator.ValidationErrors); ok {
        // 調(diào)用validatorx.Translate2Str方法進(jìn)行校驗(yàn)錯(cuò)誤轉(zhuǎn)譯
        return biz.NewBizErrCode(403, validatorx.Translate2Str(data, e))
    }
    return err
}
// 返回失敗結(jié)果集
func ErrorRes(g *gin.Context, err any) {
    switch t := err.(type) {
    case biz.BizError:
        g.JSON(http.StatusOK, model.Error(t))
    case error:
        g.JSON(http.StatusOK, model.ServerError())
        global.Log.Errorf("%s\n%s", t.Error(), string(debug.Stack()))
    case string:
        g.JSON(http.StatusOK, model.ServerError())
        global.Log.Errorf("%s\n%s", t, string(debug.Stack()))
    default:
        global.Log.Error(t)
    }
}

初始化校驗(yàn)器

項(xiàng)目啟動(dòng)時(shí),在合適的時(shí)機(jī)初始化校驗(yàn)器

// 參數(shù)校驗(yàn)器初始化、如錯(cuò)誤提示中文轉(zhuǎn)譯、注冊(cè)自定義校驗(yàn)器等
validatorx.Init()

統(tǒng)一使用方式

入?yún)⒆侄蝨ag綁定

type AccountCreateForm struct {
    Id       uint64 `json:"id"`
    // msg tag里對(duì)應(yīng)的required max即為binding里的校驗(yàn)類型
    Name     string `json:"name" binding:"required,max=16" msg:"required=姓名不能為空,max=姓名最大長(zhǎng)度不能超過16位"`
    // account_name為validatorx.RegisterPattern("account_username", "^[a-zA-Z0-9_]{5,20}$", "只允許輸入5-20位大小寫字母、數(shù)字、下劃線")
    Username string `json:"username" binding:"pattern=account_username"`
    Password string `json:"password" binding:"required"`
}
form := &form.AccountCreateForm{}
// 校驗(yàn)不通過會(huì)自行panic統(tǒng)一recover處理
var account *entity.Account = ginx.BindJsonAndCopyTo(rc.GinCtx, form, new(entity.Account)) 

效果

更多代碼詳見:gitee.com/objs/mayfly-go一個(gè)web版 linux(終端[終端回放] 文件 腳本 進(jìn)程 計(jì)劃任務(wù))、數(shù)據(jù)庫(kù)(mysql postgres)、redis(單機(jī) 哨兵 集群)、mongo統(tǒng)一管理操作平臺(tái)

到此這篇關(guān)于Gin框架中參數(shù)校驗(yàn)優(yōu)化詳解的文章就介紹到這了,更多相關(guān)Gin參數(shù)校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 并發(fā)安全本地化存儲(chǔ)go-cache讀寫鎖實(shí)現(xiàn)多協(xié)程并發(fā)訪問

    并發(fā)安全本地化存儲(chǔ)go-cache讀寫鎖實(shí)現(xiàn)多協(xié)程并發(fā)訪問

    這篇文章主要介紹了并發(fā)安全本地化存儲(chǔ)go-cache讀寫鎖實(shí)現(xiàn)多協(xié)程并發(fā)訪問,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Golang?Mutex互斥鎖源碼分析

    Golang?Mutex互斥鎖源碼分析

    本篇文章,我們將一起來探究下Golang?Mutex底層是如何實(shí)現(xiàn)的,知其然,更要知其所以然。文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-10-10
  • 如何利用Go語言實(shí)現(xiàn)LRU?Cache

    如何利用Go語言實(shí)現(xiàn)LRU?Cache

    這篇文章主要介紹了如何利用Go語言實(shí)現(xiàn)LRU?Cache,LRU是Least?Recently?Used的縮寫,是一種操作系統(tǒng)中常用的頁(yè)面置換算法,下面我們一起進(jìn)入文章了解更多內(nèi)容吧,需要的朋友可以參考一下
    2022-03-03
  • Golang 類型轉(zhuǎn)換的實(shí)現(xiàn)(斷言、強(qiáng)制、顯式類型)

    Golang 類型轉(zhuǎn)換的實(shí)現(xiàn)(斷言、強(qiáng)制、顯式類型)

    將一個(gè)值從一種類型轉(zhuǎn)換到另一種類型,便發(fā)生了類型轉(zhuǎn)換,在go可以分為斷言、強(qiáng)制、顯式類型轉(zhuǎn)換,本文就詳細(xì)的介紹一下這就幾種轉(zhuǎn)換方式,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Gotify搭建你的消息推送系統(tǒng)

    Gotify搭建你的消息推送系統(tǒng)

    這篇文章主要介紹了Gotify搭建你的消息推送系統(tǒng),今天要分享的是 gotify,是一個(gè)用 go 編寫的消息服務(wù)端,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2024-01-01
  • go語言環(huán)境變量設(shè)置全過程

    go語言環(huán)境變量設(shè)置全過程

    這篇文章主要介紹了go語言環(huán)境變量設(shè)置全過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • PHP結(jié)構(gòu)型模式之組合模式

    PHP結(jié)構(gòu)型模式之組合模式

    這篇文章主要介紹了PHP組合模式Composite Pattern優(yōu)點(diǎn)與實(shí)現(xiàn),組合模式是一種結(jié)構(gòu)型模式,它允許你將對(duì)象組合成樹形結(jié)構(gòu)來表示“部分-整體”的層次關(guān)系。組合能讓客戶端以一致的方式處理個(gè)別對(duì)象和對(duì)象組合
    2023-04-04
  • go語言之給定英語文章統(tǒng)計(jì)單詞數(shù)量(go語言小練習(xí))

    go語言之給定英語文章統(tǒng)計(jì)單詞數(shù)量(go語言小練習(xí))

    這篇文章給大家分享go語言小練習(xí)給定英語文章統(tǒng)計(jì)單詞數(shù)量,實(shí)現(xiàn)思路大概是利用go語言的map類型,以每個(gè)單詞作為關(guān)鍵字存儲(chǔ)數(shù)量信息,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2020-01-01
  • Go 變長(zhǎng)參數(shù)函數(shù)的實(shí)現(xiàn)示例

    Go 變長(zhǎng)參數(shù)函數(shù)的實(shí)現(xiàn)示例

    本文主要介紹了Go語言中的變長(zhǎng)參數(shù)的類型、聲明、調(diào)用以及其在實(shí)際開發(fā)中的應(yīng)用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-04-04
  • 十個(gè)示例帶你深入了解Go語言中的接口

    十個(gè)示例帶你深入了解Go語言中的接口

    這篇文章主要是通過十個(gè)簡(jiǎn)單的示例帶大家深入了解一下Go語言中接口的使用,文中的示例代碼簡(jiǎn)潔易懂,具有一定的學(xué)習(xí)價(jià)值,需要的可以了解一下
    2023-02-02

最新評(píng)論

华宁县| 嵊州市| 溆浦县| 沐川县| 微山县| 屯留县| 弥勒县| 抚远县| 华蓥市| 上虞市| 阜康市| 武义县| 鄄城县| 色达县| 蓝田县| 龙岩市| 仲巴县| 兖州市| 若尔盖县| 财经| 长阳| 澜沧| 平昌县| 普安县| 翁源县| 二连浩特市| 徐汇区| 尉犁县| 中牟县| 青河县| 安康市| 张家港市| 高清| 惠水县| 商丘市| 油尖旺区| 太保市| 贡觉县| 会宁县| 淅川县| 汪清县|