GoWeb脚手架的搭建
以下内容搭建一个Go Web较为通用的脚手架模板,使用CLD分层模式
一、加载配置文件
1、增加conf.yaml文件
app:
name: "web_app"
mode: "dev"
port: 8080
log:
level: "debug"
filename: "conf"
max_size: 200
max_age: 30
max_backups: 7
mysql:
host: "127.0.0.1"
port: "3306"
user: "root"
password: "root"
dbname: "Test"
redis:
host: "127.0.0.1"
port: 6379
2、新建setting包将配置绑定结构体
package setting
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
type Config struct{
App
Log
Mysql
Redis
}
type App struct{
Name string `mapstructure:"name"`
Mode string `mapstructure:"mode"`
Port int `mapstructure:"port"`
}
type Log struct{
Level string `mapstructure:"level"`
Filename string `mapstructure:"filename"`
Max_size int `mapstructure:"max_size"`
Max_age int `mapstructure:"max_age"`
Max_backups int `mapstructure:"max_backups"`
}
type Mysql struct{
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
Dbname string `mapstructure:"dbname"`
}
type Redis struct{
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
}
var Conf =&Config{}
func InitConfig(){
viper.SetConfigName("conf")
viper.AddConfigPath("Conf")
err:=viper.ReadInConfig()
if err!=nil{
if v,ok:=err.(viper.ConfigFileNotFoundError);ok{
fmt.Println(v)
}else{
panic(fmt.Errorf("read config err=%s",err))
}
}
err=viper.Unmarshal(Conf)
if err!=nil{
fmt.Println("This Unmarshal Err",err)
return
}
viper.WatchConfig()
viper.OnConfigChange(func(in fsnotify.Event) {
//Can Add Some Logics
fmt.Println("Config Was Changed",in.Name)
})
}
二、初始化配置文件
1、初始化日志log(zap日志系统)
所需要的配置信息尽量从配置中获取,不直接设置
package Log
import (
"GinFrameDemo/setting"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var logger *zap.Logger //global variable
func InitLog(){
encoder:=getEncoder()
writer:=getWriter()
core:=zapcore.NewCore(encoder,writer,zapcore.DebugLevel) //get core,this is New method first param
logger=zap.New(core,zap.AddCaller()) //return my logger
}
func getEncoder() zapcore.Encoder{
encoderConfig := zap.NewProductionEncoderConfig() //Add Encoding Config
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder //Add Time Config
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder //Add Big Writer
return zapcore.NewJSONEncoder(encoderConfig) //return core Add encoderConfig,ago Add zap.NewProductionEncoderConfig()
}
func getWriter()zapcore.WriteSyncer{
lumberJackLogger := &lumberjack.Logger{
Filename: setting.Conf.Filename,
MaxSize: setting.Conf.Max_size, //one Max Size
MaxBackups: setting.Conf.Max_backups, //beifen
MaxAge: setting.Conf.Max_age, //this time
Compress: setting.Conf.IsCompress, //zip
}
return zapcore.AddSync(lumberJackLogger)
}
注意:可能会使用gcc,需要在linux中下载gcc
sudo apt install gcc
2、初始化mysql配置
var DB *gorm.DB
func InitMysql(){
var err error
//dsn:="UserName:password@tcp(ip:port)/databaseName?charset=utf8mb4&parseTime=true&loc=local"
dsn := "root:root@tcp(127.0.0.1:3306)/testgorm?charset=utf8mb4&parseTime=True&loc=Local"
DB,err=gorm.Open(mysql.Open(dsn),&gorm.Config{}) //Open the Database
if err!=nil{
Log.Logger.Error("Gorm Open Error", zap.Error(err))
}
}
3、初始化redis操作
var (
rdb *redis.Client
)
func InitRedis() (err error) {
rdb = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "root", // password
DB: 0, // use default DB
PoolSize: 100, // Redis Pool Size
})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err = rdb.Ping(ctx).Result()
return err
}
注意:替换全局的logger
三、注册路由
将Gin中注册路由信息,返回r
//RegisterRouter
r:=Router.SetUpRouter() //Register Router IN This
//在Router包中
package Router
import (
"GinFrameDemo/Log"
"github.com/gin-gonic/gin"
)
func SetUpRouter() *gin.Engine{
r:=gin.New() //if use Default ,will use default`s Router and middleware
r.Use(Log.GinLogger(),Log.GinRecovery(true))
r.GET("/", func(c *gin.Context) {
c.JSON(200,gin.H{
"message":"hello gin",
})
})
return r
}
注意:注册zap的log中间件在gin中
四、优雅关机与平滑重启
默认路由
func SetUpRouter() *gin.Engine{
r:=gin.New() //if use Default ,will use default`s Router and middleware
r.Use(Log.GinLogger(),Log.GinRecovery(true))
r.GET("/", func(c *gin.Context) {
c.JSON(200,gin.H{
"message":"hello gin",
})
})
return r
}
设置路由并且设置平滑开机与重启
//RegisterRouter
r:=Router.SetUpRouter() //Register Router IN This
//StartService
srv:=&http.Server{
Addr: fmt.Sprintf("%d",setting.Conf.App.Port), // Listen TCP Adress,if eq nil ,will become ":http"
Handler: r, // Is Controller,if eq nil will call http.DefaultServeMux
}
go func(){
if err:=srv.ListenAndServe();err!=nil&&err!=http.ErrServerClosed{
log.Fatalf("Listen is %s",err)
}
}() //New goroutine Listen Get conn
quit:=make(chan os.Signal,1) //Create a Chanel Get Sign
//First Send syscall.SIGTERM
//Syscall.SIGINT Like Ctrl+C
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) //Mustbe Get All Sign
<-quit
log.Println("Shutdown Server ...") //When Get SignInt Start Kill
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) //Set 5s After Kill
defer cancel()
if err := srv.Shutdown(ctx); err != nil { //Beatiful Abort
log.Fatal("Server Shutdown: ", err)
}
log.Println("Server exiting")
如果看完这篇文章对自己有所帮助,请点赞支持,谢谢大家