项目 web 阶段开发

初始化新项目

mkdir mxshop-web
cd mxshop-web
PS D:\golang\goproject\src\mxshop-web>  go mod init mxshop-web
go: creating new go.mod: module mxshop-web
go: to add module requirements and sums:
        go mod tidy
PS D:\golang\goproject\src\mxshop-web> go mod tidy  

  go 语言的日志库zap

 下载库

PS D:\golang\goproject\src\mxshop-web> go get -u go.uber.org/zap
go: added go.uber.org/multierr v1.11.0
go: added go.uber.org/zap v1.28.0

  

Zap提供了两种类型的日志记录器—Sugared LoggerLogger

sugared 使用方式

package main

import (
	"time"

	"go.uber.org/zap"
)

func main() {
	logger, _ := zap.NewProduction()//生产环境用法
	defer logger.Sync() // flushes buffer, if any;把内存数据同步硬盘
	sugar := logger.Sugar()
	url := "https://imooc.com"
	sugar.Infow("failed to fetch URL",
		// Structured context as loosely typed key-value pairs.
		"url", url,
		"attempt", 3,
		"backoff", time.Second,
	)
	sugar.Infof("Failed to fetch URL: %s", url)
}
启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\zap_test\main.go
{"level":"info","ts":1788846250.2682798,"caller":"zap_test/main.go:14","msg":"failed to fetch URL","url":"https://imooc.com","attempt":3,"backoff":1}
{"level":"info","ts":1788846250.2688963,"caller":"zap_test/main.go:20","msg":"Failed to fetch URL: https://imooc.com"}

  

在性能很好但不是很关键的上下文中,使用SugaredLogger。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。

在每一微秒和每一次内存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,内存分配次数也更少,但它只支持强类型的结构化日志记录

Logger 格式

package main

import (
	"go.uber.org/zap"
)

func main() {
	logger,_:=zap.NewDevelopment()
	defer logger.Sync() // flushes buffer, if any;把内存数据同步硬盘
	url := "https://imooc.com"
	logger.Info("failed to fetch URL",
		zap.String("url",url),
		zap.Int("nums",3),
	)
}
启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\zap_test\main.go
2026-09-08T13:59:07.009+0800    INFO    zap_test/main.go:17     failed to fetch URL     {"url": "https://imooc.com", "nums": 3}

  日志写入文件

package main

import (
	"go.uber.org/zap"
	"time"
)


func NewLogger() (*zap.Logger, error) {
	cfg := zap.NewProductionConfig()
	cfg.OutputPaths = []string{
		"./myproject.log",//输出到文件
		"stderr",//错误流
		"stdout",//输出流

	}
	return cfg.Build()
}

func main()  {
	//logger, _ := zap.NewProduction()
	logger, err := NewLogger()//调用
	if err != nil {
		panic(err)
		//panic("初始化logger失败")
	}
	su := logger.Sugar()
	defer su.Sync()
	url := "https://imooc.com"
	su.Info("failed to fetch URL",
		// Structured context as strongly typed Field values.
		zap.String("url", url),
		zap.Int("attempt", 3),
		zap.Duration("backoff", time.Second),
	)
}
  启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\zap_test\zap_log_file\main.go
{"level":"info","ts":1788848313.0249052,"caller":"zap_log_file/main.go:30","msg":"failed to fetch URL{url 15 0 https://imooc.com <nil>} {attempt 11 3  <nil>} {backoff 8 1000000000  <nil>}"}
{"level":"info","ts":1788848313.0249052,"caller":"zap_log_file/main.go:30","msg":"failed to fetch URL{url 15 0 https://imooc.com <nil>} {attempt 11 3  <nil>} {backoff 8 1000000000  <nil>}"}

  initialize 初始化包里定义

package initialize

import (
	"github.com/gin-gonic/gin"
	router2 "mxshop-web/user-web/router"
)

func Routers() *gin.Engine{
	Router := gin.Default()
	ApiGroup := Router.Group("/v1")
	router2.InitUserRouter(ApiGroup)
	return  Router
}

  router 包定义

package router

