go-zero结合自定义模版校验前端参数

一、自定义模版的使用

如果想对官网goctl命名生成的项目结构改变的话,可以使用模版,自定义模版,然后生成自己想要的文件

  • 1、使用命令将官方模版映射到本地

    goctl template init
    
  • 2、在项目的根目录下添加文件夹,把刚刚映射到本地的拷贝到项目中

    在这里插入图片描述

  • 3、使用模版根据api文件来生成go的文件

    # 注意这个地方要根据你当前路径来找到goctl文件夹
    goctl api go -api *api --dir . --style=goZero --home ../../goctl
    
  • 4、注意

    • goctl api go -api *.api -dir . --style=gozero可以根据api文件来生成项目,也是修改了api来更新项目
    • goctl api new user是创建一个userapi项目

二、使用go-playground对前端数据校验

  • 1、安装依赖包

    go get -u github.com/go-playground/validator/v10
    
  • 2、在translator.go文件中自定义将错误翻译成中文

    package utils
    
    import (
    	"errors"
    	"github.com/go-playground/locales/zh"
    	ut "github.com/go-playground/universal-translator"
    	"github.com/go-playground/validator/v10"
    	zhTranslations "github.com/go-playground/validator/v10/translations/zh"
    	"go_zero_demo05/common/utils/validators"
    	"reflect"
    	"strings"
    )
    
    func Validate(dataStruct interface{}) error {
    	zhT := zh.New()
    	validate := validator.New()
    	// 注册一个函数,获取struct tag里自定义的label作为字段名
    	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
    		name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
    		if name == "-" {
    			return ""
    		}
    		return name
    	})
    
    	uni := ut.New(zhT)
    	trans, _ := uni.GetTranslator("zh")
    	// 注册自定义结构体字段校验方法
    	// 1.注册时间要比当前的晚
    	if err := validate.RegisterValidation("checkAfterDate", validators.ValidateAfterDate); err != nil {
    		return err
    	}
    	if err := validate.RegisterTranslation(
    		"checkAfterDate",
    		trans,
    		registerTranslator("checkAfterDate", "{0} 必须要晚于当前日期"),
    		translate,
    	); err != nil {
    		return err
    	}
    	
    
    	// 验证器注册翻译器
    	if err := zhTranslations.RegisterDefaultTranslations(validate, trans); err != nil {
    		return err
    	}
    	err := validate.Struct(dataStruct)
    	if err != nil {
    		for _, err1 := range err.(validator.ValidationErrors) {
    			return errors.New(err1.Translate(trans))
    		}
    	}
    	return nil
    }
    
    // registerTranslator 为自定义字段添加翻译功能
    func registerTranslator(tag string, msg string) validator.RegisterTranslationsFunc {
    	return func(trans ut.Translator) error {
    		if err := trans.Add(tag, msg, false); err != nil {
    			return err
    		}
    		return nil
    	}
    }
    
    // translate 自定义字段的翻译方法
    func translate(trans ut.Translator, fe validator.FieldError) string {
    	msg, err := trans.T(fe.Tag(), fe.Field())
    	if err != nil {
    		panic(fe.(error).Error())
    	}
    	return msg
    }
    
  • 3、关于自定义校验方法

    package validators
    
    import (
    	"github.com/go-playground/validator/v10"
    	"time"
    )
    
    // ValidateAfterDate 判断时间是否是当前时间之后
    func ValidateAfterDate(fl validator.FieldLevel) bool {
    	date, err := time.Parse("2006-01-02", fl.Field().String())
    	if err != nil {
    		return false
    	}
    	if date.Before(time.Now()) {
    		return false
    	}
    	return true
    }
    
  • 4、自定义模版handler.tpl中添加前端参数校验的方法

    package {{.PkgName}}
    
    import (
    	"net/http"
    
    	"github.com/zeromicro/go-zero/rest/httpx"
    	{{.ImportPackages}}
    )
    
    func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
    	return func(w http.ResponseWriter, r *http.Request) {
    		{{if .HasRequest}}var req types.{{.RequestType}}
    		if err := httpx.Parse(r, &req); err != nil {
    			httpx.ErrorCtx(r.Context(), w, err)
                return
    		}
    		// 数据验证
            if validateErr := utils.Validate(&req);validateErr != nil {
                httpx.ErrorCtx(r.Context(), w, validateErr)
                return
            }
    		{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
    		{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
    		if err != nil {
                httpx.ErrorCtx(r.Context(), w, err)
            } else {
                {{if .HasResp}}httpx.OkJsonCtx(r.Context(), w, resp){{else}}httpx.Ok(w){{end}}
            }
    	}
    }
    
  • 5、在定义api的时候加上参数校验

    type PostDemoReq {
    	Name string `json:"name" validate:"required"` // 姓名
    	Age  int64  `json:"age" validate:"required,gte=1,lte=130"` // 年龄
    	// optional 表示可选,omitempty如果为空的时候不走后面
    	Mobile         string `json:"mobile,optional" validate:"omitempty,checkMobile"` // 手机号码
    	Email          string `json:"email,optional" validate:"omitempty,checkEmail"` // 邮箱地址
    	Date           string `json:"date" validate:"omitempty,checkDate,checkAfterDate"` // 时间
    	Password       string `json:"password" validate:"required"` // 密码
    	ConfimPassword string `json:"confimPassword" validate:"eqfield=Password"` // 确认密码
    }
    
    • optional表示go-zero参数是可选,一个很大作用是生成的swagger上没有标识必填字段

    • checkMobilecheckEmailcheckAfterDate都是自定义校验器,需要在translator.go注册才能使用

    • omitempty表示如果为空的话,就不走后面的校验

      在这里插入图片描述

  • 6、使用命令用模版生成文件,注意导包的问题

    goctl api go -api *api --dir . --style=goZero --home ../../goctl
    
  • 7、自测错误,并且返回给前端

    在这里插入图片描述

  • 8、当go-zero中标识必填字段的时候提示的错误为下面,比如name字段不写的时候,age字段数据类型错误的时候
    在这里插入图片描述

  • 9、age数据类型错误的时候

    在这里插入图片描述

三、翻译go-zero中的参数错误

  • 1、自定义translatorError.go翻译文件

    package utils
    
    import (
    	"fmt"
    	"regexp"
    	"strings"
    )
    
    func TranslatorError(err error) string {
    	reg := regexp.MustCompile(`"(.*)?"`)
    	match := reg.FindString(err.Error())
    	if strings.Contains(err.Error(), "is not set") {
    		if match != "" {
    			return fmt.Sprintf("%s 为必填字段!", strings.Replace(match, `"`, "", -1))
    		}
    	} else if strings.Contains(err.Error(), "mismatch for field") {
    		if match != "" {
    			return fmt.Sprintf("%s 数据类型不对!", strings.Replace(match, `"`, "", -1))
    		}
    	}
    	return ""
    }
    
  • 2、在返回错误拦截器中添加使用

    func ErrHandler(name string) func(ctx context.Context, err error) (int, any) {
    	return func(ctx context.Context, err error) (int, any) {
    		fmt.Println(err, "错误信息")
    		causeErr := errors.Cause(err)
    		fmt.Println(causeErr, "111-->")
    		var errMessage = err.Error()
    		// 翻译错误
    		translatorError := TranslatorError(err)
    		if translatorError != "" {
    			errMessage = translatorError
    		}
    		// 日志记录
    		logx.WithContext(ctx).Errorf("【%s】 err %v", name, errMessage)
    		return http.StatusBadRequest, Fail(errMessage)
    	}
    }
    
  • 3、当年龄数据类型错误的时候

    在这里插入图片描述

  • 4、name字段没写的时候
    在这里插入图片描述

  • 5、另外name为空字符串的时候

    在这里插入图片描述

四、参考文档

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水痕01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值