欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

go?doudou應(yīng)用中使用注解示例詳解

 更新時(shí)間:2022年12月07日 10:29:43   作者:武斌  
這篇文章主要為大家介紹了go?doudou應(yīng)用中使用注解示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

快速上手

我們都知道go語(yǔ)言沒(méi)有原生的注解,但是做業(yè)務(wù)開(kāi)發(fā)有些時(shí)候沒(méi)有注解確實(shí)不方便。go-doudou通過(guò)go語(yǔ)言標(biāo)準(zhǔn)庫(kù)ast/parser實(shí)現(xiàn)了對(duì)注解的支持。b站配套視頻教程地址:[golang] go-doudou微服務(wù)框架入門(mén)03-如何使用注解,如果喜歡看視頻,可直接跟視頻上手實(shí)踐。

我們通過(guò)一個(gè)簡(jiǎn)單的基于go-doudou開(kāi)發(fā)的服務(wù)來(lái)演示用法和效果。

準(zhǔn)備

  • 本地安裝最新版go-doudou CLI
go install -v github.com/unionj-cloud/go-doudou@v1.1.9

本地安裝postman,用于測(cè)試接口:www.postman.com/

本地安裝goland

初始化工程

我們的服務(wù)名稱和模塊名稱都叫annotation

go-doudou svc init annotation

設(shè)計(jì)業(yè)務(wù)接口

go-doudou應(yīng)用的接口定義文件是項(xiàng)目根路徑下的svc.go文件。打開(kāi)文件后按照如下代碼修改:

package service
import "context"
//go:generate go-doudou svc http --handler --doc
type Annotation interface {
	// 此接口可公開(kāi)訪問(wèn),無(wú)需校驗(yàn)登錄和權(quán)限
	GetGuest(ctx context.Context) (data string, err error)
	// 此接口只有登錄用戶有權(quán)訪問(wèn)
	// @role(USER,ADMIN)
	GetUser(ctx context.Context) (data string, err error)
	// 此接口只有管理員有權(quán)訪問(wèn)
	// @role(ADMIN)
	GetAdmin(ctx context.Context) (data string, err error)
}

@role(USER,ADMIN)@role(ADMIN)就是本文的主角。注解定義格式為:@注解名稱(參數(shù)1,參數(shù)2,參數(shù)3...)。可以根據(jù)業(yè)務(wù)實(shí)際需求,自定義各種不同的注解,@role僅是一個(gè)例子,你還可以定義其他如@permission(create,update,del),以及無(wú)參數(shù)注解@inner()。

生成代碼

點(diǎn)擊截圖中左上角的綠色三角形,執(zhí)行go:generate指令,生成接口路由和http handler相關(guān)代碼,以及遵循OpenAPI 3.0規(guī)范的json文檔。

我們重點(diǎn)看一下transport/httpsrv/handler.go文件。

package httpsrv
import (
	"net/http"
	ddmodel "github.com/unionj-cloud/go-doudou/framework/http/model"
)
// http handler接口
type AnnotationHandler interface {
	GetGuest(w http.ResponseWriter, r *http.Request)
	GetUser(w http.ResponseWriter, r *http.Request)
	GetAdmin(w http.ResponseWriter, r *http.Request)
}
// 接口路由
func Routes(handler AnnotationHandler) []ddmodel.Route {
	return []ddmodel.Route{
		{
			"GetGuest",
			"GET",
			"/guest",
			handler.GetGuest,
		},
		{
			"GetUser",
			"GET",
			"/user",
			handler.GetUser,
		},
		{
			"GetAdmin",
			"GET",
			"/admin",
			handler.GetAdmin,
		},
	}
}
// 在內(nèi)存中存儲(chǔ)解析出來(lái)的注解信息
// ddmodel.AnnotationStore是map[string][]Annotation類(lèi)型的別名,
// 鍵是路由名稱,值是注解結(jié)構(gòu)體切片。注解結(jié)構(gòu)體中存放了注解名稱和參數(shù)切片,
// 下文我們實(shí)現(xiàn)的校驗(yàn)權(quán)限的中間件原理就是通過(guò)http.Request對(duì)象拿到路由名稱,
// 然后用路由名稱從RouteAnnotationStore中找出存儲(chǔ)的注解結(jié)構(gòu)體切片,
// 最后比對(duì)從內(nèi)存數(shù)據(jù)源或外部數(shù)據(jù)源拿到的用戶角色和注解結(jié)構(gòu)體的參數(shù)切片中的元素
// 判斷該用戶是否有權(quán)限繼續(xù)訪問(wèn)接口
var RouteAnnotationStore = ddmodel.AnnotationStore{
	"GetUser": {
		{
			Name: "@role",
			Params: []string{
				"USER",
				"ADMIN",
			},
		},
	},
	"GetAdmin": {
		{
			Name: "@role",
			Params: []string{
				"ADMIN",
			},
		},
	},
}

下載依賴