import (
	"mxshop-web/user-web/api"

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

func InitUserRouter(Router *gin.RouterGroup) {
	UserRouter:=Router.Group("/user")
	zap.S().Info("配置用户相关url")
	{
	UserRouter.GET("list",api.GetUserList)
	}
}

  主函数调用

package main

import (
	"fmt"
	"mxshop-web/user-web/initialize"

	"go.uber.org/zap"
	//"google.golang.org/protobuf/proto"
)

func main() {
	pro := 8021
	logger,_ := zap.NewProduction()
	zap.ReplaceGlobals(logger)//全局
	//初始化
	Router :=initialize.Routers()

	// logger,_:=zap.NewDevelopment()
	// defer logger.Sync()
	// suger := logger.Sugar()
	/*
	1.S()可以获取一个全局的Sugar,可以设置一个全局的loggar
	*/
	zap.S().Infof("启动,端口:%d",8021)//打印日志信息
	if err :=Router.Run(fmt.Sprintf(":%d",pro));err!=nil{
		zap.S().Panic("启动失败",err.Error())
		
	}
}
启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

{"level":"info","ts":1788858352.887364,"caller":"router/user.go:12","msg":"配置用户相关url"}
[GIN-debug] GET    /v1/user/list             --> mxshop-web/user-web/api.GetUserList (3 handlers)
{"level":"info","ts":1788858352.8878922,"caller":"user-web/main.go:24","msg":"启动,端口:8021"}
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :8021

  从主函数将日志初始化拆分出来

package initialize

import "go.uber.org/zap"

func InitLogger() {
	logger, _ := zap.NewDevelopment()
	zap.ReplaceGlobals(logger)//全局
}

  主函数

package main

import (
	"fmt"
	"mxshop-web/user-web/initialize"

	"go.uber.org/zap"

)

func main() {
	pro := 8021
	//初始化log
	initialize.InitLogger()
	//初始化路由
	Router :=initialize.Routers()

	/*
	1.S()可以获取一个全局的Sugar,可以设置一个全局的loggar
	2.日志是分级别的debug、info、 warn、 error 、fatal
	3.S函数和L函数很有用;给我们提供一个安全的全局访问路径
	*/
	zap.S().Debugf("启动,端口:%d",8021)//打印日志信息
	if err :=Router.Run(fmt.Sprintf(":%d",pro));err!=nil{
		zap.S().Panic("启动失败",err.Error())
		
	}
}
启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

2026-09-08T17:23:53.118+0800    INFO    router/user.go:12       配置用户相关url
[GIN-debug] GET    /v1/user/list             --> mxshop-web/user-web/api.GetUserList (3 handlers)
2026-09-08T17:23:53.198+0800    DEBUG   user-web/main.go:26     启动,端口:8021
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :8021

 目录结构

image

  gin调用grpc 服务

api/user.go 文件

package api

import (
	"context"
	"fmt"
	"mxshop-web/user-web/global/reponse"
	proto "mxshop-web/user-web/prote"
	"net/http"
	"time"

	//proto "mxshop-web/user-web/proter"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"
)
func HandleGrpcErrorToHttp(err error,c *gin.Context){
	//将grpc 的code转换为http状态码
	if err != nil{
		if e,ok :=status.FromError(err);ok{
			switch e.Code(){
			case codes.NotFound:
				c.JSON(http.StatusNotFound,gin.H{
					"msg":e.Message(),
				})
			case codes.Internal:
				c.JSON(http.StatusInternalServerError,gin.H{
					"msg":"内部错误",
				})
			case codes.InvalidArgument:
				c.JSON(http.StatusBadRequest,gin.H{
					"msg":"参数错误",
				})
			case codes.Unavailable:
				c.JSON(http.StatusInternalServerError,gin.H{
					"msg":"用户服务不可用",
				})
			default:
				c.JSON(http.StatusInternalServerError,gin.H{
					"msg":"其他错误",
				})
			}
			return 
			
		}
	}

}

func GetUserList(cxt *gin.Context){
	ip := "127.0.0.1"
	port:= 50051
	//拨号连接
	userConn,err :=grpc.NewClient(
		fmt.Sprintf("%s:%d",ip,port),
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	)
	if err!=nil{
		zap.S().Errorw("连接用户服务失败","msg",err.Error(),)
	}
	//生成grpc 的client并调用接口
	userSrvClient:=proto.NewUserClient(userConn)
	rsq,err:=userSrvClient.GetUserList(context.Background(),&proto.PageInfo{
		Pn: 0,
		PSize: 0,
	})
	if err != nil{
		zap.S().Errorw("[GetUserList] 查询【用户列表失败】")
		HandleGrpcErrorToHttp(err,cxt)
		return 
	}
	result := make([]interface{},0)
	for _,value := range rsq.Data{
		//data := make(map[string]interface{})
		user := reponse.UserResPonse{
			Id: value.Id,
			NickName: value.NickName,
			BirthDay: reponse.JsonTime(time.Unix(int64(value.BirthDay),0)),
			Gender: value.Gender,
			Mobile: value.Mobile,
		}
		// data["id"]=value.Id
		// data["name"]=value.NickName
		// data["birthday"]=value.BirthDay
		// data["gender"]=value.Gender
		// data["mobile"]=value.Mobile
		result=append(result, user)
	}
	cxt.JSON(http.StatusOK,result)	
}

 global\reponse\user.go 文件

package reponse

import (
	"fmt"
	"time"
)

//import "time"
type JsonTime time.Time
func (j JsonTime)MarshalJSON() ([]byte,error){
	var stmp = fmt.Sprintf("\"%s\"",time.Time(j).Format("2006-01-02"))
	return []byte(stmp),nil
}
 
type UserResPonse struct {
	Id       int32  `json:"id"`
	NickName string `json:"name"`
	//BirthDay string `json:"birthday"`
	//BirthDay time.Time `json:"birthday"`
	BirthDay JsonTime `json:"birthday"`
	Gender   string `json:"gender"`
	Mobile string `json:"mobile"`
	
}

 initialize\router.go 文件

package initialize

import (
	"github.com/gin-gonic/gin"
	router2 "mxshop-web/user-web/router"
)

func Routers() *gin.Engine{
	Router := gin.Default()
	ApiGroup := Router.Group("/u/v1")
	router2.InitUserRouter(ApiGroup)
	return  Router
}

router\user.go 文件

package router

import (
	"mxshop-web/user-web/api"

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

func InitUserRouter(Router *gin.RouterGroup) {
	UserRouter:=Router.Group("/user")
	zap.S().Info("配置用户相关url")
	{
	UserRouter.GET("list",api.GetUserList)
	}
}

prote\user.proto 文件

syntax = "proto3";
import "google/protobuf/empty.proto";
option go_package = ".;proto";
service User {
    rpc GetUserList(PageInfo) returns(UserListResPonse);//用户列表
    rpc GetUserByMobile(MobileRequest) returns(UserInfoResPonse);//通过mobile查询用户
    rpc GetUserByID(IdRequest) returns (UserInfoResPonse);//通过ID查用户
    rpc CreateUser(CreateUserInfo) returns (UserInfoResPonse);//添加用户
    rpc UpdateUser(UpdateUserInfo) returns (google.protobuf.Empty);//更新用户
    rpc CheckPassWord(PasswordCheckInfo) returns (CheckReponse);//检查密码
}
message PasswordCheckInfo {
    string password =1;
    string encryptedPassword=2;
 
}
message CheckReponse {
    bool success=1;
}
message PageInfo {
    uint32 Pn = 1;
    uint32 pSize =2;
}
message  MobileRequest{
    string mobile=1;
}
message IdRequest {
    int32 Id =1;
}
message CreateUserInfo {
    string nickName =1;
    string passWord =2;
    string mobile =3;
}
message UpdateUserInfo {
    int32 id = 1;
    string nickName =2;
    string gender = 3;
    uint64 birthDay =4;
}
message UserInfoResPonse {
    int32 id = 1;
    string password = 2;
    string mobile = 3;
    string nickName =4;
    uint64 birthDay = 5;
    string gender = 6;
    int32 role = 7;
}
message UserListResPonse {
    int32 total=1;
    repeated UserInfoResPonse data=2;
 
}

生成
protoc --go_out=. --go-grpc_out=. user.proto

  main.go

package main

import (
	"fmt"
	"mxshop-web/user-web/initialize"

	"go.uber.org/zap"
	//"google.golang.org/protobuf/proto"
)

func main() {
	pro := 8021
	//初始化log
	initialize.InitLogger()
	//初始化路由
	Router :=initialize.Routers()

	// logger,_:=zap.NewDevelopment()
	// defer logger.Sync()
	// suger := logger.Sugar()
	/*
	1.S()可以获取一个全局的Sugar,可以设置一个全局的loggar
	2.日志是分级别的debug、info、 warn、 error 、fatal
	3.S函数和L函数很有用;给我们提供一个安全的全局访问路径
	*/
	zap.S().Debugf("启动,端口:%d",8021)//打印日志信息
	if err :=Router.Run(fmt.Sprintf(":%d",pro));err!=nil{
		zap.S().Panic("启动失败",err.Error())
		
	}
}

启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

2026-09-09T18:44:22.283+0800    INFO    router/user.go:12       配置用户相关url
[GIN-debug] GET    /u/v1/user/list           --> mxshop-web/user-web/api.GetUserList (3 handlers)
2026-09-09T18:44:22.300+0800    DEBUG   user-web/main.go:26     启动,端口:8021
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :8021
[GIN] 2026/09/09 - 18:44:27 | 200 |   8.59ms |       127.0.0.1 | GET      "/u/v1/user/list"
[GIN] 2026/09/09 - 18:44:29 | 200 |   3.63ms |       127.0.0.1 | GET      "/u/v1/user/list"
[GIN] 2026/09/09 - 18:51:02 | 200 |  13.76ms |       127.0.0.1 | GET      "/u/v1/user/list"

  测试

image

go 的配置文件管理-viper

介绍  

Viper是适用于Go应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。它支持以下特性:

    • 设置默认值
    • JSONTOMLYAMLHCLenvfileJava properties格式的配置文件读取配置信息
    • 实时监控和重新读取配置文件(可选)
    • 从环境变量中读取
    • 从远程配置系统(etcd或Consul)读取并监控配置变化
    • 从命令行参数读取配置
    • 从buffer读取配置
    • 显式配置值

 yaml 教程

示例

下载viper 管理库

go get github.com/spf13/viper

  

配置文件yaml 

image

 

 Viper 管理配置文件

package main

import (
	"fmt"

	"github.com/spf13/viper"
)
type ServerConfig struct{
	ServerName string `mapstructure:"name"`

}

func main() {
	v := viper.New()
	v.SetConfigFile("user-web/viper_test/ch01/config.yaml")//配置相对路径
	if err:= v.ReadInConfig(); err!=nil{
		panic(err)
	}
	server := ServerConfig{}
	if err := v.Unmarshal(&server);err!=nil{
		panic(err)
	}
	fmt.Println(server)

}

启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\viper_test\ch01\main.go
{user-web}

  新增一个字段

image

 main.go

package main

import (
	"fmt"

	"github.com/spf13/viper"
)
type ServerConfig struct{
	ServerName string `mapstructure:"name"`//tag 表示把mapstructure的name对应的值填充到ServerName
	Prot int `mapstructure:"prot"`//

}

func main() {
	v := viper.New()
	v.SetConfigFile("user-web/viper_test/ch01/config.yaml")//配置相对路径
	if err:= v.ReadInConfig(); err!=nil{
		panic(err)
	}
	server := ServerConfig{}
	if err := v.Unmarshal(&server);err!=nil{
		panic(err)
	}
	fmt.Println(server)

}
启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\viper_test\ch01\main.go
{user-web 8021}

  yaml 嵌套配置

yaml配置

name: 'user-web'
prot: 8021
mysql:
  host: '127.0.0.1'
  prot: 3306

main.go 读取

package main
import (
	"fmt"

	"github.com/spf13/viper"
)
type MysqlConfig struct{
	Host string `mapstructure:"host"`
	Prot  int `mapstructure:"prot"`
}
type ServerConfig struct{
	ServerName string `mapstructure:"name"`//tag 表示把mapstructure的name对应的值填充到ServerName
	Prot int `mapstructure:"prot"`//
	MysqlInfo MysqlConfig `mapstructure:"mysql"`

}

func main() {
	v := viper.New()
	v.SetConfigFile("user-web/viper_test/ch02/config.yaml")//配置相对路径
	if err:= v.ReadInConfig(); err!=nil{
		panic(err)
	}
	server := ServerConfig{}
	if err := v.Unmarshal(&server);err!=nil{
		panic(err)
	}
	fmt.Println(server)

}
执行
PS D:\golang\goproject\src\mxshop-web> go run user-web\viper_test\ch02\main.go
{user-web 8021 {127.0.0.1 3306}}

  环境配置文件隔离

设置系统环境变量

image

 读取环境变量

package main
import (
	"fmt"

	"github.com/spf13/viper"
)
type MysqlConfig struct{
	Host string `mapstructure:"host"`
	Prot  int `mapstructure:"prot"`
}
type ServerConfig struct{
	ServerName string `mapstructure:"name"`//tag 表示把mapstructure的name对应的值填充到ServerName
	Prot int `mapstructure:"prot"`//
	MysqlInfo MysqlConfig `mapstructure:"mysql"`

}
func GetEnvInfo(env string) bool{
	viper.AutomaticEnv()
	return viper.GetBool(env)
}

func main() {
	fmt.Println(GetEnvInfo("MXSHOP_DEBUG"))//如果是刚设置的环境变量要重启开发工具像vscode、goland 等才会生效,因为启动的时候才会读环境变量,而你启动后设置的环境变量需要重启更新环境变量
	
}
执行
PS D:\golang\goproject\src\mxshop-web> go run user-web\viper_test\ch02\main.go
true

  config-debug.yaml

environment: debug
ame: 'user-web'
prot: 8021
mysql:
  host: '127.0.0.1'
  prot: 3306

  config-pro.yaml

environment: pro
name: 'user-web'
prot: 8021
mysql:
  host: '127.0.0.1'
  prot: 3306

  main.go

package main
import (
	"fmt"

	"github.com/spf13/viper"
)
type MysqlConfig struct{
	Host string `mapstructure:"host"`
	Prot  int `mapstructure:"prot"`
}
type ServerConfig struct{
	Environment string `mapstructure:"environment"`
	ServerName string `mapstructure:"name"`//tag 表示把mapstructure的name对应的值填充到ServerName
	Prot int `mapstructure:"prot"`//
	MysqlInfo MysqlConfig `mapstructure:"mysql"`

}
func GetEnvInfo(env string) bool{
	viper.AutomaticEnv()
	return viper.GetBool(env)
}

func main() {
	debug:=GetEnvInfo("MXSHOP_DEBUG")//如果是刚设置的环境变量要重启开发工具像vscode、goland 等才会生效,因为启动的时候才会读环境变量,而你启动后设置的环境变量需要重启更新环境变量
	configFilePrefix:="config"
	cofigFileName:=fmt.Sprintf("user-web/viper_test/ch02/%s-pro.yaml",configFilePrefix)
	if debug{
		cofigFileName = fmt.Sprintf("user-web/viper_test/ch02/%s-debug.yaml",configFilePrefix)
	}
	v := viper.New()
	v.SetConfigFile(cofigFileName)//配置相对路径
	if err:= v.ReadInConfig(); err!=nil{
		panic(err)
	}
	server := ServerConfig{}
	if err := v.Unmarshal(&server);err!=nil{
		panic(err)
	}
	fmt.Println(server)
	fmt.Printf("%v",v.Get("environment"))
}

启动
PS D:\golang\goproject\src\mxshop-web> go run user-web\viper_test\ch02\main.go
{debug  8021 {127.0.0.1 3306}}
debug

  //viper 动态监控变化的功能

package main

import (
	"fmt"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)
type MysqlConfig struct{
	Host string `mapstructure:"host"`
	Prot  int `mapstructure:"prot"`
}
type ServerConfig struct{
	Environment string `mapstructure:"environment"`
	ServerName string `mapstructure:"name"`//tag 表示把mapstructure的name对应的值填充到ServerName
	Prot int `mapstructure:"prot"`//
	MysqlInfo MysqlConfig `mapstructure:"mysql"`

}
func GetEnvInfo(env string) bool{
	viper.AutomaticEnv()
	return viper.GetBool(env)
}

func main() {
	debug:=GetEnvInfo("MXSHOP_DEBUG")//如果是刚设置的环境变量要重启开发工具像vscode、goland 等才会生效,因为启动的时候才会读环境变量,而你启动后设置的环境变量需要重启更新环境变量
	configFilePrefix:="config"
	cofigFileName:=fmt.Sprintf("user-web/viper_test/ch02/%s-pro.yaml",configFilePrefix)
	if debug{
		cofigFileName = fmt.Sprintf("user-web/viper_test/ch02/%s-debug.yaml",configFilePrefix)
	}
	v := viper.New()
	v.SetConfigFile(cofigFileName)//配置相对路径
	if err:= v.ReadInConfig(); err!=nil{
		panic(err)
	}
	server := ServerConfig{}
	if err := v.Unmarshal(&server);err!=nil{
		panic(err)
	}
	fmt.Println(server)
	fmt.Printf("%v",v.Get("environment"))
	v.WatchConfig()
	v.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("config file channed :",e.Name)
		_=v.ReadInConfig()
		_=v.Unmarshal(&server)
		fmt.Println(server)
	})
	time.Sleep(time.Second*300)
}

