routing

This is relatively simple, is the role of the registration route

package route import ( "go_web_app/logger" "net/http" "github.com/gin-gonic/gin" ) func Setup() *gin.Engine { r := R.us (logger.ginlogger (), logger.ginRecovery (true)) r.git ("/", func(context *gin.Context) { context.String(http.StatusOK, "ok") }) return r }Copy the code

Start the process

This one was introduced earlier, which is a slightly more sophisticated and elegant reboot scheme,

SRV := &http.Server{Addr: ftt.sprintf (":%d", viper.getint ("app.port"))), Handler: R,} go func() {// Start a goroutine start service if err := srv.listenAndServe (); err ! = nil && err ! = http.ErrServerClosed { zap.L().Error("listen: %s\n", zap.error (err))}}() // Wait for an interrupt signal to gracefully shut down the server, Quit := make(chan os.signal, Syscall. SIGTERM // kill -2 sends syscall.SIGINT, // Syscall.SIGKILL -9 sends the syscall.SIGKILL signal, but it cannot be captured. SIGINT (quit, syscall.sigint, syscall.sigterm, syscall.sigterm, syscall.sigterm, Syscall.sigterm) // will not block here <-quit // will block here Zap.l ().info ("Shutdown server") // Create a context CTX with a timeout of 5 seconds, Cancel := context.withtimeout (context.background (), 5* time.second) defer cancel() // Gracefully close the service within 5 seconds. If err := srv.Shutdown(CTX); err ! = nil { log.Fatal("Server Shutdown: ", err) zap.L().Error("Server Shutdown: ", zap.Error(err)) } zap.L().Info("Server exiting")Copy the code

Optimize the code. – DON’t expose the DB

In the previous code, it was not appropriate to expose the DB. The best solution is to provide a close method so that the method does not expose the DB

// initialize mysql if err := mysql.init (); err ! = nil { fmt.Printf("init mysql failed:%s \n", Err) return} zap.l ().debug ("mysql init success") // Initialize redis if err := redis.init (); err ! = nil { fmt.Printf("init redis failed:%s \n", err) return } defer mysql.Close() defer redis.Close()Copy the code
var db *sqlx.DB func Close() { _ = db.Close() } func Init() (err error) { dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s? charset=utf8mb4&parseTime=True", viper.GetString("mysql.user"), viper.GetString("mysql.password"), viper.GetString("mysql.host"), viper.GetInt("mysql.port"), viper.GetString("mysql.dbname"), ) // You can also use MustConnect to panic db, err = sqlx.Connect("mysql", DSN) if err! = nil { zap.L().Error("connect DB failed, err:%v\n", zap.Error(err)) return } db.SetMaxOpenConns(viper.GetInt("mysql.max_open_connection")) db.SetMaxIdleConns(viper.GetInt("mysql.max_idle_connection")) return }Copy the code

Optimized configuration item

The previous configuration items are fetched by string, which is not very readable. Now we need to find a way to convert config into a structure to handle this, so that the code will be more readable

type AppConfig struct {
   Name         string `mapstructure:"name"`
   Mode         string `mapstructure:"mode"`
   Port         int    `mapstructure:"port"`
   *LogConfig   `mapstructure:"log"`
   *MysqlConfig `mapstructure:"mysql"`
   *RedisConfig `mapstructure:"redis"`
}

type LogConfig struct {
   Level      string `mapstructure:"level"`
   FileName   string `mapstructure:"filename"`
   MaxSize    int    `mapstructure:"max_size"`
   MaxAge     int    `mapstructure:"max_age"`
   MaxBackups int    `mapstructure:"max_backups"`
}

type MysqlConfig struct {
   Host              string `mapstructure:"host"`
   Port              int    `mapstructure:"port"`
   User              string `mapstructure:"user"`
   Password          string `mapstructure:"password"`
   DbName            string `mapstructure:"dbname"`
   MaxOpenConnection int    `mapstructure:"max_open_connection"`
   MaxIdleConnection int    `mapstructure:"max_idle_connection"`
}

type RedisConfig struct {
   Host     string `mapstructure:"host"`
   Password string `mapstructure:"passowrd"`
   Post     int    `mapstructure:"port"`
   Db       int    `mapstructure:"db"`
   PoolSize int    `mapstructure:"pool_size"`
}
Copy the code

And then we change our viper reading process which is basically serialization

Var Config = new(AppConfig) // Init Load configuration file func Init() error {per.setConfigname (" Config ") // Name of configuration file Viper. setType ("yaml") // The extension of the configuration file. Err := per.readinConfig () if err! = nil {fmt.Println("viper init failed:", err) return err} if err := per.unmarshal (Config); err ! = nil { fmt.Println("viper Unmarshal err", Err)} per.watchConfig () per.onConfigChange (func(in fsnotify.event) {fmt.println (" Config file has been modified ")}) return err}Copy the code

Modify mysql init method to pass a mysql config parameter

func Init(config *setting.MysqlConfig) (err error) { dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s? charset=utf8mb4&parseTime=True", config.User, config.Password, config.Host, config.Port, config.DbName, Err := sqlx.Connect("mysql", DSN) if err! = nil { zap.L().Error("connect DB failed, err:%v\n", zap.Error(err)) return } db.SetMaxOpenConns(viper.GetInt("mysql.max_open_connection")) db.SetMaxIdleConns(viper.GetInt("mysql.max_idle_connection")) return }Copy the code

That’s all you need to use it

/ / initialized mysql if err: = mysql. The Init (setting. Config. MysqlConfig); err ! = nil { fmt.Printf("init mysql failed:%s \n", err) return }Copy the code

The source address