首页 > 其他分享 >go-商品服务-web

go-商品服务-web

时间:2022-11-15 18:58:45浏览次数:40  
标签:web goods 服务 string err int32 go

一.项目初始化

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())
	}

}

  

 

标签:web,goods,服务,string,err,int32,go
From: https://www.cnblogs.com/wlike/p/16893500.html

相关文章

  • 成为 Go 高手的 8 个 GitHub 开源项目
    成为Go高手的8个GitHub开源项目polarisxu 2022-11-1518:12 发表于北京大家好,我是polarisxu。想成为Go高手吗?那推荐看看这些开源项目。Go从2009年开始......
  • IDT系列:(二)中断处理过程,使用bochs调试IDT中的中断服务程序
    参考:https://blog.csdn.net/liujiayu2/article/details/73947357一、中断处理的过程根据Intel64andIA-32ArchitecturesSoftwareDeveloper’sManual的介绍,在中断......
  • Nginx配置之实现多台服务器负载均衡
    原文http://www.1000zx.cn/it/13524.htmlNginx负载均衡服务器:IP:192.168.0.4(Nginx-Server)Web服务器列表:Web1:192.168.0.5(Nginx-Node1/Nginx-Web1)Web2:192.168.0.7(Ngi......
  • OpenSergo 流量路由:从场景到标准化的探索
    作者:十眠流量路由,顾名思义就是将具有某些属性特征的流量,路由到指定的目标。流量路由是流量治理中重要的一环,多个路由如同流水线一样,形成一条路由链,从所有的地址表中筛选出......
  • 阿里云服务器上SpringBoot单体项目的部署
    1、注意阿里云需要安全组端口设置,不然无法访问。不仅linux虚拟机里需要开放指定端口,阿里云ecs安全组也需要添加开放对应的端口;2、linux虚拟机中安装docker,参照阿里云服务......
  • CentOS服务器上普通用户(非root)源码部署禅道
    简介:公司服务器上的docker容器,其中一个容器最小化安装了CentOS,要在这个什么命令都没有的Linux系统上,在指定的路径下,部署禅道(先搭建环境);搭建Apache、PHP、MariaDB,并结合同......
  • 记录一个gorm发生全局查询条件的问题
       正常情况下在使用gorm做修改操作时,会使用omit过滤一些字段,比如上图中修改的时候就不应该修改创建时间和创建人字段的值。关键点在于上图如果omit中没有增加id字......
  • django源码解读 一
    1.搭建django源码测试环境1.安装python环境这里我使用的是3.102.安装django,我安装的是django4.03.创建一个文件夹,将找到django源码放在这个文件夹中,一般是在安......
  • webpack简介及自定义插件
    webpack 是一个用于现代JavaScript应用程序的 静态模块打包工具。当webpack处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependencygraph),然......
  • .NET平台微服务项目汇集
    最近博客园出现了一篇文章《​​微服务时代之2017年五军之战:NetPHP谁先死​​》,掀起了一波撕逼,作者只是从一个使用者的角度来指点江山,这个姿势是不对的。.NETCore就是专门......