加速開(kāi)發(fā):使用Go語(yǔ)言和Gin框架構(gòu)建Web項(xiàng)目的利器
節(jié)省時(shí)間與精力,更高效地打造穩(wěn)定可靠的Web項(xiàng)目:基于Go語(yǔ)言和Gin框架的完善Web項(xiàng)目骨架。無(wú)需從零開(kāi)始,直接利用這個(gè)骨架,快速搭建一個(gè)功能齊全、性能優(yōu)異的Web應(yīng)用。充分發(fā)揮Go語(yǔ)言和Gin框架的優(yōu)勢(shì),輕松處理高并發(fā)、大流量的請(qǐng)求。構(gòu)建可擴(kuò)展性強(qiáng)、易于維護(hù)的代碼架構(gòu),保證項(xiàng)目的長(zhǎng)期穩(wěn)定運(yùn)行。同時(shí),通過(guò)集成常用功能模塊和最佳實(shí)踐,減少繁瑣的開(kāi)發(fā)工作,使您專(zhuān)注于業(yè)務(wù)邏輯的實(shí)現(xiàn)。
該骨架每個(gè)組件之間可單獨(dú)使用,組件之間松耦合,高內(nèi)聚,組件的實(shí)現(xiàn)基于其他三方依賴(lài)包的封裝。
目前該骨架實(shí)現(xiàn)了大多數(shù)的組件,比如事件
,中間件
,日志
,配置
,參數(shù)驗(yàn)證
,命令行
,定時(shí)任務(wù)
等功能,目前可以滿(mǎn)足大多數(shù)開(kāi)發(fā)需求,后續(xù)會(huì)持續(xù)維護(hù)更新功能。
github地址:https://github.com/czx-lab/skeleton
設(shè)置環(huán)境變量并下載項(xiàng)目依賴(lài)
go env -w GO111MODULE=on go env -w GOPROXY=https://goproxy.cn,direct go mod download
運(yùn)行項(xiàng)目
go run ./cmd/main.go
項(xiàng)目編譯打包運(yùn)行
go build ./cmd/main.go // 編譯 make build // 運(yùn)行 make run // 編譯與運(yùn)行 make // 運(yùn)行項(xiàng)目 ./main
項(xiàng)目目錄結(jié)構(gòu)說(shuō)明
├─app │ ├─command ---> 命令行 │ ├─controller │ │ └─base.go ---> BaseController,主要定義了request參數(shù)驗(yàn)證器validator │ ├─event │ │ ├─entity ---> 事件實(shí)體目錄 │ │ ├─listen ---> 事件監(jiān)聽(tīng)執(zhí)行腳本目錄 │ │ └─event.go ---> 事件注冊(cè)代碼 │ │ │ ├─middleware ---> 中間件代碼目錄 │ ├─request ---> 請(qǐng)求參數(shù)校驗(yàn)代碼目錄 │ │ └─request.go ---> 參數(shù)驗(yàn)證器 │ └─task ---> 定時(shí)任務(wù)代碼目錄 │ └─task.go ---> 注冊(cè)定時(shí)任務(wù)腳本 ├─cmd ---> 項(xiàng)目入口目錄 │ └─cli ---> 項(xiàng)目命令行模式入口目錄 ├─config │ └─config.yaml ---> 配置文件 ├─internal ---> 包含第三方包的封裝 ├─router ---> 路由目錄 │ └─router.go ├─storage ---> 日志、資源存儲(chǔ)目錄 │ └─logs └─test ---> 單元測(cè)試目錄
基礎(chǔ)功能
路由
該骨架的web框架是gin,所以路由定義可直接閱讀Gin框架的文檔。
在該骨架中定義注冊(cè)路由需要在router
文件夾下面的router.go
文件中的func (*AppRouter) Add(server *gin.Engine)
方法定義注冊(cè):
server.GET("/foo", func(ctx *gin.Context) { ctx.String(http.StatusOK, "hello word!") })
也可以通過(guò)自己定義路由的定義注冊(cè),只需要實(shí)現(xiàn)github.com/czx-lab/skeleton/internal/server/router
下面的Interface
接口。如下示例:
在router目錄下定義了一個(gè)CustomRouter
結(jié)構(gòu)體,該結(jié)構(gòu)體實(shí)現(xiàn)了Interface
接口
package router import ( "net/http" "skeleton/internal/server" "github.com/gin-gonic/gin" ) type CustomRouter struct { server server.HttpServer } func NewCustom(srv server.HttpServer) *CustomRouter { return &CustomRouter{ srv, } } func (*CustomRouter) Add(srv *gin.Engine) { srv.GET("/custom", func(ctx *gin.Context) { ctx.String(http.StatusOK, "custom router") }) }
需要注意的是,如果是自定義路由注冊(cè),需要修改項(xiàng)目
cmd
文件夾下面的main.go
入口文件,通過(guò)http.SetRouters(router.NewCustom(http))
注冊(cè)給gin
中間件
定義中間件與gin
框架一樣,該估計(jì)默認(rèn)實(shí)現(xiàn)了panic異常的中間件,可以查看internal/server/middleware
文件夾中的exception.go
文件。
如果需要定義其他的中間件并加載注冊(cè),可以將定義好的中間件通過(guò)server.HttpServer
接口的SetMiddleware(middlewares ...middleware.Interface)
方法注冊(cè)加載,
比如我們實(shí)現(xiàn)如下自定義全局中間件middleware/custom.go
:
type Custom struct{} func (c *Custom) Handle() gin.HandlerFunc { return func(ctx *gin.Context) { fmt.Println("Custom middleware exec...") } }
然后在定義路由的地方使用server.SetMiddleware(&middleware.Custom{})
注冊(cè)中間件。
定義全局路由中間件可以參考router/router.go
中的New
方法。
如果是局部中間件,可以直接在具體的路由上注冊(cè),參考gin路由中間件的用法
日志
在該骨架中的日志是直接對(duì)go.uber.org/zap
的封裝,使用時(shí),直接通過(guò)全局變量variable.Log
訪問(wèn)寫(xiě)入日志,可直接使用zap支持的所有方法。
package demo import "skeleton/internal/variable" func Demo() { variable.Log.Info("info message") }
日志文件默認(rèn)是以json
格式寫(xiě)入到storage/logs/system.log
里面
配置
配置項(xiàng)的定義直接在config/config.yaml
文件中定義,并且配置的讀取寫(xiě)入是通過(guò)封裝github.com/spf13/viper
實(shí)現(xiàn),在該骨架中,只提供了如下一些獲取配置的方法:
type ConfigInterface interface { Get(key string) any GetString(key string) string GetBool(key string) bool GetInt(key string) int GetInt32(key string) int32 GetInt64(key string) int64 GetFloat64(key string) float64 GetDuration(key string) time.Duration GetStringSlice(key string) []string }
需要注意的是,骨架中對(duì)配置項(xiàng)的獲取做了緩存的處理,第一次加載是在文件中獲取,后面每次回去都是在cache
中獲取,目前cache
默認(rèn)只支持memory
,骨架中也支持自定義cache
的方法,只需要實(shí)現(xiàn)config.CacheInterface
接口就可以,比如需要使用redis
作為配置緩存,可以通過(guò)下面的方式處理:
type ConfigRedisCache struct {} var _ config.CacheInterface = (*ConfigRedisCache)(nil) func (c *ConfigRedisCache) Get(key string) any { return nil } func (c *ConfigRedisCache) Set(key string, value any) bool { return true } func (c *ConfigRedisCache) Has(key string) bool { return true } func (c *ConfigRedisCache) FuzzyDelete(key string) { }
然后將ConfigRedisCache
結(jié)構(gòu)體配置到config.Options
中,如下所示,修改internal/bootstrap/init.go
初始化配置的方法:
variable.Config, err := config.New(driver.New(), config.Options{ BasePath: './', Cache: &ConfigRedisCache{} })
config.yaml
基礎(chǔ)配置如下:
# http配置 HttpServer: Port: ":8888" # 服務(wù)模式,和gin的gin.SetMode的值是一樣的 Mode: "debug" # socket配置 Websocket: WriteReadBufferSize: 2048 HeartbeatFailMaxTimes: 4 PingPeriod: 20 ReadDeadline: 100 WriteDeadline: 35 PingMsg: "ping" # 數(shù)據(jù)庫(kù)配置 Database: # 可以查看GORM相關(guān)的配置選項(xiàng) Mysql: SlowThreshold: 5 LogLevel: 4 ConnMaxLifetime: 1 MaxIdleConn: 2 MaxOpenConn: 2 ConnMaxIdleTime: 12 Reade: - "root:root@tcp(192.168.1.4:3306)/test?charset=utf8mb4&loc=Local&parseTime=True" Write: "root:root@tcp(192.168.1.4:3306)/test?charset=utf8mb4&loc=Local&parseTime=True" # mongo數(shù)據(jù)庫(kù)的基礎(chǔ)配置 Mongo: Enable: false Uri: MinPoolSize: 10 MaxPoolSize: 20 Redis: Disabled: false Addr: "192.168.1.4:6379" Pwd: "" Db: 0 PoolSize: 20 MaxIdleConn: 30 MinIdleConn: 10 # 單位(秒) MaxLifeTime: 60 # 單位(分) MaxIdleTime: 30 # 定時(shí)任務(wù) Crontab: Enable: true # 消息隊(duì)列,使用rocketmq MQ: Enable: false Servers: - "127.0.0.1:9876" ConsumptionSize: 1 Retries: 1
事件機(jī)制
定義事件實(shí)體
在
app/event/entity
目錄下定義一個(gè)事件實(shí)體,該實(shí)體實(shí)現(xiàn)了event.EventInterface
接口:package entity type DemoEvent struct {} func (d *DemoEvent) EventName() string { return "demo-event" } func (d *DemoEvent) GetData() any { return "demo param" }
定義事件監(jiān)聽(tīng)
在
app/event/listen
目錄中定義一個(gè)DemoEventListen
事件監(jiān)聽(tīng),并且該DemoEventListen
結(jié)構(gòu)體必須要實(shí)現(xiàn)event.Interface
接口:package listen import ( "fmt" event2 "skeleton/app/event/entity" "skeleton/internal/event" ) type DemoEventListen struct { } func (*DemoEventListen) Listen() event.EventInterface { return &event2.DemoEvent{} } func (*DemoEventListen) Process(data any) (any, error) { return fmt.Sprintf("%v --> %s", data, "exec DemoEventListen.Process"), nil }
最后需要將事件進(jìn)行注冊(cè),在
app/event/event.go
文件中的Init
方法內(nèi)執(zhí)行:variable.Event.Register(&listen.DemoEventListen{})
調(diào)用事件執(zhí)行
variable.Event.Dispatch(&entity.DemoEvent{})
驗(yàn)證器
gin框架本身內(nèi)置了validator
校驗(yàn),骨架里面只是對(duì)其參數(shù)的校驗(yàn)做了統(tǒng)一的校驗(yàn)入口。
通過(guò)如下方式獲取進(jìn)行參數(shù)的校驗(yàn),并設(shè)置中文錯(cuò)誤提示:
type Param struct { Name int `binding:"required" form:"name" query:"name" json:"name"` } appRequest, err := AppRequest.New("zh") if err != nil { return } var data Param errMap := appRequest.Validator(ctx, &data) fmt.Println(errMap)
骨架里面已經(jīng)實(shí)現(xiàn)了默認(rèn)的參數(shù)校驗(yàn),可以在app/request/request.go
文件中查看。并且在controller
目錄中base.go
有一個(gè)Validate(ctx *gin.Context, param any)
方法,在其他controller中要進(jìn)行參數(shù)校驗(yàn)的時(shí)候,只需要繼承base
結(jié)構(gòu)體,然后調(diào)用Validate
方法。
package controller import "github.com/gin-gonic/gin" type DemoController struct { base } type DemoRequest struct { Id int `binding:"required" form:"id" query:"id" json:"id"` } func (d *DemoController) Index(ctx *gin.Context) { var param DemoRequest if err := d.base.Validate(ctx, ¶m); err == nil { ctx.JSON(http.StatusOK, gin.H{"data": param}) } else { ctx.JSON(http.StatusBadRequest, gin.H{"message": err}) } }
驗(yàn)證規(guī)格參考
github.com/go-playground/validator
官方文檔
命令行
基于github.com/spf13/cobra
封裝
定義命令
在
app/command
目錄中定義自己的命令,比如自定義一個(gè)輸出success ok
的命令package command import ( "fmt" "github.com/spf13/cobra" ) type FooCommand struct {} func (f *FooCommand) Command() *cobra.Command { return &cobra.Command{ Use: "foo", Short: "命令使用簡(jiǎn)介.", Long: `命令介紹.`, Run: func(cmd *cobra.Command, args []string) { str, _ := cmd.Flags().GetString("name") fmt.Printf("success, %s", str) }, } } func (f *FooCommand) Flags(root *cobra.Command) { root.PersistentFlags().String("name", "", "命令參數(shù)") }
注冊(cè)命令
需要在
cmd/cli/cli.go
中的main
方法內(nèi)注冊(cè)自定義命令。執(zhí)行命令
go run cmd/cli/cli.go foo --name ok
查看命令信息
go run cmd/cli/cli.go help // 或者 go run cmd/cli/cli.go foo --help
定時(shí)任務(wù)
定時(shí)是通過(guò)封裝github.com/robfig/cron/v3
實(shí)現(xiàn)
定義定時(shí)任務(wù)方法
在
app/task
目錄下定義執(zhí)行方法,比如每一分鐘打印success
字符package task import "fmt" type SuccessTask struct { } // 時(shí)間規(guī)則 func (s *SuccessTask) Rule() string { return "* * * * *" } func (s *SuccessTask) Execute() func() { return func() { fmt.Println("success") } }
加載定時(shí)任務(wù)
需要在
app/task/task.go
文件中的Tasks
方法內(nèi),加載自定義的任務(wù),參考task目錄下的task.go
文件
Go語(yǔ)言和Gin框架是開(kāi)發(fā)高性能Web項(xiàng)目的理想選擇。Go語(yǔ)言以其簡(jiǎn)潔性、高效性和并發(fā)性而聞名,使開(kāi)發(fā)者能夠編寫(xiě)可靠且高性能的代碼。而Gin框架是一個(gè)輕量級(jí)的Web框架,具有快速的路由能力和豐富的中間件支持,使開(kāi)發(fā)者能夠快速構(gòu)建靈活且可擴(kuò)展的Web應(yīng)用程序。使用Go語(yǔ)言和Gin框架,開(kāi)發(fā)者可以享受到高效的開(kāi)發(fā)過(guò)程和出色的性能表現(xiàn)。無(wú)論是構(gòu)建小型項(xiàng)目還是大型應(yīng)用程序,Go語(yǔ)言和Gin框架都能為開(kāi)發(fā)者提供強(qiáng)大的工具和優(yōu)化的性能,使開(kāi)發(fā)過(guò)程更加高效和愉快。
到此這篇關(guān)于加速開(kāi)發(fā):使用Go語(yǔ)言和Gin框架構(gòu)建Web項(xiàng)目的利器的文章就介紹到這了,更多相關(guān)基于go語(yǔ)言gin框架的web項(xiàng)目骨架 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go計(jì)算某段代碼運(yùn)行所耗時(shí)間簡(jiǎn)單實(shí)例
這篇文章主要給大家介紹了關(guān)于Go計(jì)算某段代碼運(yùn)行所耗時(shí)間的相關(guān)資料,主要介紹了Golang記錄計(jì)算函數(shù)執(zhí)行耗時(shí)、運(yùn)行時(shí)間的一個(gè)簡(jiǎn)單方法,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下2023-11-11golang類(lèi)型轉(zhuǎn)換之interface轉(zhuǎn)字符串string簡(jiǎn)單示例
在我們使用Golang進(jìn)行開(kāi)發(fā)過(guò)程中,總是繞不開(kāi)對(duì)字符或字符串的處理,這篇文章主要給大家介紹了關(guān)于golang類(lèi)型轉(zhuǎn)換之interface轉(zhuǎn)字符串string的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01Golang實(shí)現(xiàn)優(yōu)雅的將struct轉(zhuǎn)換為map
在項(xiàng)目實(shí)踐中,有時(shí)候我們需要將struct結(jié)構(gòu)體轉(zhuǎn)為map映射表,然后基于map做數(shù)據(jù)裁剪或操作。那么下面我來(lái)介紹下常用的兩種轉(zhuǎn)換方式,希望對(duì)大家有所幫助2023-01-01GoLang并發(fā)機(jī)制探究goroutine原理詳細(xì)講解
goroutine是Go語(yǔ)言提供的語(yǔ)言級(jí)別的輕量級(jí)線(xiàn)程,在我們需要使用并發(fā)時(shí),我們只需要通過(guò) go 關(guān)鍵字來(lái)開(kāi)啟 goroutine 即可。這篇文章主要介紹了GoLang并發(fā)機(jī)制goroutine原理,感興趣的可以了解一下2022-12-12Go語(yǔ)言實(shí)現(xiàn)多協(xié)程文件下載器的過(guò)程詳解
這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)多協(xié)程文件下載器的相關(guān)資料,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-08-08Go語(yǔ)言實(shí)現(xiàn)Snowflake雪花算法
雪花算法產(chǎn)生的背景當(dāng)然是twitter高并發(fā)環(huán)境下對(duì)唯一ID生成的需求,得益于twitter內(nèi)部牛的技術(shù),雪花算法能夠流傳于至今并且被廣泛使用,本文就詳細(xì)的介紹一下,感興趣的可以了解一下2021-06-06