什么網(wǎng)站發(fā)布找做效果圖的電腦優(yōu)化是什么意思
前言
上一篇文章帶你實現(xiàn)了Go-Zero和goctl:解鎖微服務(wù)開發(fā)的神器,快速上手指南,本文將繼續(xù)深入探討Go-Zero的強大之處,并介紹如何使用goctl工具實現(xiàn)模板定制化,并根據(jù)實際項目業(yè)務(wù)需求進行模板定制化實現(xiàn)。
通過本文的教程,你能夠親自實踐并完成goctl模板的定制化,進一步提升你的Go-Zero開發(fā)技能。
概述
goctl 代碼生成是基于 go 的模板去實現(xiàn)數(shù)據(jù)驅(qū)動的,默認情況會選擇內(nèi)存中的模板進行生成,當開發(fā)需要修改模板時,就需要定制化模板,goctl為我們實現(xiàn)了這一功能。
實戰(zhàn)前準備
首先需要你在本地安裝goctl、protoc、go-zero,下載教學和地址點擊這里,按照教程操作即可,非常簡單。
下面按順序和我操作吧,對整體開發(fā)流程不清楚的同學務(wù)必先看我前篇文章:GoZero的開發(fā)技巧 & 整體開發(fā)流程
本文重在實戰(zhàn),如果對goctl毫不了解的話,建議先看我前一篇文章:Go-Zero和goctl:解鎖微服務(wù)開發(fā)的神器,快速上手指南
以下均以我的商業(yè)項目舉例,應(yīng)該對你有啟發(fā):
(后面我會把商業(yè)項目脫敏開源出來,歡迎關(guān)注我)
數(shù)據(jù)表生成Model方法腳本
首先在deploy下新增script目錄,結(jié)構(gòu)如下圖所示。
腳本內(nèi)容如下:
#!/usr/bin/env bash# 使用方法:
# ./genModel.sh lottery lottery
# ./genModel.sh lottery prize
# 再將./genModel下的文件剪切到對應(yīng)服務(wù)的model目錄里面,記得改package#生成的表名
tables=$2
#表生成的genmodel目錄
modeldir=./genModel# 數(shù)據(jù)庫配置
host=127.0.0.1
port=33069
dbname=$1
username=root
passwd=PXDN93VRKUm8TeE7
template=../../goctl/1.6.1echo "開始創(chuàng)建庫:$dbname 的表:$2"
goctl model mysql datasource -url="${username}:${passwd}@tcp(${host}:${port})/${dbname}" -table="${tables}" -dir="${modeldir}" -cache=true --home="${template}" --style=goZero
模板定制化使用方法
相關(guān)命令使用詳情,參考:官網(wǎng)文檔
具體使用方法網(wǎng)上有很多文章介紹,官網(wǎng)也有詳細步驟。這里更加注重商業(yè)項目對于模板定制化的實戰(zhàn),對相關(guān)操作不進行贅述,快速過一遍流程即可。
初始化模板到本地
依據(jù)前文所介紹的項目目錄結(jié)構(gòu),我們將自定義模板放在deploy下面即可,并且采用的版本號為1.6.1(目錄路徑根據(jù)自己實際情況修改)
goctl template init --home $HOME/Desktop/lottery-backend/deploy/goctl/1.6.1
注意:如果不指定–home 他會初始化到$HOME/.goctl
這樣就生成好自己版本的goctl模板啦,可以根據(jù)自己的實際需求進行模板的修改。
接下來分享我們項目中關(guān)于自定義goctl的實戰(zhàn)。
自定義goctl實戰(zhàn)
實戰(zhàn)1:Model層方法定制化
很多時候我們需要對數(shù)據(jù)進行分頁查詢。這個方法是一個通用的方法,可以在很多地方復用,所以放入模板去生成,這樣可以減少重復代碼,提高開發(fā)效率。
步驟一:在model/update.tpl下面新增一個方法FindPageListByPage
方法具體實現(xiàn)如下
func (m *default{{.upperStartCamelObject}}Model) FindPageListByPage(ctx context.Context,builder squirrel.SelectBuilder,page ,pageSize int64,orderBy string) ([]*{{.upperStartCamelObject}},error) {builder = builder.Columns({{.lowerStartCamelObject}}Rows)if orderBy == ""{builder = builder.OrderBy("id DESC")}else{builder = builder.OrderBy(orderBy)}if page < 1{page = 1}offset := (page - 1) * pageSizequery, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()if err != nil {return nil, err}var resp []*{{.upperStartCamelObject}}{{if .withCache}}err = m.QueryRowsNoCacheCtx(ctx,&resp, query, values...){{else}}err = m.conn.QueryRowsCtx(ctx,&resp, query, values...){{end}}switch err {case nil:return resp, nildefault:return nil, err}
}
步驟二:使用之前做好的腳本生成代碼
使用GitBash打開deploy/script/mysql目錄,執(zhí)行腳本
此時genModel目錄下面就會生成相關(guān)代碼
步驟三:將生成的代碼剪切到項目目錄的對應(yīng)位置
效果
默認模板生成的Model層方法
自定義模板生成的Model層方法
生成的FindPageListByPage方法
func (m *defaultLotteryModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*Lottery, error) {builder = builder.Columns(lotteryRows)if orderBy == "" {builder = builder.OrderBy("id DESC")} else {builder = builder.OrderBy(orderBy)}if page < 1 {page = 1}offset := (page - 1) * pageSizequery, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()if err != nil {return nil, err}var resp []*Lotteryerr = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)switch err {case nil:return resp, nildefault:return nil, err}
}
實戰(zhàn)2:api自定義響應(yīng)返回以及集成validator庫校驗參數(shù)
當我們希望自定義統(tǒng)一返回響應(yīng)體以及希望每個api接口都進行參數(shù)校驗時,我們可以在模板中修改handler層的代碼,從而實現(xiàn)這些效果。
步驟一:實現(xiàn)自定義統(tǒng)一返回響應(yīng)
在common目錄下新建result目錄和httpResult.go文件,如下圖所示
具體實現(xiàn)代碼不是本文重點,下面是提供的代碼
package resultimport ("fmt""net/http""looklook/common/xerr""github.com/pkg/errors""github.com/zeromicro/go-zero/core/logx""github.com/zeromicro/go-zero/rest/httpx""google.golang.org/grpc/status"
)// http返回
func HttpResult(r *http.Request, w http.ResponseWriter, resp interface{}, err error) {if err == nil {//成功返回r := Success(resp)httpx.WriteJson(w, http.StatusOK, r)} else {//錯誤返回errcode := xerr.SERVER_COMMON_ERRORerrmsg := "服務(wù)器開小差啦,稍后再來試一試"causeErr := errors.Cause(err) // err類型if e, ok := causeErr.(*xerr.CodeError); ok { //自定義錯誤類型//自定義CodeErrorerrcode = e.GetErrCode()errmsg = e.GetErrMsg()} else {if gstatus, ok := status.FromError(causeErr); ok { // grpc err錯誤grpcCode := uint32(gstatus.Code())if xerr.IsCodeErr(grpcCode) { //區(qū)分自定義錯誤跟系統(tǒng)底層、db等錯誤,底層、db錯誤不能返回給前端errcode = grpcCodeerrmsg = gstatus.Message()}}}logx.WithContext(r.Context()).Errorf("【API-ERR】 : %+v ", err)httpx.WriteJson(w, http.StatusBadRequest, Error(errcode, errmsg))}
}// http 參數(shù)錯誤返回
func ParamErrorResult(r *http.Request, w http.ResponseWriter, err error) {errMsg := fmt.Sprintf("%s ,%s", xerr.MapErrMsg(xerr.REUQEST_PARAM_ERROR), err.Error())httpx.WriteJson(w, http.StatusBadRequest, Error(xerr.REUQEST_PARAM_ERROR, errMsg))
}
步驟二:在handler下面引入定制的validator包
關(guān)于定制validator也不是本文重點,感興趣的同學可以關(guān)注我,留言。
package translatorimport ("errors""github.com/go-playground/locales/zh"ut "github.com/go-playground/universal-translator""github.com/go-playground/validator/v10"zh_translations "github.com/go-playground/validator/v10/translations/zh""looklook/app/lottery/cmd/api/internal/logic/lottery""looklook/app/lottery/cmd/api/internal/types""reflect""strings"
)func Validate(dataStruct interface{}) error {zh_ch := zh.New()validate := validator.New()// 注冊一個函數(shù),獲取struct tag里自定義的label作為字段名validate.RegisterTagNameFunc(func(fld reflect.StructField) string {name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]if name == "-" {return ""}return name})// 在這里注冊自定義結(jié)構(gòu)體/字段校驗方法// 注冊自定義結(jié)構(gòu)體校驗方法validate.RegisterStructValidation(lottery.SignUpParamStructLevelValidation, types.TestReq{})// 注冊自定義結(jié)構(gòu)體字段校驗方法if err := validate.RegisterValidation("checkDate", lottery.CheckDate); err != nil {return err}uni := ut.New(zh_ch)trans, _ := uni.GetTranslator("zh")// 在這里注冊自定義tag翻譯// 注意!因為這里會使用到trans實例// 所以這一步注冊要放到trans初始化的后面if err := validate.RegisterTranslation("checkDate",trans,registerTranslator("checkDate", "{0}必須要晚于當前日期"),translate,); err != nil {return err}// 驗證器注冊翻譯器zh_translations.RegisterDefaultTranslations(validate, trans)err := validate.Struct(dataStruct)if err != nil {for _, err := range err.(validator.ValidationErrors) {return errors.New(err.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
}
步驟三:修改handler.tpl模板代碼
將模板替換為以下內(nèi)容
package {{.PkgName}}import ("net/http""looklook/common/result""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}validateErr := translator.Validate(&req)if validateErr != nil {result.ParamErrorResult(r, w, validateErr)return}{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx){{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})result.HttpResult(r, w, {{if .HasResp}}resp{{else}}nil{{end}}, err)}
}
步驟四:生成對應(yīng)的代碼
注意生成handler后需要手動點開生成的handler文件,導入translator包,否則服務(wù)會報錯!!!
# 使用自定義的goctl 生成api
goctl api go -api main.api -dir ../ --style=goZero --home=../../../../../deploy/goctl/1.6.1
修改后的響應(yīng)體
{"code": 200,"msg": "OK","data": {"message": ""}
}
模板自定義規(guī)則
- 在 goctl 提供的有效數(shù)據(jù)范圍內(nèi)修改,即不支持外部變量
- 不支持新增模板文件
- 不支持變量修改
總結(jié)
本文介紹了如何使用Go-Zero的goctl工具進行自定義模板的實戰(zhàn),并提供了一個具體的案例來演示定制化模板的過程。
如果你需要詳細的命令使用詳情,可以參考官方文檔中的相關(guān)內(nèi)容。模板定制化 | go-zero Documentation
我將繼續(xù)更新Go-Zero系列文章,如果你對Go語言或者微服務(wù)感興趣,歡迎關(guān)注我,也歡迎直接私信我。
gozero&微服務(wù)交流群
我將繼續(xù)更新Go-Zero系列文章,如果你對Go語言或者微服務(wù)感興趣,歡迎關(guān)注我,也歡迎直接私信我。
微信:wangzhongyang1993