執(zhí)行命令go mod tidy,下載項(xiàng)目依賴。此時(shí),服務(wù)已經(jīng)可以啟動(dòng)了,但是我們不急。下面我們要根據(jù)注解信息,編寫(xiě)中間件,實(shí)現(xiàn)我們依據(jù)用戶角色控制訪問(wèn)權(quán)限的需求。

Auth中間件

本示例項(xiàng)目的登錄憑證采用http basic的base64 token。我們打開(kāi)transport/httpsrv/middleware.go文件,黏貼進(jìn)去如下代碼:

package httpsrv
import (
	"annotation/vo"
	"github.com/gorilla/mux"
	"github.com/unionj-cloud/go-doudou/toolkit/sliceutils"
	"net/http"
)
// vo.UserStore是map[Auth]RoleEnum的別名類(lèi)型,鍵為用戶名和密碼構(gòu)成的結(jié)構(gòu)體,值為角色枚舉
// 我們用userStore代表數(shù)據(jù)庫(kù)
func Auth(userStore vo.UserStore) func(inner http.Handler) http.Handler {
	return func(inner http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// 從http.Request中拿到路由名稱
			currentRoute := mux.CurrentRoute(r)
			if currentRoute == nil {
				inner.ServeHTTP(w, r)
				return
			}
			routeName := currentRoute.GetName()
			// 查詢?cè)撀酚墒欠裼嘘P(guān)聯(lián)的注解結(jié)構(gòu)體切片
			// 如果沒(méi)有,則放行
			if !RouteAnnotationStore.HasAnnotation(routeName, "@role") {
				inner.ServeHTTP(w, r)
				return
			}
			// 從請(qǐng)求頭中提取并解析http basic用戶名和密碼
			user, pass, ok := r.BasicAuth()
			// 如果不成功,則禁止訪問(wèn),返回401
			if !ok {
				w.Header().Set("WWW-Authenticate", `Basic realm="Provide user name and password"`)
				w.WriteHeader(401)
				w.Write([]byte("Unauthorised.\n"))
				return
			}
			// 從userStore中查詢是否存在此用戶
			role, exists := userStore[vo.Auth{user, pass}]
			// 如果不存在,則禁止訪問(wèn),返回401
			if !exists {
				w.Header().Set("WWW-Authenticate", `Basic realm="Provide user name and password"`)
				w.WriteHeader(401)
				w.Write([]byte("Unauthorised.\n"))
				return
			}
			// 如果存在,則判斷該接口是否允許該用戶所屬角色訪問(wèn)
			params := RouteAnnotationStore.GetParams(routeName, "@role")
			// 判斷該路由的@role注解的參數(shù)切片中是否包含該用戶的角色
			// 如果不包含,則禁止訪問(wèn),返回403
			if !sliceutils.StringContains(params, role.StringGetter()) {
				w.WriteHeader(403)
				w.Write([]byte("Access denied\n"))
				return
			}
			// 如果包含,則放行
			inner.ServeHTTP(w, r)
		})
	}
}

至此,我們已經(jīng)完成核心邏輯開(kāi)發(fā)。最后我們只要把這個(gè)中間件加到go-doudou服務(wù)里即可。

修改main函數(shù)

package main
import (
	service "annotation"
	"annotation/config"
	"annotation/transport/httpsrv"
	"annotation/vo"
	ddhttp "github.com/unionj-cloud/go-doudou/framework/http"
)
func main() {
	conf := config.LoadFromEnv()
	svc := service.NewAnnotation(conf)
	handler := httpsrv.NewAnnotationHandler(svc)
	srv := ddhttp.NewDefaultHttpSrv()
	// 將上文編寫(xiě)的Auth中間件加入go-doudou服務(wù)中
	srv.AddMiddleware(httpsrv.Auth(vo.UserStore{
		vo.Auth{
			User: "guest",
			Pass: "guest",
		}: vo.GUEST,
		vo.Auth{
			User: "user",
			Pass: "user",
		}: vo.USER,
		vo.Auth{
			User: "admin",
			Pass: "admin",
		}: vo.ADMIN,
	}))
	srv.AddRoute(httpsrv.Routes(handler)...)
	srv.Run()
}

啟動(dòng)服務(wù)

啟動(dòng)服務(wù)有多種方式:

go-doudou內(nèi)置啟動(dòng)命令(僅用于開(kāi)發(fā)階段):

go-doudou svc run

go run cmd/main.go

點(diǎn)擊main函數(shù)左邊的綠色 圖表

測(cè)試效果

將生成的annotation_openapi3.json文件導(dǎo)入postman中即可測(cè)試。postman的用法超出了本文的范疇,此處只附上部分截圖供參考。

注解實(shí)現(xiàn)原理

