go-商品服务-web
一.项目初始化
1.目录结构
C:.
│ config-debug.yaml
│ config-pro.yaml
│ main.go
│
├─api
│ └─goods
│ goods.go
│
├─config
│ config.go
│
├─forms
│ goods.go
│
├─global
│ golbal.go
│
├─initialize
│ config.go
│ logger.go
│ router.go
│ srv_conn.go
│ validator.go
│
├─middlewares
│ admin.go
│ cors.go
│ jwt.go
│
├─models
│ request.go
│
├─proto
│ goods.pb.go
│ goods.proto
│
├─router
│ goods.go
│
├─utils
│ addr.go
│
├─validator
└─zap_test
│ main.go
│
└─zap_file
main.go
2.代码
(1)接口处理及返回代码
goods-web/api/goods/goods.go
package goods
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"mxshop-api/goods-web/global"
"net/http"
"strings"
)
func removeTopStruct(fileds map[string]string) map[string]string {
rsp := map[string]string{}
for field, err := range fileds {
rsp[field[strings.Index(field, ".")+1:]] = err
}
return rsp
}
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 HandleValidatorError(ctx *gin.Context, err error) {
//定义统一返回的报错处理
errs, ok := err.(validator.ValidationErrors)
if !ok {
ctx.JSON(http.StatusOK, gin.H{
"msg": err.Error(),
})
}
ctx.JSON(http.StatusBadRequest, gin.H{
"error": removeTopStruct(errs.Translate(global.Trans)),
})
return
}
func List(ctx *gin.Context) {
ctx.JSON(http.StatusOK, "ww")
}
(2)配置文件
goods-web/config/config.go
package config
type GoodsSrvConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
Name string `mapstructure:"name" json:"name"`
}
type ServerConfig struct {
Name string `mapstructure:"name" json:"name"`
Port int `mapstructure:"port" json:"port"`
UserSrvInfo GoodsSrvConfig `mapstructure:"goods_srv" json:"goods_srv"`
JWTInfo JWTConfig `mapstructure:"jwt" json:"jwt"`
ConsulInfo ConsulConfig `mapstructure:"consul" json:"consul"`
}
type JWTConfig struct {
SigningKey string `mapstructure:"key" json:"key"`
}
type ConsulConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
}
type Nacos struct {
Host string `mapstructure:"host" json:"host"`
Port uint64 `mapstructure:"port" json:"port"`
User string `mapstructure:"user" json:"user"`
Password string `mapstructure:"password" json:"password"`
NameSpace string `mapstructure:"namespace" json:"namespace"`
DataId string `mapstructure:"dataid" json:"dataid"`
Group string `mapstructure:"group" json:"group"`
}
(3)全局变量
goods-web/global/golbal.go
package global
import (
ut "github.com/go-playground/universal-translator"
"mxshop-api/goods-web/config"
"mxshop-api/goods-web/proto"
)
var (
Trans ut.Translator
ServerConfig *config.ServerConfig = &config.ServerConfig{}
GoodsSrvClient proto.GoodsClient
NacosConfig *config.Nacos = &config.Nacos{}
)
(3)初始化
配置初始化:goods-web/initialize/config.go
package initialize
import (
"encoding/json"
"fmt"
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant"
"github.com/nacos-group/nacos-sdk-go/vo"
"github.com/spf13/viper"
"go.uber.org/zap"
"mxshop-api/goods-web/global"
)
func GetEnvInfo(env string) bool {
viper.AutomaticEnv()
return viper.GetBool(env)
//刚才设置的环境变量 想要生效 我们必须得重启goland
}
//func InitConfig() {
//读取本地配置文件时候的配置
// fmt.Println(GetEnvInfo("MXSHOP_DEBUG"))
// //配置环境变量
// debug := GetEnvInfo("MXSHOP_DEBUG")
// configFilePrefix := "config"
// configFileName := fmt.Sprintf("goods-web/%s-pro.yaml", configFilePrefix)
// if debug {
// configFileName = fmt.Sprintf("goods-web/%s-debug.yaml", configFilePrefix)
// }
//
// v := viper.New()
// //文件的路径如何设置
// v.SetConfigFile(configFileName)
// if err := v.ReadInConfig(); err != nil {
// panic(err)
// }
// if err := v.Unmarshal(global.ServerConfig); err != nil {
// panic(err)
// }
// zap.S().Infof("配置文件:&v", configFileName)
//
// zap.S().Infof("配置信息:&v", global.ServerConfig)
//
// //viper的功能 - 动态监控变化
// v.WatchConfig()
// v.OnConfigChange(func(e fsnotify.Event) {
// zap.S().Infof("配置产生变化:&v", e.Name)
//
// fmt.Println("config file channed: ", e.Name)
// _ = v.ReadInConfig()
// _ = v.Unmarshal(&global.ServerConfig)
// zap.S().Infof("配置信息:&v", global.ServerConfig)
// })
//}
func InitConfig() {
//读取nacos的配置
fmt.Println(GetEnvInfo("MXSHOP_DEBUG"))
//配置环境变量
debug := GetEnvInfo("MXSHOP_DEBUG")
configFilePrefix := "config"
configFileName := fmt.Sprintf("goods-web/%s-pro.yaml", configFilePrefix)
if debug {
configFileName = fmt.Sprintf("goods-web/%s-debug.yaml", configFilePrefix)
}
v := viper.New()
//文件的路径如何设置
v.SetConfigFile(configFileName)
if err := v.ReadInConfig(); err != nil {
panic(err)
}
if err := v.Unmarshal(global.NacosConfig); err != nil {
panic(err)
}
zap.S().Infof("配置信息:&v", global.NacosConfig)
// 从nacos中读取配置信息
sc := []constant.ServerConfig{
{
IpAddr: global.NacosConfig.Host,
Port: global.NacosConfig.Port,
},
}
cc := constant.ClientConfig{
NamespaceId: global.NacosConfig.NameSpace, // 如果需要支持多namespace,我们可以场景多个client,它们有不同的NamespaceId
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "tmp/nacos/log",
CacheDir: "tmp/nacos/cache",
LogLevel: "debug",
}
configClient, err := clients.CreateConfigClient(map[string]interface{}{
"serverConfigs": sc,
"clientConfig": cc,
})
if err != nil {
panic(err)
}
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: global.NacosConfig.DataId,
Group: global.NacosConfig.Group})
if err != nil {
panic(err)
}
//读取配置
//fmt.Println(content)
//fmt.Println(content) //字符串 - yaml
//想要将一个json字符串转换成struct,需要去设置这个struct的tag
err = json.Unmarshal([]byte(content), &global.ServerConfig)
if err != nil {
zap.S().Fatalf("服务nacos配置失败:%s", err.Error())
}
fmt.Println(&global.ServerConfig)
}
日志初始化:goods-web/initialize/logger.go
package initialize
import "go.uber.org/zap"
func InitLogger() {
logger, _ := zap.NewProduction()
zap.ReplaceGlobals(logger)
}
路由初始化:goods-web/initialize/router.go
package initialize
import (
"github.com/gin-gonic/gin"
"mxshop-api/goods-web/middlewares"
"mxshop-api/goods-web/router"
"net/http"
)
func Routers() *gin.Engine {
Router := gin.Default()
Router.GET("health", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{
"code": http.StatusOK,
"success": true,
})
})
//配置跨域
Router.Use(middlewares.Cors())
ApiGroup := Router.Group("/g/v1")
router.InitGoodsRoute(ApiGroup)
return Router
}
连接grpc初始化:goods-web/initialize/srv_conn.go
package initialize
import (
"fmt"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"mxshop-api/goods-web/global"
"mxshop-api/goods-web/proto"
_ "github.com/mbobakov/grpc-consul-resolver" // It's important
)
func InitSrvConn() {
userConn, err := grpc.Dial(
fmt.Sprintf("consul://%s:%d/%s?wait=14s", global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port, global.ServerConfig.UserSrvInfo.Name),
//grpc.WithInsecure(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
)
if err != nil {
zap.S().Fatal("【InitSrvConn】链接【用户失败】")
}
global.GoodsSrvClient = proto.NewGoodsClient(userConn)
}
翻译初始化goods-web/initialize/validator.go
package initialize
import (
"fmt"
"mxshop-api/goods-web/global"
"reflect"
"strings"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "github.com/go-playground/validator/v10/translations/en"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
)
func InitTrans(locale string) (err error) {
//修改gin框架中的validator引擎属性, 实现定制
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
//注册一个获取json的tag的自定义方法
v.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
zhT := zh.New() //中文翻译器
enT := en.New() //英文翻译器
//第一个参数是备用的语言环境,后面的参数是应该支持的语言环境
uni := ut.New(enT, zhT, enT)
global.Trans, ok = uni.GetTranslator(locale)
if !ok {
return fmt.Errorf("uni.GetTranslator(%s)", locale)
}
switch locale {
case "en":
en_translations.RegisterDefaultTranslations(v, global.Trans)
case "zh":
zh_translations.RegisterDefaultTranslations(v, global.Trans)
default:
en_translations.RegisterDefaultTranslations(v, global.Trans)
}
return
}
return
}
(3)认证相关代码
权限:goods-web/middlewares/admin.go
package middlewares
import (
"github.com/gin-gonic/gin"
"mxshop-api/goods-web/models"
"net/http"
)
func IsAdminAuth() gin.HandlerFunc {
return func(ctx *gin.Context) {
claims, _ := ctx.Get("claims")
currentUser := claims.(*models.CustomClaims)
if currentUser.AuthorityId != 2 {
// 管理员
ctx.JSON(http.StatusForbidden, gin.H{
"msg": "无权限",
})
ctx.Abort()
return
}
ctx.Next()
}
}
跨域:goods-web/middlewares/cors.go
package middlewares
import (
"github.com/gin-gonic/gin"
"net/http"
)
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
}
}
认证:goods-web/middlewares/jwt.go
package middlewares
import (
"errors"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"mxshop-api/goods-web/global"
"mxshop-api/goods-web/models"
"net/http"
"time"
)
func JWTAuth() gin.HandlerFunc {
return func(c *gin.Context) {
// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localSstorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
token := c.Request.Header.Get("x-token")
if token == "" {
c.JSON(http.StatusUnauthorized, map[string]string{
"msg": "请登录",
})
c.Abort()
return
}
j := NewJWT()
// parseToken 解析token包含的信息
claims, err := j.ParseToken(token)
if err != nil {
if err == TokenExpired {
if err == TokenExpired {
c.JSON(http.StatusUnauthorized, map[string]string{
"msg": "授权已过期",
})
c.Abort()
return
}
}
c.JSON(http.StatusUnauthorized, "未登陆")
c.Abort()
return
}
c.Set("claims", claims)
c.Set("userId", claims.ID)
c.Next()
}
}
type JWT struct {
SigningKey []byte
}
var (
TokenExpired = errors.New("Token is expired")
TokenNotValidYet = errors.New("Token not active yet")
TokenMalformed = errors.New("That's not even a token")
TokenInvalid = errors.New("Couldn't handle this token:")
)
func NewJWT() *JWT {
return &JWT{
[]byte(global.ServerConfig.JWTInfo.SigningKey), //可以设置过期时间
}
}
// 创建一个token
func (j *JWT) CreateToken(claims models.CustomClaims) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(j.SigningKey)
}
// 解析 token
func (j *JWT) ParseToken(tokenString string) (*models.CustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &models.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
return j.SigningKey, nil
})
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
return nil, TokenMalformed
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
// Token is expired
return nil, TokenExpired
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
return nil, TokenNotValidYet
} else {
return nil, TokenInvalid
}
}
}
if token != nil {
if claims, ok := token.Claims.(*models.CustomClaims); ok && token.Valid {
return claims, nil
}
return nil, TokenInvalid
} else {
return nil, TokenInvalid
}
}
// 更新token
func (j *JWT) RefreshToken(tokenString string) (string, error) {
jwt.TimeFunc = func() time.Time {
return time.Unix(0, 0)
}
token, err := jwt.ParseWithClaims(tokenString, &models.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
return j.SigningKey, nil
})
if err != nil {
return "", err
}
if claims, ok := token.Claims.(*models.CustomClaims); ok && token.Valid {
jwt.TimeFunc = time.Now
claims.StandardClaims.ExpiresAt = time.Now().Add(1 * time.Hour).Unix()
return j.CreateToken(*claims)
}
return "", TokenInvalid
}
(3)model
goods-web/models/request.go
package models
import (
"github.com/dgrijalva/jwt-go"
)
type CustomClaims struct {
ID uint
NickName string
AuthorityId uint
jwt.StandardClaims
}
(3)proto文件
goods-web/proto/goods.proto
syntax = "proto3";
import "google/protobuf/empty.proto";
option go_package = ".;proto";
service Goods{
//商品接口
rpc GoodsList(GoodsFilterRequest) returns(GoodsListResponse);
//现在用户提交订单有多个商品GoodsListResponse,你得批量查询商品的信息吧
rpc BatchGetGoods(BatchGoodsIdInfo) returns(GoodsListResponse); //批量获取商品信息
rpc CreateGoods(CreateGoodsInfo) returns (GoodsInfoResponse);
rpc DeleteGoods(DeleteGoodsInfo) returns (google.protobuf.Empty);
rpc UpdateGoods(CreateGoodsInfo) returns (google.protobuf.Empty);
rpc GetGoodsDetail(GoodInfoRequest) returns(GoodsInfoResponse);
//商品分类
rpc GetAllCategorysList(google.protobuf.Empty) returns(CategoryListResponse); //获取所有的分类
//获取子分类
rpc GetSubCategory(CategoryListRequest) returns(SubCategoryListResponse);
rpc CreateCategory(CategoryInfoRequest) returns(CategoryInfoResponse); //新建分类信息
rpc DeleteCategory(DeleteCategoryRequest) returns(google.protobuf.Empty); //删除分类
rpc UpdateCategory(CategoryInfoRequest) returns(google.protobuf.Empty); //修改分类信息
//品牌和轮播图
rpc BrandList(BrandFilterRequest) returns(BrandListResponse); //批量获取品牌信息
rpc CreateBrand(BrandRequest) returns(BrandInfoResponse); //新建品牌信息
rpc DeleteBrand(BrandRequest) returns(google.protobuf.Empty); //删除品牌
rpc UpdateBrand(BrandRequest) returns(google.protobuf.Empty); //修改品牌信息
//轮播图
rpc BannerList(google.protobuf.Empty) returns(BannerListResponse); //获取轮播列表信息
rpc CreateBanner(BannerRequest) returns(BannerResponse); //添加banner图
rpc DeleteBanner(BannerRequest) returns(google.protobuf.Empty); //删除轮播图
rpc UpdateBanner(BannerRequest) returns(google.protobuf.Empty); //修改轮播图
//品牌分类
rpc CategoryBrandList(CategoryBrandFilterRequest) returns(CategoryBrandListResponse); //获取轮播列表信息
//通过category获取brands
rpc GetCategoryBrandList(CategoryInfoRequest) returns(BrandListResponse);
rpc CreateCategoryBrand(CategoryBrandRequest) returns(CategoryBrandResponse); //添加banner图
rpc DeleteCategoryBrand(CategoryBrandRequest) returns(google.protobuf.Empty); //删除轮播图
rpc UpdateCategoryBrand(CategoryBrandRequest) returns(google.protobuf.Empty); //修改轮播图
}
message CategoryListRequest {
int32 id = 1;
int32 level = 2;
}
message CategoryInfoRequest {
int32 id = 1;
string name = 2;
int32 parentCategory = 3;
int32 level = 4;
bool isTab = 5;
}
message DeleteCategoryRequest {
int32 id = 1;
}
message QueryCategoryRequest {
int32 id = 1;
string name = 2;
}
message CategoryInfoResponse {
int32 id = 1;
string name = 2;
int32 parentCategory = 3;
int32 level = 4;
bool isTab = 5;
}
message CategoryListResponse {
int32 total = 1;
repeated CategoryInfoResponse data = 2;
string jsonData = 3;
}
message SubCategoryListResponse {
int32 total = 1;
CategoryInfoResponse info = 2;
repeated CategoryInfoResponse subCategorys = 3;
}
message CategoryBrandFilterRequest {
int32 pages = 1;
int32 pagePerNums = 2;
}
message FilterRequest {
int32 pages = 1;
int32 pagePerNums = 2;
}
message CategoryBrandRequest{
int32 id = 1;
int32 categoryId = 2;
int32 brandId = 3;
}
message CategoryBrandResponse{
int32 id = 1;
BrandInfoResponse brand = 2;
CategoryInfoResponse category = 3;
}
message BannerRequest {
int32 id = 1;
int32 index = 2;
string image = 3;
string url = 4;
}
message BannerResponse {
int32 id = 1;
int32 index = 2;
string image = 3;
string url = 4;
}
message BrandFilterRequest {
int32 pages = 1;
int32 pagePerNums = 2;
}
message BrandRequest {
int32 id = 1;
string name = 2;
string logo = 3;
}
message BrandInfoResponse {
int32 id = 1;
string name = 2;
string logo = 3;
}
message BrandListResponse {
int32 total = 1;
repeated BrandInfoResponse data = 2;
}
message BannerListResponse {
int32 total = 1;
repeated BannerResponse data = 2;
}
message CategoryBrandListResponse {
int32 total = 1;
repeated CategoryBrandResponse data = 2;
}
message BatchGoodsIdInfo {
repeated int32 id = 1;
}
message DeleteGoodsInfo {
int32 id = 1;
}
message CategoryBriefInfoResponse {
int32 id = 1;
string name = 2;
}
message CategoryFilterRequest {
int32 id = 1;
bool isTab = 2;
}
message GoodInfoRequest {
int32 id = 1;
}
message CreateGoodsInfo {
int32 id = 1;
string name = 2;
string goodsSn = 3;
int32 stocks = 7; //库存,
float marketPrice = 8;
float shopPrice = 9;
string goodsBrief = 10;
string goodsDesc = 11;
bool shipFree = 12;
repeated string images = 13;
repeated string descImages = 14;
string goodsFrontImage = 15;
bool isNew = 16;
bool isHot = 17;
bool onSale = 18;
int32 categoryId = 19;
int32 brandId = 20;
}
message GoodsReduceRequest {
int32 GoodsId = 1;
int32 nums = 2;
}
message BatchCategoryInfoRequest {
repeated int32 id = 1;
int32 goodsNums = 2;
int32 brandNums = 3;
}
message GoodsFilterRequest {
int32 priceMin = 1;
int32 priceMax = 2;
bool isHot = 3;
bool isNew = 4;
bool isTab = 5;
int32 topCategory = 6;
int32 pages = 7;
int32 pagePerNums = 8;
string keyWords = 9;
int32 brand = 10;
}
message GoodsInfoResponse {
int32 id = 1;
int32 categoryId = 2;
string name = 3;
string goodsSn = 4;
int32 clickNum = 5;
int32 soldNum = 6;
int32 favNum = 7;
float marketPrice = 9;
float shopPrice = 10;
string goodsBrief = 11;
string goodsDesc = 12;
bool shipFree = 13;
repeated string images = 14;
repeated string descImages = 15;
string goodsFrontImage = 16;
bool isNew = 17;
bool isHot = 18;
bool onSale = 19;
int64 addTime = 20;
CategoryBriefInfoResponse category = 21;
BrandInfoResponse brand = 22;
}
message GoodsListResponse {
int32 total = 1;
repeated GoodsInfoResponse data = 2;
}
//安装pip install grpcio -i https://pypi.douban.com/simple
//pip install grpcio-tools -i https://pypi.douban.com/simple
//生成proto: python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I . user.proto
// // go: protoc -I . goods.proto --go_out=plugins=grpc:.
(3)路由配置
goods-web/router/goods.go
package router
import (
"github.com/gin-gonic/gin"
"mxshop-api/goods-web/api/goods"
"mxshop-api/goods-web/middlewares"
)
func InitGoodsRoute(Router *gin.RouterGroup) {
GoodsRouter := Router.Group("goods")
{
GoodsRouter.GET("list", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.List)
}
}
(3)获取地址
goods-web/utils/addr.go
package utils
import "net"
func GetFreePort() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if addr != nil {
return 0, nil
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return 0, nil
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}
(3)配置文件
goods-web/config-debug.yaml
#nacos:
host: '
port: 80
namespace: '3aaf14b9-6c20-4dab-89df-a15082ba6301'
user: 'nacos'
password: ''
dataid: 'goods-web.json'
group: 'dev'
(3)主入口
goods-web/main.go
package main
import (
"fmt"
"github.com/spf13/viper"
"go.uber.org/zap"
"mxshop-api/goods-web/global"
"mxshop-api/goods-web/utils"
"mxshop-api/goods-web/initialize"
)
func main() {
//初始化logger
initialize.InitLogger()
//初始化配置文件
initialize.InitConfig()
//初始化routes
Router := initialize.Routers()
//初始化翻译
if err := initialize.InitTrans("zh"); err != nil {
panic(err)
}
//初始化srv的链接
initialize.InitSrvConn()
//如果是本地开发环境,端口固定
viper.AutomaticEnv()
debug := viper.GetBool("MXSHOP_DEBUG")
fmt.Println(debug)
if !debug {
port, err := utils.GetFreePort()
if err == nil {
global.ServerConfig.Port = port
}
}
/*
1. S()可以获取一个全局的sugar,可以让我们自己设置一个全局的logger
2. 日志是分级别的,debug, info , warn, error, fetal
3. S函数和L函数很有用, 提供了一个全局的安全访问logger的途径
*/
zap.S().Infof("启动服务")
//port := 8881
if err := Router.Run(fmt.Sprintf(":%d", global.ServerConfig.Port)); err != nil {
zap.S().Panic("启动失败:", err.Error())
}
}