执行
PS D:\golang\goproject\src\mxshop-web> go run user-web\viper_test\ch02\main.go
{debug  8021 {127.0.0.1 3306}}
debugconfig file channed : user-web\viper_test\ch02\config-debug.yaml
{debug  8021 {127.0.0.1 330}}
config file channed : user-web\viper_test\ch02\config-debug.yaml
{debug  8021 {127.0.0.1 330}}
config file channed : user-web\viper_test\ch02\config-debug.yaml
{debug  8021 {127.0.0.1 3309}}
config file channed : user-web\viper_test\ch02\config-debug.yaml
{debug  8021 {127.0.0.1 3309}}

  viper集成到项目中

目录结构

image

 config-debug.yaml 文件

name: "user-web"
prot : 8021
user-srv: 
  host: '127.0.0.1'
  prot: 50051

 config-pro.yaml  文件

name: "user-web"
prot : 8021
user-srv: 
  host: "127.0.0.1"
  prot: 50051 

  user-web\config\config.go 文件

package config
type UserSrvConfig struct{
	Host string `mapstructure:"host"`
	Prot int `mapstructuer:"prot"`
}
type ServerConfig struct{
	Name string `mapstructure:"name"`
	Prot int `mapstructuer:"prot"`
	UserSrvInfo UserSrvConfig `mapstructure:"user-srv"`

}

  user-web\global\global.go 文件

