您的位置:首頁(yè) > 軟件教程 > 教程 > Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

來(lái)源:好特整理 | 時(shí)間:2024-05-09 11:59:11 | 閱讀:168 |  標(biāo)簽: T GO C 開(kāi)發(fā) 服務(wù) zero   | 分享到:

gozero如何自定義goctl?本文詳解和實(shí)戰(zhàn),通過(guò)本文你將了解goctl的妙用,提高你的開(kāi)發(fā)效率。介紹如何使用goctl工具實(shí)現(xiàn)模板定制化,并根據(jù)實(shí)際項(xiàng)目業(yè)務(wù)需求進(jìn)行模板定制化實(shí)現(xiàn)。

前言

上一篇文章帶你實(shí)現(xiàn)了 Go-Zero和goctl:解鎖微服務(wù)開(kāi)發(fā)的神器,快速上手指南 ,本文將繼續(xù)深入探討Go-Zero的強(qiáng)大之處,并介紹如何使用goctl工具實(shí)現(xiàn)模板定制化,并根據(jù)實(shí)際項(xiàng)目業(yè)務(wù)需求進(jìn)行模板定制化實(shí)現(xiàn)。

通過(guò)本文的教程,你能夠親自實(shí)踐并完成goctl模板的定制化,進(jìn)一步提升你的Go-Zero開(kāi)發(fā)技能。

概述

goctl 代碼生成是基于 go 的模板去實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)的,默認(rèn)情況會(huì)選擇內(nèi)存中的模板進(jìn)行生成,當(dāng)開(kāi)發(fā)需要修改模板時(shí),就需要定制化模板,goctl為我們實(shí)現(xiàn)了這一功能。

實(shí)戰(zhàn)前準(zhǔn)備

首先需要你在本地安裝goctl、protoc、go-zero,下載教學(xué)和地址 點(diǎn)擊這里 ,按照教程操作即可,非常簡(jiǎn)單。

下面按順序和我操作吧,對(duì)整體開(kāi)發(fā)流程不清楚的同學(xué)務(wù)必先看我前篇文章: GoZero的開(kāi)發(fā)技巧 & 整體開(kāi)發(fā)流程

本文重在實(shí)戰(zhàn),如果對(duì)goctl毫不了解的話(huà),建議先看我前一篇文章: Go-Zero和goctl:解鎖微服務(wù)開(kāi)發(fā)的神器,快速上手指南

以下均以我的商業(yè)項(xiàng)目舉例,應(yīng)該對(duì)你有啟發(fā):

(后面我會(huì)把商業(yè)項(xiàng)目脫敏開(kāi)源出來(lái),歡迎關(guān)注我)

數(shù)據(jù)表生成Model方法腳本

首先在deploy下新增script目錄,結(jié)構(gòu)如下圖所示。

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

腳本內(nèi)容如下:

#!/usr/bin/env bash

# 使用方法:
# ./genModel.sh lottery lottery
# ./genModel.sh lottery prize
# 再將./genModel下的文件剪切到對(duì)應(yīng)服務(wù)的model目錄里面,記得改package

#生成的表名
tables=$2
#表生成的genmodel目錄
modeldir=./genModel

# 數(shù)據(jù)庫(kù)配置
host=127.0.0.1
port=33069
dbname=$1
username=root
passwd=PXDN93VRKUm8TeE7
template=../../goctl/1.6.1

echo "開(kāi)始創(chuàng)建庫(kù):$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)也有詳細(xì)步驟。這里更加注重商業(yè)項(xiàng)目對(duì)于模板定制化的實(shí)戰(zhàn),對(duì)相關(guān)操作不進(jìn)行贅述,快速過(guò)一遍流程即可。

初始化模板到本地

依據(jù)前文所介紹的項(xiàng)目目錄結(jié)構(gòu),我們將自定義模板放在deploy下面即可,并且采用的版本號(hào)為1.6.1(目錄路徑根據(jù)自己實(shí)際情況修改)

