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

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

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

快速上手

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

我們通過一個簡單的基于go-doudou開發(fā)的服務(wù)來演示用法和效果。

準(zhǔn)備

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

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

本地安裝goland

初始化工程

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

go-doudou svc init annotation

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

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

package service
import "context"
//go:generate go-doudou svc http --handler --doc
type Annotation interface {
	// 此接口可公開訪問,無需校驗登錄和權(quán)限
	GetGuest(ctx context.Context) (data string, err error)
	// 此接口只有登錄用戶有權(quán)訪問
	// @role(USER,ADMIN)
	GetUser(ctx context.Context) (data string, err error)
	// 此接口只有管理員有權(quá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僅是一個例子,你還可以定義其他如@permission(create,update,del),以及無參數(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)存中存儲解析出來的注解信息
// ddmodel.AnnotationStore是map[string][]Annotation類型的別名,
// 鍵是路由名稱,值是注解結(jié)構(gòu)體切片。注解結(jié)構(gòu)體中存放了注解名稱和參數(shù)切片,
// 下文我們實(shí)現(xiàn)的校驗權(quán)限的中間件原理就是通過http.Request對象拿到路由名稱,
// 然后用路由名稱從RouteAnnotationStore中找出存儲的注解結(jié)構(gòu)體切片,
// 最后比對從內(nèi)存數(shù)據(jù)源或外部數(shù)據(jù)源拿到的用戶角色和注解結(jié)構(gòu)體的參數(shù)切片中的元素
// 判斷該用戶是否有權(quán)限繼續(xù)訪問接口
var RouteAnnotationStore = ddmodel.AnnotationStore{
	"GetUser": {
		{
			Name: "@role",
			Params: []string{
				"USER",
				"ADMIN",
			},
		},
	},
	"GetAdmin": {
		{
			Name: "@role",
			Params: []string{
				"ADMIN",
			},
		},
	},
}

下載依賴

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

Auth中間件

本示例項目的登錄憑證采用http basic的base64 token。我們打開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的別名類型,鍵為用戶名和密碼構(gòu)成的結(jié)構(gòu)體,值為角色枚舉
// 我們用userStore代表數(shù)據(jù)庫
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()
			// 查詢該路由是否有關(guān)聯(lián)的注解結(jié)構(gòu)體切片
			// 如果沒有,則放行
			if !RouteAnnotationStore.HasAnnotation(routeName, "@role") {
				inner.ServeHTTP(w, r)
				return
			}
			// 從請求頭中提取并解析http basic用戶名和密碼
			user, pass, ok := r.BasicAuth()
			// 如果不成功,則禁止訪問,返回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}]
			// 如果不存在,則禁止訪問,返回401
			if !exists {
				w.Header().Set("WWW-Authenticate", `Basic realm="Provide user name and password"`)
				w.WriteHeader(401)
				w.Write([]byte("Unauthorised.\n"))
				return
			}
			// 如果存在,則判斷該接口是否允許該用戶所屬角色訪問
			params := RouteAnnotationStore.GetParams(routeName, "@role")
			// 判斷該路由的@role注解的參數(shù)切片中是否包含該用戶的角色
			// 如果不包含,則禁止訪問,返回403
			if !sliceutils.StringContains(params, role.StringGetter()) {
				w.WriteHeader(403)
				w.Write([]byte("Access denied\n"))
				return
			}
			// 如果包含,則放行
			inner.ServeHTTP(w, r)
		})
	}
}

至此,我們已經(jīng)完成核心邏輯開發(fā)。最后我們只要把這個中間件加到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()
	// 將上文編寫的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()
}

啟動服務(wù)

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

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

go-doudou svc run

go run cmd/main.go

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

測試效果

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

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

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

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

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

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

相關(guān)文章

  • logrus日志自定義格式操作

    logrus日志自定義格式操作

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

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

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

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

    這篇文章主要為大家介紹了GoFrame框架Scan類型轉(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ù)控制的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • Go語言?Channel通道詳解

    Go語言?Channel通道詳解

    Channel是一個通道,可以通過它讀取和寫入數(shù)據(jù),它就像水管一樣,網(wǎng)絡(luò)數(shù)據(jù)通過Channel 讀取和寫入,這篇文章主要給大家介紹了關(guān)于Go語言?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類型互相轉(zhuǎn)換

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

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

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

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

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

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

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

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

最新評論