最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

go?doudou應用中使用注解示例詳解

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

快速上手

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

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

準備

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

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

本地安裝goland

初始化工程

我們的服務名稱和模塊名稱都叫annotation

go-doudou svc init annotation

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

go-doudou應用的接口定義文件是項目根路徑下的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è)務實際需求,自定義各種不同的注解,@role僅是一個例子,你還可以定義其他如@permission(create,update,del),以及無參數(shù)注解@inner()

生成代碼

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

我們重點看一下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ù)切片,
// 下文我們實現(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,下載項目依賴。此時,服務已經(jīng)可以啟動了,但是我們不急。下面我們要根據(jù)注解信息,編寫中間件,實現(xiàn)我們依據(jù)用戶角色控制訪問權(quán)限的需求。

Auth中間件

本示例項目的登錄憑證采用http basic的base64 token。我們打開transport/httpsrv/middleware.go文件,黏貼進去如下代碼:

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服務里即可。

修改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服務中
	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()
}

啟動服務

啟動服務有多種方式:

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

go-doudou svc run

go run cmd/main.go

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

測試效果

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

注解實現(xiàn)原理

go-doudou實現(xiàn)注解的原理非常簡單,就是通過go語言標準庫ast/parser對接口定義文件svc.go文件中的源碼進行解析,將注釋塊里的注解通過正則表達式提取出來,創(chuàng)建Annotation結(jié)構(gòu)體實例,關(guān)聯(lián)到對應的接口上,最后作為靜態(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é)

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

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

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

相關(guān)文章

  • 用Go語言標準庫實現(xiàn)Web服務之項目介紹

    用Go語言標準庫實現(xiàn)Web服務之項目介紹

    從本節(jié)開始將從后端到前端一步一步實現(xiàn)一個Go語言Web服務,后端除了MySQL驅(qū)動,全部使用Go語言標準庫來實現(xiàn)一個小型項目,本篇將簡單的介紹一下項目開發(fā)要準備的流程,感興趣的同學可以閱讀一下
    2023-05-05
  • Golang語言如何高效拼接字符串詳解

    Golang語言如何高效拼接字符串詳解

    最近在做性能優(yōu)化,有個函數(shù)里面的耗時特別長,看里面的操作大多是一些字符串拼接的操作,而字符串拼接在 golang 里面其實有很多種實現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Golang語言如何高效拼接字符串的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • 詳解Golang中的通道機制與應用

    詳解Golang中的通道機制與應用

    這篇文章主要來和大家一起深入探討了Go語言中通道(Channel)的各個方面,文章詳細解析了通道的類型、操作方法以及垃圾回收機制,有需要的可以了解下
    2023-10-10
  • golang 實現(xiàn)時間滑動窗口的示例代碼

    golang 實現(xiàn)時間滑動窗口的示例代碼

    滑動時間窗口就是把一段時間片分為多個樣本窗口,可以通過更細粒度對數(shù)據(jù)進行統(tǒng)計,這篇文章主要介紹了golang 實現(xiàn)時間滑動窗口,需要的朋友可以參考下
    2022-10-10
  • 淺析golang開發(fā)Error的使用詳解

    淺析golang開發(fā)Error的使用詳解

    Error是Go語言開發(fā)中最基礎(chǔ)也是最重要的部分,很多朋友不明白goland error的一些基本使用方法,今天通過本文給大家詳細介紹下,需要的朋友參考下吧
    2021-07-07
  • Go語言工程實踐單元測試基準測試示例詳解

    Go語言工程實踐單元測試基準測試示例詳解

    這篇文章主要為大家介紹了Go語言工程實踐單元測試基準測試示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Golang 文件操作:刪除指定的文件方式

    Golang 文件操作:刪除指定的文件方式

    這篇文章主要介紹了Golang 文件操作:刪除指定的文件方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 簡單聊聊Golang中Flag包的具體使用

    簡單聊聊Golang中Flag包的具體使用

    flag 包是 Go 語言標準庫中的一個包,用于解析命令行參數(shù),這篇文章主要來和大家簡單聊聊Golang中Flag包的具體使用,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-05-05
  • golang實現(xiàn)http服務器處理靜態(tài)文件示例

    golang實現(xiàn)http服務器處理靜態(tài)文件示例

    這篇文章主要介紹了golang實現(xiàn)http服務器處理靜態(tài)文件的方法,涉及Go語言基于http協(xié)議處理文件的相關(guān)技巧,需要的朋友可以參考下
    2016-07-07
  • 從零封裝Gin框架及項目初始化教程

    從零封裝Gin框架及項目初始化教程

    這篇文章主要為大家介紹了從零封裝Gin框架及項目的初始化教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01

最新評論

白山市| 当涂县| 南宫市| 含山县| 宁国市| 鲁甸县| 鄂州市| 孟州市| 金寨县| 兰考县| 法库县| 濮阳县| 凭祥市| 广东省| 永昌县| 云阳县| 吉木萨尔县| 井研县| 建湖县| 厦门市| 阿拉尔市| 朝阳县| 安多县| 临沧市| 华蓥市| 连平县| 侯马市| 巫溪县| 新兴县| 宁安市| 名山县| 科尔| 定陶县| 乌苏市| 井陉县| 五常市| 遂昌县| 永定县| 洪洞县| 江永县| 肇州县|