go-doudou實(shí)現(xiàn)注解的原理非常簡(jiǎn)單,就是通過(guò)go語(yǔ)言標(biāo)準(zhǔn)庫(kù)ast/parser對(duì)接口定義文件svc.go文件中的源碼進(jìn)行解析,將注釋塊里的注解通過(guò)正則表達(dá)式提取出來(lái),創(chuàng)建Annotation結(jié)構(gòu)體實(shí)例,關(guān)聯(lián)到對(duì)應(yīng)的接口上,最后作為靜態(tài)變量RouteAnnotationStore的值通過(guò)代碼生成器輸出到transport/httpsrv/handler.go文件里的,供開(kāi)發(fā)者調(diào)用。

以下是提取注解的源碼,供參考:

var reAnno = regexp.MustCompile(`@(\S+?)\((.*?)\)`)
func GetAnnotations(text string) []Annotation {
	if !reAnno.MatchString(text) {
		return nil
	}
	var annotations []Annotation
	matches := reAnno.FindAllStringSubmatch(text, -1)
	for _, item := range matches {
		name := fmt.Sprintf(`@%s`, item[1])
		var params []string
		if stringutils.IsNotEmpty(item[2]) {
			params = strings.Split(strings.TrimSpace(item[2]), ",")
		}
		annotations = append(annotations, Annotation{
			Name:   name,
			Params: params,
		})
	}
	return annotations
}

總結(jié)

本文通過(guò)一個(gè)快速上手實(shí)例,講解了go-doudou注解特性的用法和原理。有任何疑問(wèn)都可以在下方留言。示例源碼地址:github.com/unionj-clou…

關(guān)于go-doudou的更多特性和用法請(qǐng)參考官方文檔:go-doudou.unionj.cloud/

以上就是go doudou應(yīng)用中使用注解示例詳解的詳細(xì)內(nèi)容,更多關(guān)于go doudou應(yīng)用注解的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • logrus日志自定義格式操作

    logrus日志自定義格式操作

    這篇文章主要介紹了logrus日志自定義格式操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • Go語(yǔ)言獲取系統(tǒng)性能數(shù)據(jù)gopsutil庫(kù)的操作

    Go語(yǔ)言獲取系統(tǒng)性能數(shù)據(jù)gopsutil庫(kù)的操作

    這篇文章主要介紹了Go語(yǔ)言獲取系統(tǒng)性能數(shù)據(jù)gopsutil庫(kù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • GoFrame框架Scan類(lèi)型轉(zhuǎn)換實(shí)例

    GoFrame框架Scan類(lèi)型轉(zhuǎn)換實(shí)例

    這篇文章主要為大家介紹了GoFrame框架Scan類(lèi)型轉(zhuǎn)換的實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • golang實(shí)現(xiàn)并發(fā)數(shù)控制的方法

    golang實(shí)現(xiàn)并發(fā)數(shù)控制的方法

    下面小編就為大家分享一篇golang實(shí)現(xiàn)并發(fā)數(shù)控制的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • Go語(yǔ)言?Channel通道詳解

    Go語(yǔ)言?Channel通道詳解

    Channel是一個(gè)通道,可以通過(guò)它讀取和寫(xiě)入數(shù)據(jù),它就像水管一樣,網(wǎng)絡(luò)數(shù)據(jù)通過(guò)Channel 讀取和寫(xiě)入,這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言?Channel通道的相關(guān)資料,需要的朋友可以參考下
    2023-07-07
  • golang程序進(jìn)度條實(shí)現(xiàn)示例詳解

    golang程序進(jìn)度條實(shí)現(xiàn)示例詳解

    這篇文章主要為大家介紹了golang程序?qū)崿F(xiàn)進(jìn)度條示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • golang基礎(chǔ)之字符串與int、int64類(lèi)型互相轉(zhuǎn)換

    golang基礎(chǔ)之字符串與int、int64類(lèi)型互相轉(zhuǎn)換

    這篇文章主要給大家介紹了關(guān)于golang基礎(chǔ)之字符串與int、int64類(lèi)型互相轉(zhuǎn)換的相關(guān)資料,在Go語(yǔ)言中string轉(zhuǎn)int是一項(xiàng)常見(jiàn)的操作,需要的朋友可以參考下
    2023-07-07
  • go語(yǔ)言實(shí)現(xiàn)字符串base64編碼的方法

    go語(yǔ)言實(shí)現(xiàn)字符串base64編碼的方法

    這篇文章主要介紹了go語(yǔ)言實(shí)現(xiàn)字符串base64編碼的方法,實(shí)例分析了Go語(yǔ)言操作字符串的技巧及base64編碼的使用技巧,需要的朋友可以參考下
    2015-03-03
  • golang 的string與[]byte轉(zhuǎn)換方式

    golang 的string與[]byte轉(zhuǎn)換方式

    這篇文章主要介紹了golang 的string與[]byte轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Go語(yǔ)言實(shí)現(xiàn)基于websocket瀏覽器通知功能

    Go語(yǔ)言實(shí)現(xiàn)基于websocket瀏覽器通知功能

    這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)基于websocket瀏覽器通知功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07

最新評(píng)論