W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
雖然?gvalid
?已經(jīng)內(nèi)置了常見的數(shù)十種校驗(yàn)規(guī)則,但是在部分業(yè)務(wù)場景下我們需要自定義校驗(yàn)規(guī)則,特別是一些可以重復(fù)使用的業(yè)務(wù)相關(guān)的校驗(yàn)規(guī)則。當(dāng)然,?gvalid
?如此的強(qiáng)大和貼心,她已經(jīng)為您考慮得如此周全。自定義校驗(yàn)規(guī)則可以實(shí)現(xiàn)靈活性強(qiáng),可復(fù)用性高的校驗(yàn)特性。
自定義規(guī)則方法定義,以及對應(yīng)的輸入?yún)?shù)數(shù)據(jù)結(jié)構(gòu)。
// RuleFuncInput holds the input parameters that passed to custom rule function RuleFunc.
type RuleFuncInput struct {
// Rule specifies the validation rule string, like "required", "between:1,100", etc.
Rule string
// Message specifies the custom error message or configured i18n message for this rule.
Message string
// Value specifies the value for this rule to validate.
Value *gvar.Var
// Data specifies the `data` which is passed to the Validator. It might be a type of map/struct or a nil value.
// You can ignore the parameter `Data` if you do not really need it in your custom validation rule.
Data *gvar.Var
}
// RuleFunc is the custom function for data validation.
type RuleFunc func(ctx context.Context, in RuleFuncInput) error
方法參數(shù)簡要說明:
ctx
?是必須的。RuleFuncInput
?數(shù)據(jù)結(jié)構(gòu)說明:Rule
?表示當(dāng)前的校驗(yàn)規(guī)則,包含規(guī)則的參數(shù),例如:?required
?, ?between:1,100
?, ?length:6
?等等。Message
?參數(shù)表示在校驗(yàn)失敗后返回的校驗(yàn)錯(cuò)誤提示信息。Value
?參數(shù)表示被校驗(yàn)的數(shù)據(jù)值,注意類型是一個(gè)?*gvar.Var
?泛型,因此您可以傳遞任意類型的參數(shù)。Data
?參數(shù)表示校驗(yàn)時(shí)傳遞的參數(shù),例如校驗(yàn)的是一個(gè)?map
?或者?struct
?時(shí),往往在聯(lián)合校驗(yàn)時(shí)有用。需要注意的是,這個(gè)值是運(yùn)行時(shí)輸入的,值可能是?nil
?。自定義錯(cuò)誤默認(rèn)情況下已支持?i18n
?特性,因此您只需要按照 ?gf.gvalid.rule.自定義規(guī)則名稱
? 配置?i18n
?轉(zhuǎn)譯信息即可,該信息在校驗(yàn)失敗時(shí)會自動從?i18n
?管理器獲取后,通過?Message
?參數(shù)傳入給您注冊的自定義校驗(yàn)方法中。
自定義規(guī)則分為兩種:全局規(guī)則注冊和局部規(guī)則注冊。
全局規(guī)則是全局生效的規(guī)則,注冊之后無論是使用方法還是對象來執(zhí)行數(shù)據(jù)校驗(yàn)都可以使用自定義的規(guī)則。
注冊校驗(yàn)方法:
// RegisterRule registers custom validation rule and function for package.
func RegisterRule(rule string, f RuleFunc) {
customRuleFuncMap[rule] = f
}
// RegisterRuleByMap registers custom validation rules using map for package.
func RegisterRuleByMap(m map[string]RuleFunc) {
for k, v := range m {
customRuleFuncMap[k] = v
}
}
您需要按照?RuleFunc
?類型的方法定義,實(shí)現(xiàn)一個(gè)您需要的校驗(yàn)方法,隨后使用?RegisterRule
?注冊到?gvalid
?模塊中全局管理。該注冊邏輯往往是在程序初始化時(shí)執(zhí)行。該方法在對數(shù)據(jù)進(jìn)行校驗(yàn)時(shí)將會被自動調(diào)用,方法返回?nil
?表示校驗(yàn)通過,否則應(yīng)當(dāng)返回一個(gè)非空的?error
?類型值。
注意事項(xiàng):自定義規(guī)則的注冊方法不支持并發(fā)調(diào)用,您需要在程序啟動時(shí)進(jìn)行注冊(例如在?boot
?包中處理),無法在運(yùn)行時(shí)動態(tài)注冊,否則會產(chǎn)生并發(fā)安全問題。
在電商業(yè)務(wù)中,當(dāng)我們對訂單進(jìn)行操作時(shí),可以通過自定義規(guī)則校驗(yàn)給定的訂單?ID
?是否存在,因此我們可以注冊一個(gè)?order-exist
?的全局規(guī)則來實(shí)現(xiàn)。
package main
import (
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/util/gvalid"
"time"
)
type Request struct {
OrderId int64
ProductName string
Amount int64
// ...
}
func init() {
rule := "order-exist"
gvalid.RegisterRule(rule, RuleOrderExist)
}
func RuleOrderExist(ctx context.Context, in gvalid.RuleFuncInput) error {
// SELECT COUNT(*) FROM `order` WHERE `id` = xxx
count, err := g.Model("order").
Ctx(ctx).
Cache(gdb.CacheOption{
Duration: time.Hour,
Name: "",
Force: false,
}).
WhereNot("id", in.Value.Int64()).
Count()
if err != nil {
return err
}
if count == 0 {
return gerror.Newf(`invalid order id "%d"`, in.Value.Int64())
}
return nil
}
func main() {
var (
ctx = gctx.New()
req = &Request{
OrderId: 65535,
ProductName: "HikingShoe",
Amount: 10000,
}
)
err := g.Validator().CheckStruct(ctx, req)
fmt.Println(err)
}
在用戶注冊時(shí),我們往往需要校驗(yàn)當(dāng)前用戶提交的名稱/賬號是否唯一,因此我們可以注冊一個(gè)??unique-nam?e
?的全局規(guī)則來實(shí)現(xiàn)。
package main
import (
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/util/gvalid"
"time"
)
type User struct {
Id int
Name string `v:"required|unique-name#請輸入用戶名稱|用戶名稱已被占用"`
Pass string `v:"required|length:6,18"`
}
func init() {
rule := "unique-name"
gvalid.RegisterRule(rule, RuleUniqueName)
}
func RuleUniqueName(ctx context.Context, in gvalid.RuleFuncInput) error {
var user *User
if err := in.Data.Scan(&user); err != nil {
return gerror.Wrap(err, `Scan data to user failed`)
}
// SELECT COUNT(*) FROM `user` WHERE `id` != xxx AND `name` != xxx
count, err := g.Model("user").
Ctx(ctx).
Cache(gdb.CacheOption{
Duration: time.Hour,
Name: "",
Force: false,
}).
WhereNot("id", user.Id).
WhereNot("name", user.Name).
Count()
if err != nil {
return err
}
if count > 0 {
if in.Message != "" {
return gerror.New(in.Message)
}
return gerror.Newf(`user name "%s" is already token by others`, user.Name)
}
return nil
}
func main() {
var (
ctx = gctx.New()
user = &User{
Id: 1,
Name: "john",
Pass: "123456",
}
)
err := g.Validator().CheckStruct(ctx, user)
fmt.Println(err)
}
局部規(guī)則是僅在當(dāng)前校驗(yàn)對象下生效規(guī)則,校驗(yàn)規(guī)則是注冊到當(dāng)前使用的鏈?zhǔn)讲僮髁鞒讨卸皇侨种小?
注冊方法:
// RuleFunc registers one custom rule function to current Validator.
func (v *Validator) RuleFunc(rule string, f RuleFunc) *Validator
// RuleFuncMap registers multiple custom rule functions to current Validator.
func (v *Validator) RuleFuncMap(m map[string]RuleFunc) *Validator
簡要介紹:
RuleFunc
?方法用于注冊單個(gè)自定義校驗(yàn)規(guī)則到當(dāng)前對象。
RuleFuncMap
?方法用于注冊多個(gè)自定義校驗(yàn)規(guī)則到當(dāng)前對象。
使用示例:
我們將上面其中一個(gè)例子改為局部校驗(yàn)規(guī)則注冊。
package main
import (
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/util/gvalid"
"time"
)
type Request struct {
OrderId int64
ProductName string
Amount int64
// ...
}
func RuleOrderExist(ctx context.Context, in gvalid.RuleFuncInput) error {
// SELECT COUNT(*) FROM `order` WHERE `id` = xxx
count, err := g.Model("order").
Ctx(ctx).
Cache(gdb.CacheOption{
Duration: time.Hour,
Name: "",
Force: false,
}).
WhereNot("id", in.Value.Int64()).
Count()
if err != nil {
return err
}
if count == 0 {
return gerror.Newf(`invalid order id "%d"`, in.Value.Int64())
}
return nil
}
func main() {
var (
ctx = gctx.New()
req = &Request{
OrderId: 65535,
ProductName: "HikingShoe",
Amount: 10000,
}
)
err := g.Validator().RuleFunc("order-exist", RuleOrderExist).Data(req).Run(ctx)
fmt.Println(err)
}
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: