36-搭建通用web开发脚手架

36-搭建通用web开发脚手架_第1张图片

脚手架目录结构

1、配置管理

项目目录下创建setting/setting.go:

package setting

import (
	"fmt"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

// Conf 定义配置的全局变量
var Conf = new(AppConfig)

type AppConfig struct {
	Name      string `mapstructure:"name"`
	Mode      string `mapstructure:"mode"`
	Version   string `mapstructure:"version"`
	StartTime string `mapstructure:"start_time"`
	MachineID int64  `mapstructure:"machine_id"`
	Port      int    `mapstructure:"port"`

	*LogConfig   `mapstructure:"log"`
	*MySQLConfig `mapstructure:"mysql"`
	*RedisConfig `mapstructure:"redis"`
}

type MySQLConfig struct {
	Host         string `mapstructure:"host"`
	User         string `mapstructure:"user"`
	Password     string `mapstructure:"password"`
	DB           string `mapstructure:"dbname"`
	Port         int    `mapstructure:"port"`
	MaxOpenConns int    `mapstructure:"max_open_conns"`
	MaxIdleConns int    `mapstructure:"max_idle_conns"`
}

type RedisConfig struct {
	Host         string `mapstructure:"host"`
	Password     string `mapstructure:"password"`
	Port         int    `mapstructure:"port"`
	DB           int    `mapstructure:"db"`
	PoolSize     int    `mapstructure:"pool_size"`
	MinIdleConns int    `mapstructure:"min_idle_conns"`
}

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"`
}

// 配置相关

// Init 配置初始化
func Init(filePath string) (err error) {
	// 指定配置文件路径
	viper.SetConfigFile(filePath)
	// 读取配置信息
	err = viper.ReadInConfig()
	if err != nil {
		// 读取配置信息失败
		fmt.Printf("viper.ReadInConfig failed, err:%v\n", err)
		return
	}

	// 把读取到的配置信息反序列化到 Conf 变量中
	if err := viper.Unmarshal(Conf); err != nil {
		fmt.Printf("viper.Unmarshal failed, err:%v\n", err)
		return err
	}
	// 监听配置文件变化
	viper.WatchConfig()

	// 当使用结构体变量存储配置的时候,需要在配置发生变更后手动更新一下结构体变量
	viper.OnConfigChange(func(in fsnotify.Event) {
		fmt.Println("配置文件修改了...")
		if err := viper.Unmarshal(Conf); err != nil {
			fmt.Printf("viper.Unmarshal failed, err:%v\n", err)
		}
	})
	return nil
}

在conf/conf.yaml配置:

name: myapp
mode: dev
version: "1.0"
port: 8099

log:
  level: debug
  filename: myapp.log
  max_size: 400
  max_age: 30
  max_backups: 15

  mysql:
    host: 127.0.0.1
    port: 3306
    user: root
    password: root1234
    db: db1
    MaxOpenConns: 20
    MaxIdleConns: 2

2、logger从配置文件读取

Logger/logger.go

package logger

import (
	"gin_zap/setting"
	"strings"

	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// initlogger 初始化日志
func Init() (err error) {
	// 1、encoder
	encndercfg := zap.NewProductionEncoderConfig()
	encndercfg.TimeKey = "time"                          // 改变时间的key
	encndercfg.EncodeTime = zapcore.ISO8601TimeEncoder   // 更改时间格式
	encndercfg.EncodeLevel = zapcore.CapitalLevelEncoder //将日志级别大写并带有颜色
	enconder := zapcore.NewJSONEncoder(encndercfg)

	// 2、writerSyncer 将日志写到文件和终端
	lumberJackLogger1 := &lumberjack.Logger{
		Filename:   setting.Conf.LogConfig.Filename, // 从配置文件读取
		MaxSize:    setting.Conf.LogConfig.MaxSize,
		MaxBackups: setting.Conf.LogConfig.MaxBackups,
		MaxAge:     setting.Conf.LogConfig.MaxAge,
		Compress:   false,
	}

	lumberJackLogger2 := &lumberjack.Logger{
		Filename:   strings.Replace(setting.Conf.LogConfig.Filename, ".log", "_err.log", 1),
		MaxSize:    setting.Conf.LogConfig.MaxSize,
		MaxBackups: setting.Conf.LogConfig.MaxBackups,
		MaxAge:     setting.Conf.LogConfig.MaxAge,
		Compress:   false,
	}
	// 3、设置loglevel
	level, _ := zapcore.ParseLevel(setting.Conf.LogConfig.Level) // 从配置文件中读取

	// 创建zapcore
	core1 := zapcore.NewCore(enconder, zapcore.AddSync(lumberJackLogger1), level)
	core2 := zapcore.NewCore(enconder, zapcore.AddSync(lumberJackLogger2), zapcore.ErrorLevel) // 将error级别的log单独放在一个文件
	core := zapcore.NewTee(core1, core2)
	// 创建logger
	logger := zap.New(core)

	// 替换zap全局的logger
	zap.ReplaceGlobals(logger)
	zap.L().Info(" logger init success")
	return

}

3、数据库初始化

Dao/mysql.go

package dao

// 将之前数据库连接代码写进去
func Init() error {
	return nil
}

4、路由初始化

router/router.go

package router

import (
	"gin_zap/middleware"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

func Init() *gin.Engine {
	r := gin.New()
	r.Use(middleware.GinLogger(zap.L()), middleware.GinRecovery(zap.L(), true))
	r.GET("/littleboy", func(c *gin.Context) {
		zap.L().Info("返回一条日志")
	})

	return r

}

5、路由启动

r.Run()

6、main函数启动

package main

import (
	"fmt"
	"gin_zap/dao"
	"gin_zap/logger"
	"gin_zap/router"
	"gin_zap/setting"
	"os"

	"go.uber.org/zap"
)

func main() {

	// 1、加载配置
	if len(os.Args) < 2 {
		panic("执行时必须指定参数")
	}
	err := setting.Init(os.Args[1])
	if err != nil {
		panic(err)
	}
	fmt.Println(setting.Conf.Name)

	// 2、 加载日志模块
	err = logger.Init()
	if err != nil {
		panic(err)
	}

	// 3、数据库初始化

	err = dao.Init()
	if err != nil {
		zap.L().Error("mysql connect error")
	}

	// 4、路由初始化
	r := router.Init()
	// 5、程序启动
	r.Run()
}

代码层级结构 CLD分层

36-搭建通用web开发脚手架_第2张图片

你可能感兴趣的:(Golang,golang,运维开发,后端)