1. 程式人生 > >go-admin線上開發平臺學習-3[細節解析]

go-admin線上開發平臺學習-3[細節解析]

本章節主要的內容是對go-admin中的一些有趣編碼進行分析,為自己以後提供一些借鑑 ## 使用cli方式啟動專案 使用cobra[眼鏡蛇]完成強壯cli的工具,確保穩定。 使用cli的方式啟動專案的好處顯而易見,可以在進行配置的自定義化,而不是固定的使用某個配置檔案中的資訊。在一些需要頻繁更換命令引數的場景下尤為有效。 cobra的使用有一個預設的規定,即新建一個``cmd``資料夾,基於這個資料夾定義自己的命令結構 1、小型專案 cmd 資料夾 -- root.go 根命令 -- version.go 版本命令【子命令】 2、中/大型專案 cmd 資料夾 --version 資料夾 ​ --server.go --config 資料夾 ​ --server.go -- root.go 入口指令 不同的專案選用不同的方式進行命令的定義。 ## 監聽中斷訊號 ``` // 等待中斷訊號以優雅地關閉伺服器(設定 5 秒的超時時間) quit := make(chan os.Signal) signal.Notify(quit, os.Interrupt) <-quit fmt.Printf("%s Shutdown Server ... \r\n", tools.GetCurrentTimeStr()) if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } log.Info("Server exiting") ``` 訊號監聽,當遇到ctrl+c的時候當前服務結束,列印結束日誌 ## 配置檔案Viper的使用 viper的使用,配置檔案路徑,獲取viper根類 ``` //資料庫配置 cfgDatabase = viper.Sub("settings.database") DatabaseConfig = InitDatabase(cfgDatabase) //應用程式配置 cfgApplication = viper.Sub("settings.application") ApplicationConfig = InitApplication(cfgApplication) ``` 其他的內容與此方式類似 viper.Sub獲取對應分類的內容,然後使用自定義的Init***函式初使化類 --- /tools/config資料夾中定義實體類,對應config.yml中的分類 舉例:application.go對應圖二的application分類內容,其他的也是同樣意思 ![image-20210218155728868](https://gitee.com/happlyfox/img/raw/master/image-20210218155728868.png) 此目錄下的內容,package包名為config。config下的配置資訊使用大寫表示【對外暴露】。如果其他地方要呼叫,引用包後使用config.分類名稱.引數 即可得到配置檔案的內容 ## 初始化資料庫 配置檔案 dirver:mysql,定義不同的資料庫字串,程式啟動時case 連線字串,對不同的資料庫型別做不同的配置 資料庫日誌開關作為單獨配置區分,如果開啟,資料庫日誌單獨啟用 現在程式的資料庫.go都需要實現介面如下 ``` type Database interface { Setup() Open(conn string, cfg *gorm.Config) (db *gorm.DB, err error) GetConnect() string GetDriver() string } ``` ![image-20210218161101421](https://gitee.com/happlyfox/img/raw/master/image-20210218161101421.png) interface定義介面,其他的go檔案實現介面-使用不同的開源資料庫驅動 ## 介面訪問控制 casbin 輕量級開源訪問控制框架,採用了元模型的設計思想,支援多種經典的訪問控制方案,如基於角色的訪問控制 RBAC、基於屬性的訪問控制 ABAC 等 **策略檔案** ``` // Initialize the model from a string. var text = ` [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.sub == p.sub && (keyMatch2(r.obj, p.obj) || keyMatch(r.obj, p.obj)) && (r.act == p.act || p.act == "*") ` ``` 使用 ``github.com/casbin/gorm-adapter/v3``作為casbin的資料庫介面卡即可 ## 資料庫上下文整合gin gin一次請求共用一個數據庫例項 ![image-20210218162726796](https://gitee.com/happlyfox/img/raw/master/image-20210218162726796.png) ![image-20210218162715014](https://gitee.com/happlyfox/img/raw/master/image-20210218162715014.png) r.Use()是gin的中介軟體擴充套件方法,WithContextDb方法說明的是,如果每次請求到來會開啟一次資料庫連結,獲得資料庫連結例項,將例項返回後作為引數傳遞給方法。如果有此例項,c.Set()方法執行,將此例項儲存到gin執行上下文中。 ## 全域性異常處理 使用一個異常捕獲方法recover()補獲未知曉的異常 如果異常訊息符合定義的規則,列印後返回給前臺。 如果無異常,正常執行下一個定義的中介軟體 ``` r.Use(CustomError) ``` ``` func CustomError(c *gin.Context) { defer func() { if err := recover(); err != nil { if c.IsAborted() { c.Status(200) } switch errStr := err.(type) { case string: p := strings.Split(errStr, "#") if len(p) == 3 && p[0] == "CustomError" { statusCode, e := strconv.Atoi(p[1]) if e != nil { break } c.Status(statusCode) fmt.Println( time.Now().Format("2006-01-02 15:04:05"), "[ERROR]", c.Request.Method, c.Request.URL, statusCode, c.Request.RequestURI, c.ClientIP(), p[2], ) c.JSON(http.StatusOK, gin.H{ "code": statusCode, "msg": p[2], }) } default: panic(err) } } }() c.Next() } ``` ## web服務執行區分ssl和正常 從配置檔案中獲取內容,定義addr 得到對應的web執行引擎,當前使用**gin** 啟動一個協程,判斷如果ssl,使用TlS方法。否則使用正常模式 ``` srv := &http.Server{ Addr: config.ApplicationConfig.Host + ":" + config.ApplicationConfig.Port, Handler: global.Cfg.GetEngine(), } go func() { // 服務連線 if config.SslConfig.Enable { if err := srv.ListenAndServeTLS(config.SslConfig.Pem, config.SslConfig.KeyStr); err != nil && err != http.ErrServerClosed { log.Fatal("listen: ", err) } } else { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal("listen: ", err) } }