继续上次的操作
接下来我们需要在/recipe下面创建一个config文件夹
在config文件创建一个config.go的文件用于映射我们上篇文章中提到的yaml配置文件
定义结构体 package config
//系统配置
type ServerConfig struct {
MysqlConfig MysqlConfig `yaml:"mysql_config"` //mysql配置
WebPort string `yaml:"web_port"` //web服务端口配置
LogDirectory string `yaml:"log_directory"` //日志输出目录配置
}
//mysql配置
type MysqlConfig struct {
User string `yaml:"user"` //账号
Password string `yaml:"password"` //密码
Host string `yaml:"host"` //ip或者域名
Port string `yaml:"port"` //端口
DbName string `yaml:"db_name"` //数据库名
}
然后我们还需要一个全局变量用来存放我们初始化配置文件以后的数据
在/recipe下面 新建一个global文件夹 在global文件夹下面新建一个global.go
package global
import (
"go.uber.org/zap"
"gorm.io/gorm"
"recipe/config"
)
var (
Config *config.ServerConfig
Mysql *gorm.DB
Log *zap.Logger
)
接着我们在/recipe下面创建一个initializes文件夹存放一些初始化方法
初始化一个配置文件:init_config.go
package initializes
import (
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
"recipe/config"
"recipe/global"
)
//初始化配置文件
func InitConfig() {
configs := new(config.ServerConfig)
//读取yaml配置文件
yamlFile, err := ioutil.ReadFile("./config.yaml")
if err != nil {
log.Printf("获取yaml配置文件错误:#%v ", err)
return
}
//yaml配置文件映射到结构体
err = yaml.Unmarshal(yamlFile, configs)
if err != nil {
log.Fatalf("yaml文件解析失败: %v", err)
}
//设置全局变量
global.Config = configs
}
初始化mysql连接:init_myql.go
package initializes
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"recipe/global"
)
func InitMsql() {
//gorm数据库配置
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{},
)
//mysql数据库连接url拼接
mysqlUrl := fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local",
global.Config.MysqlConfig.User,
global.Config.MysqlConfig.Password,
global.Config.MysqlConfig.Host,
global.Config.MysqlConfig.Port,
global.Config.MysqlConfig.DbName,
)
var err error
DB, err := gorm.Open(mysql.Open(mysqlUrl), &gorm.Config{Logger: newLogger})
if err != nil {
fmt.Println("数据库连接失败")
}
//设置连接池
sqlDb, _ := DB.DB()
sqlDb.SetMaxIdleConns(200) //设置最大连接数
sqlDb.SetMaxOpenConns(200) //设置最大的空闲连接数
global.Mysql = DB
}
初始化表结构:init_table.go
package initializes
import (
"recipe/global"
"recipe/models/tables"
)
//初始化数据表
func InitTable() {
db := global.Mysql
db.AutoMigrate(
tables.User{},
tables.AdminUser{},
tables.Collection{},
tables.Column{},
tables.ColumnItem{},
tables.HistoricalRecord{},
tables.Like{},
tables.Popularity{},
tables.Recipe{},
tables.RecipeType{},
tables.Steps{},
tables.Ingredients{},
)
}
除了上面的东西我们还需要初始化一个zap日志 这里使用的方法参考的是golang-vue-admin 已在github上开源 大家可以去看看
在recipe下新建一个croe文件夹继续新建一个zap.go
package core
import (
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
myGlobal "recipe/global"
"time"
)
func Zap() (logger *zap.Logger) {
if ok, _ := utils.PathExists(myGlobal.Config.LogDirectory); !ok { // 判断是否有Director文件夹
fmt.Printf("create %v directory\n", global.GVA_CONFIG.Zap.Director)
_ = os.Mkdir(global.GVA_CONFIG.Zap.Director, os.ModePerm)
}
// 调试级别
debugPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
return lev == zap.DebugLevel
})
// 日志级别
infoPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
return lev == zap.InfoLevel
})
// 警告级别
warnPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
return lev == zap.WarnLevel
})
// 错误级别
errorPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
return lev >= zap.ErrorLevel
})
cores := [...]zapcore.Core{
getEncoderCore(fmt.Sprintf("./%s/server_debug.log", myGlobal.Config.LogDirectory), debugPriority),
getEncoderCore(fmt.Sprintf("./%s/server_info.log", myGlobal.Config.LogDirectory), infoPriority),
getEncoderCore(fmt.Sprintf("./%s/server_warn.log", myGlobal.Config.LogDirectory), warnPriority),
getEncoderCore(fmt.Sprintf("./%s/server_error.log", myGlobal.Config.LogDirectory), errorPriority),
}
logger = zap.New(zapcore.NewTee(cores[:]...), zap.AddCaller())
if global.GVA_CONFIG.Zap.ShowLine {
logger = logger.WithOptions(zap.AddCaller())
}
return logger
}
// getEncoderConfig 获取zapcore.EncoderConfig
func getEncoderConfig() (config zapcore.EncoderConfig) {
config = zapcore.EncoderConfig{
MessageKey: "message",
LevelKey: "level",
TimeKey: "time",
NameKey: "logger",
CallerKey: "caller",
StacktraceKey: global.GVA_CONFIG.Zap.StacktraceKey,
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: CustomTimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.FullCallerEncoder,
}
switch {
case global.GVA_CONFIG.Zap.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
config.EncodeLevel = zapcore.LowercaseLevelEncoder
case global.GVA_CONFIG.Zap.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
config.EncodeLevel = zapcore.LowercaseColorLevelEncoder
case global.GVA_CONFIG.Zap.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
config.EncodeLevel = zapcore.CapitalLevelEncoder
case global.GVA_CONFIG.Zap.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
config.EncodeLevel = zapcore.CapitalColorLevelEncoder
default:
config.EncodeLevel = zapcore.LowercaseLevelEncoder
}
return config
}
// getEncoder 获取zapcore.Encoder
func getEncoder() zapcore.Encoder {
if global.GVA_CONFIG.Zap.Format == "json" {
return zapcore.NewJSONEncoder(getEncoderConfig())
}
return zapcore.NewConsoleEncoder(getEncoderConfig())
}
// getEncoderCore 获取Encoder的zapcore.Core
func getEncoderCore(fileName string, level zapcore.LevelEnabler) (core zapcore.Core) {
writer := utils.GetWriteSyncer(fileName) // 使用file-rotatelogs进行日志分割
return zapcore.NewCore(getEncoder(), writer, level)
}
// 自定义日志输出时间格式
func CustomTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format(global.GVA_CONFIG.Zap.Prefix + "2006/01/02 - 15:04:05.000"))
}
然后我们还要初始化一个路由
在recipe下面新建一个router的文件夹里面继续分两层,分别对应的是我们的后台管理端和微信小程序端
admin为后台管理端的路由
client为小程序的路由
在外层的router.go里面分别调用里面的router
/recipe/router/router.go
package router
import (
"github.com/gin-gonic/gin"
"recipe/router/admin"
"recipe/router/client"
)
//路由设置
func InitRouter(r *gin.Engine) {
r.Static("/resources", "./resources")
adminRouter := r.Group("/admin")
admin.InitRouter(adminRouter)
clientRouter:=r.Group("/client")
client.InitRouter(clientRouter)
//clientRouter:=r.Group("/client")
}
/recipe/router/admin/router.go
package admin
import (
"github.com/gin-gonic/gin"
"recipe/controllers/admin"
"recipe/middleware"
)
//后台管理路由设置
func InitRouter(r *gin.RouterGroup) {
}
/recipe/router/client/router.go
package client
import (
"github.com/gin-gonic/gin"
"recipe/controllers/client"
"recipe/middleware"
)
func InitRouter(r *gin.RouterGroup) {
}
然后我们在回到/recipe/initializes/新建一个init_router.go对我们的路由进行一个初始化
package initializes
import (
"github.com/gin-gonic/gin"
"recipe/global"
"recipe/router"
)
//初始化路由
func InitRouter() {
r := gin.Default()
router.InitRouter(r)
r.Run(global.Config.WebPort)
}
接在在新建一个run_serve.go
package initializes
import (
core "recipe/croe"
"recipe/global"
)
func RunServe() {
InitConfig()
global.Log=core.Zap()
InitMsql()
InitTable()
InitRouter()
}
至此 我们基本初始化工作已经完成
然后我们在顶层新建一个入口mian.go
package main
import "recipe/initializes"
func main() {
//启动服务
initializes.RunServe()
}
我们尝试启动它
在运行之前我们先安装一下用到的第三方库
在控制台执行
go mod tidy
然后运行它
当我们看见Listening and serving HTTP on :8081的字样就证明已经启动成功了