package global

import "mxshop-web/user-web/config"

var (
	ServerConfig *config.ServerConfig =&config.ServerConfig{}
)

  user-web\initialize\config.go 文件

package initialize

import (
	"fmt"

	//"mxshop-web/user-web/config"
	"mxshop-web/user-web/global"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
	"go.uber.org/zap"
)

func GetEnvInfo(env string) bool {
	viper.AutomaticEnv()
	return viper.GetBool(env)
}

func InitConfig() {
		debug:=GetEnvInfo("MXSHOP_DEBUG")//如果是刚设置的环境变量要重启开发工具像vscode、goland 等才会生效,因为启动的时候才会读环境变量,而你启动后设置的环境变量需要重启更新环境变量
	configFilePrefix:="config"
	cofigFileName:=fmt.Sprintf("user-web/%s-pro.yaml",configFilePrefix)
	if debug{
		cofigFileName = fmt.Sprintf("user-web/%s-debug.yaml",configFilePrefix)
	}
	v := viper.New()
	v.SetConfigFile(cofigFileName)//配置相对路径
	if err:= v.ReadInConfig(); err!=nil{
		panic(err)
	}
	// server := config.ServerConfig{}
	//使用全局变量
	if err := v.Unmarshal(global.ServerConfig);err!=nil{
		panic(err)
	}
	//fmt.Println(global.ServerConfig)
	zap.S().Infof("配置信息:&v",global.ServerConfig)
	fmt.Printf("%v",v.Get("environment"))
	v.WatchConfig()
	v.OnConfigChange(func(e fsnotify.Event) {

		fmt.Println("config file channed :",e.Name)
		zap.S().Infof("配置文件产生变化:%v",e.Name)
		_=v.ReadInConfig()
		_=v.Unmarshal(global.ServerConfig)
		// fmt.Println(global.ServerConfig)
		
		zap.S().Infof("配置信息:&v",global.ServerConfig)
	})
	///time.Sleep(time.Second*300)
}

  man文件

package main

import (
	"fmt"
	"mxshop-web/user-web/global"
	"mxshop-web/user-web/initialize"

	"go.uber.org/zap"
	//"google.golang.org/protobuf/proto"
)

func main() {
	// prot := 8021
	//初始化log
	initialize.InitLogger()
	//初始化配置文件
	initialize.InitConfig()
	//初始化路由
	Router :=initialize.Routers()
	


	// logger,_:=zap.NewDevelopment()
	// defer logger.Sync()
	// suger := logger.Sugar()
	/*
	1.S()可以获取一个全局的Sugar,可以设置一个全局的loggar
	2.日志是分级别的debug、info、 warn、 error 、fatal
	3.S函数和L函数很有用;给我们提供一个安全的全局访问路径
	*/
	zap.S().Debugf("启动,端口:%d",global.ServerConfig.Prot)//打印日志信息
	if err :=Router.Run(fmt.Sprintf(":%d",global.ServerConfig.Prot));err!=nil{
		zap.S().Panic("启动失败",err.Error())
		
	}
}

  

 

 

  

  

 

 

 

  

  

 

  

posted @ 2026-09-11 15:32  烟雨楼台,行云流水  阅读(4)  评论(0)    收藏  举报