goctl template init --home $HOME/Desktop/lottery-backend/deploy/goctl/1.6.1

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

注意:如果不指定–home 他會(huì)初始化到$HOME/.goctl

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

這樣就生成好自己版本的goctl模板啦,可以根據(jù)自己的實(shí)際需求進(jìn)行模板的修改。

接下來(lái)分享我們項(xiàng)目中關(guān)于自定義goctl的實(shí)戰(zhàn)。

自定義goctl實(shí)戰(zhàn)

實(shí)戰(zhàn)1:Model層方法定制化

很多時(shí)候我們需要對(duì)數(shù)據(jù)進(jìn)行分頁(yè)查詢(xún)。這個(gè)方法是一個(gè)通用的方法,可以在很多地方復(fù)用,所以放入模板去生成,這樣可以減少重復(fù)代碼,提高開(kāi)發(fā)效率。

步驟一:在model/update.tpl下面新增一個(gè)方法FindPageListByPage

方法具體實(shí)現(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) * pageSize

	query, 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, nil
	default:
		return nil, err
	}
}

步驟二:使用之前做好的腳本生成代碼

使用GitBash打開(kāi)deploy/script/mysql目錄,執(zhí)行腳本

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

此時(shí)genModel目錄下面就會(huì)生成相關(guān)代碼

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

步驟三:將生成的代碼剪切到項(xiàng)目目錄的對(duì)應(yīng)位置

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

效果

默認(rèn)模板生成的Model層方法

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

自定義模板生成的Model層方法

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

生成的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) * pageSize

	query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
	if err != nil {
		return nil, err
	}

	var resp []*Lottery
	err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
	switch err {
	case nil:
		return resp, nil
	default:
		return nil, err
	}
}

實(shí)戰(zhàn)2:api自定義響應(yīng)返回以及集成validator庫(kù)校驗(yàn)參數(shù)

當(dāng)我們希望自定義統(tǒng)一返回響應(yīng)體以及希望每個(gè)api接口都進(jìn)行參數(shù)校驗(yàn)時(shí),我們可以在模板中修改handler層的代碼,從而實(shí)現(xiàn)這些效果。

步驟一:實(shí)現(xiàn)自定義統(tǒng)一返回響應(yīng)

在common目錄下新建result目錄和httpResult.go文件,如下圖所示

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

具體實(shí)現(xiàn)代碼不是本文重點(diǎn),下面是提供的代碼

package result

import (
	"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 {
		//錯(cuò)誤返回
		errcode := xerr.SERVER_COMMON_ERROR
		errmsg := "服務(wù)器開(kāi)小差啦,稍后再來(lái)試一試"

		causeErr := errors.Cause(err)                // err類(lèi)型
		if e, ok := causeErr.(*xerr.CodeError); ok { //自定義錯(cuò)誤類(lèi)型
			//自定義CodeError
			errcode = e.GetErrCode()
			errmsg = e.GetErrMsg()
		} else {
			if gstatus, ok := status.FromError(causeErr); ok { // grpc err錯(cuò)誤
				grpcCode := uint32(gstatus.Code())
				if xerr.IsCodeErr(grpcCode) { //區(qū)分自定義錯(cuò)誤跟系統(tǒng)底層、db等錯(cuò)誤,底層、db錯(cuò)誤不能返回給前端
					errcode = grpcCode
					errmsg = gstatus.Message()
				}
			}
		}

		logx.WithContext(r.Context()).Errorf("【API-ERR】 : %+v ", err)

		httpx.WriteJson(w, http.StatusBadRequest, Error(errcode, errmsg))
	}
}

// http 參數(shù)錯(cuò)誤返回
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包

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

關(guān)于定制validator也不是本文重點(diǎn),感興趣的同學(xué)可以關(guān)注我,留言。

package translator

