一、自定义模版的使用
如果想对官网
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
是创建一个user
的api
项目
二、使用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
上没有标识必填字段 -
checkMobile
、checkEmail
、checkAfterDate
都是自定义校验器,需要在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
为空字符串的时候
四、参考文档
-
1、go-playground文档
-
2、go-zero官网