import (
	"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()
	// 注冊(cè)一個(gè)函數(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
	})

	// 在這里注冊(cè)自定義結(jié)構(gòu)體/字段校驗(yàn)方法
	// 注冊(cè)自定義結(jié)構(gòu)體校驗(yàn)方法
	validate.RegisterStructValidation(lottery.SignUpParamStructLevelValidation, types.TestReq{})

	// 注冊(cè)自定義結(jié)構(gòu)體字段校驗(yàn)方法
	if err := validate.RegisterValidation("checkDate", lottery.CheckDate); err != nil {
		return err
	}

	uni := ut.New(zh_ch)
	trans, _ := uni.GetTranslator("zh")

	// 在這里注冊(cè)自定義tag翻譯
	// 注意!因?yàn)檫@里會(huì)使用到trans實(shí)例
	// 所以這一步注冊(cè)要放到trans初始化的后面

	if err := validate.RegisterTranslation(
		"checkDate",
		trans,
		registerTranslator("checkDate", "{0}必須要晚于當(dāng)前日期"),
		translate,
	); err != nil {
		return err
	}

	// 驗(yàn)證器注冊(cè)翻譯器
	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模板代碼

Go-Zero自定義goctl實(shí)戰(zhàn):定制化模板,加速你的微服務(wù)開(kāi)發(fā)效率(四)

將模板替換為以下內(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)
	}
}

步驟四:生成對(duì)應(yīng)的代碼

注意生成handler后需要手動(dòng)點(diǎn)開(kāi)生成的 handler文件,導(dǎo)入translator包 ,否則服務(wù)會(huì)報(bào)錯(cuò)。!

# 使用自定義的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ī)則

  1. 在 goctl 提供的有效數(shù)據(jù)范圍內(nèi)修改,即不支持外部變量
  2. 不支持新增模板文件
  3. 不支持變量修改

總結(jié)

本文介紹了如何使用Go-Zero的goctl工具進(jìn)行自定義模板的實(shí)戰(zhàn),并提供了一個(gè)具體的案例來(lái)演示定制化模板的過(guò)程。

如果你需要詳細(xì)的命令使用詳情,可以參考官方文檔中的相關(guān)內(nèi)容。模板定制化 | go-zero Documentation

我將繼續(xù)更新Go-Zero系列文章,如果你對(duì)Go語(yǔ)言或者微服務(wù)感興趣,歡迎關(guān)注我,也歡迎直接私信我。

gozero&微服務(wù)交流群

我將繼續(xù)更新Go-Zero系列文章, 如果你對(duì)Go語(yǔ)言或者微服務(wù)感興趣,歡迎關(guān)注我,也歡迎直接私信我。

微信:wangzhongyang1993

小編推薦閱讀

好特網(wǎng)發(fā)布此文僅為傳遞信息,不代表好特網(wǎng)認(rèn)同期限觀點(diǎn)或證實(shí)其描述。

Go v1.62
Go v1.62
類(lèi)型:動(dòng)作冒險(xiǎn)  運(yùn)營(yíng)狀態(tài):正式運(yùn)營(yíng)  語(yǔ)言:中文   

游戲攻略

游戲禮包

游戲視頻

游戲下載

游戲活動(dòng)

GoEscape是一款迷宮逃脫休閑闖關(guān)游戲。在這款游戲中,玩家可以挑戰(zhàn)大量關(guān)卡,通過(guò)旋轉(zhuǎn)屏幕的方式幫助球球

相關(guān)視頻攻略

更多

掃二維碼進(jìn)入好特網(wǎng)手機(jī)版本!

掃二維碼進(jìn)入好特網(wǎng)微信公眾號(hào)!

本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請(qǐng)發(fā)郵件[email protected]

湘ICP備2022002427號(hào)-10 湘公網(wǎng)安備:43070202000427號(hào)© 2013~2024 haote.com 好特網(wǎng)