商品微服务(goods_api)API接口服务

五.商品微服务(goods_api)

1.项目初始化
1.1添加配置文件

在goods-web/config-debug.yaml

host: '192.168.0.4'
port: 8848
namespace: 'ba14206d-403f-4377-b7e7-70a3e8fa2bbf'
user: 'nacos'
password: 'nacos'
dataid: 'goods-web.json'
group: 'dev'
1.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 JWTConfig struct {
   SigningKey string `mapstructure:"key" json:"key"`
}

type ConsulConfig struct {
   Host string `mapstructure:"host" json:"host"`
   Port int    `mapstructure:"port" json:"port"`
}

type RedisConfig struct {
   Host   string `mapstructure:"host" json:"host"`
   Port   int    `mapstructure:"port" json:"port"`
   Expire int    `mapstructure:"expire" json:"expire"`
}

type ServerConfig struct {
   Name        string         `mapstructure:"name" json:"name"`
   Host        string         `mapstructure:"host" json:"host"`
   Tags        []string       `mapstructure:"tags" json:"tags"`
   Port        int            `mapstructure:"port" json:"port"`
   UserSrvInfo GoodsSrvConfig `mapstructure:"goods_srv" json:"goods_srv"`
   JWTInfo     JWTConfig      `mapstructure:"jwt" json:"jwt"`
   RedisInfo   RedisConfig    `mapstructure:"redis" json:"redis"`
   ConsulInfo  ConsulConfig   `mapstructure:"consul" json:"consul"`
}

type NacosConfig struct {
   Host      string `mapstructure:"host"`
   Port      uint64 `mapstructure:"port"`
   Namespace string `mapstructure:"namespace"`
   User      string `mapstructure:"user"`
   Password  string `mapstructure:"password"`
   DataId    string `mapstructure:"dataid"`
   Group     string `mapstructure:"group"`
}
1.3建立全局变量

在goods-web/global/global.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.NacosConfig = &config.NacosConfig{}
)
1.4配置日志初始化

在goods-web/initalize目录下添加logger.go

package initalize

import "go.uber.org/zap"

func InitLogger() {
   logger, _ := zap.NewDevelopment()
   zap.ReplaceGlobals(logger)
}
1.5路由初始化
package initalize

import (
   "github.com/gin-gonic/gin"
   "mxshop_api/goods-web/middlewares"
   "mxshop_api/goods-web/router"
)

func Routers() *gin.Engine {
   Router := gin.Default()
   //配置跨域
   Router.Use(middlewares.Cors())
   ApiGroup := Router.Group("/g/v1")
   router.InitGoodsRouter(ApiGroup)

   return Router
}
1.6服务注册初始化
package initalize

import (
   "fmt"
   _ "github.com/mbobakov/grpc-consul-resolver"
   "go.uber.org/zap"
   "google.golang.org/grpc"
   "mxshop_api/goods-web/global"
   "mxshop_api/goods-web/proto"
)

func InitSrvConn() {
   consulInfo := global.ServerConfig.ConsulInfo
   goodsConn, err := grpc.Dial(
      fmt.Sprintf("consul://%s:%d/%s?wait=14s", consulInfo.Host, consulInfo.Port, global.ServerConfig.UserSrvInfo.Name),
      grpc.WithInsecure(),
      grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
   )
   if err != nil {
      zap.S().Fatal("[InitSrvConn] 连接 【用户服务失败】")
   }

   goodsSrvClient := proto.NewGoodsClient(goodsConn)
   global.GoodsSrvClient = goodsSrvClient
}

1.7服务注册接口开发

goods-web/utils/registry/registry.go

package consul

import (
	"fmt"

	"github.com/hashicorp/consul/api"
	)

type Registry struct{
	Host string
	Port int
}

type RegistryClient interface {
	Register(address string, port int, name string, tags []string, id string) error
	DeRegister(serviceId string) error
}

func NewRegistryClient(host string, port int) RegistryClient{
	return &Registry{
		Host: host,
		Port: port,
	}
}

func (r *Registry)Register(address string, port int, name string, tags []string, id string) error {
	cfg := api.DefaultConfig()
	cfg.Address = fmt.Sprintf("%s:%d", r.Host, r.Port)

	client, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}
	//生成对应的检查对象
	check := &api.AgentServiceCheck{
		HTTP: fmt.Sprintf("http://%s:%d/health", address, port),
		Timeout: "5s",
		Interval: "5s",
		DeregisterCriticalServiceAfter: "10s",
	}

	//生成注册对象
	registration := new(api.AgentServiceRegistration)
	registration.Name = name
	registration.ID = id
	registration.Port = port
	registration.Tags = tags
	registration.Address = address
	registration.Check = check

	err = client.Agent().ServiceRegister(registration)
	if err != nil {
		panic(err)
	}
	return nil
}

func (r *Registry)DeRegister(serviceId string) error{
	cfg := api.DefaultConfig()
	cfg.Address = fmt.Sprintf("%s:%d", r.Host, r.Port)

	client, err := api.NewClient(cfg)
	if err != nil {
		return err
	}
	err = client.Agent().ServiceDeregister(serviceId)
	return err
}
1.8整合main.go
package main

import (
	"fmt"
	_ "github.com/gin-gonic/gin/binding"
	_ "github.com/go-playground/universal-translator"
	uuid "github.com/satori/go.uuid"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"mxshop_api/goods-web/global"
	"mxshop_api/goods-web/initalize"
	"mxshop_api/goods-web/utils"
	"mxshop_api/goods-web/utils/registry/consul"
	_ "mxshop_api/goods-web/validator"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	//1.初始化logger
	initalize.InitLogger()

	//2. 初始化配置文件
	initalize.InitConfig()

	//3.初始化routers
	Router := initalize.Routers()
	zap.S().Debugf("启动服务器,端口:%d", global.ServerConfig.Port)

	//4. 初始化翻译
	if err := initalize.InitTrans("zh"); err != nil {
		panic(err)
	}

	//5.初始化SRV的连接
	initalize.InitSrvConn()

	viper.AutomaticEnv()
	debug := viper.GetBool("MXSHOP_DEBUG")
	if !debug {
		port, err := utils.GetFreePort()
		if err == nil {
			global.ServerConfig.Port = port
		}
	}

	register_client := consul.NewRegistryClient(global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port)
	serviceId := fmt.Sprintf("%s", uuid.NewV4())
	err := register_client.Register(global.ServerConfig.Host, global.ServerConfig.Port, global.ServerConfig.Name, global.ServerConfig.Tags, serviceId)
	if err != nil {
		zap.S().Panic("服务注册失败:", err.Error())
	}
	zap.S().Debugf("启动服务器, 端口: %d", global.ServerConfig.Port)
	go func() {
		if err := Router.Run(fmt.Sprintf(":%d", global.ServerConfig.Port)); err != nil {
			zap.S().Panic("启动失败:", err.Error())
		}
	}()
	//接收终止信号
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	if err = register_client.DeRegister(serviceId); err != nil {
		zap.S().Info("注销失败:", err.Error())
	} else {
		zap.S().Info("注销成功:")
	}
}
2.goods_api接口
2.1商品的列表页接口
package goods

import (
   "context"
   "github.com/gin-gonic/gin"
   "github.com/go-playground/validator/v10"
   "go.uber.org/zap"
   "google.golang.org/grpc/codes"
   "google.golang.org/grpc/status"
   "mxshop_api/goods-web/global"
   "mxshop_api/goods-web/proto"
   "net/http"
   "strconv"
   "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": e.Code(),
            })
         }
         return
      }
   }
}

func HandleValidatorError(c *gin.Context, err error) {
   errs, ok := err.(validator.ValidationErrors)
   if !ok {
      c.JSON(http.StatusOK, gin.H{
         "msg": err.Error(),
      })
   }
   c.JSON(http.StatusBadRequest, gin.H{
      "error": removeTopStruct(errs.Translate(global.Trans)),
   })
   return
}
func List(ctx *gin.Context) {
   request := &proto.GoodsFilterRequest{}
   priceMin := ctx.DefaultQuery("pmin", "0")
   priceMinInt, _ := strconv.Atoi(priceMin)
   request.PriceMin = int32(priceMinInt)

   priceMax := ctx.DefaultQuery("pmax", "0")
   priceMaxInt, _ := strconv.Atoi(priceMax)
   request.PriceMax = int32(priceMaxInt)

   isHot := ctx.DefaultQuery("ih", "0")
   if isHot == "1" {
      request.IsHot = true
   }
   isNew := ctx.DefaultQuery("in", "0")
   if isNew == "1" {
      request.IsNew = true
   }

   isTab := ctx.DefaultQuery("it", "0")
   if isTab == "1" {
      request.IsTab = true
   }

   categoryId := ctx.DefaultQuery("c", "0")
   categoryIdInt, _ := strconv.Atoi(categoryId)
   request.TopCategory = int32(categoryIdInt)

   pages := ctx.DefaultQuery("p", "0")
   pagesInt, _ := strconv.Atoi(pages)
   request.Pages = int32(pagesInt)

   perNums := ctx.DefaultQuery("pnum", "0")
   perNumsInt, _ := strconv.Atoi(perNums)
   request.PagePerNums = int32(perNumsInt)

   keywords := ctx.DefaultQuery("q", "")
   request.KeyWords = keywords

   brandId := ctx.DefaultQuery("b", "0")
   brandIdInt, _ := strconv.Atoi(brandId)
   request.Brand = int32(brandIdInt)

   r, err := global.GoodsSrvClient.GoodsList(context.WithValue(context.Background(), "ginContext", ctx), request)
   if err != nil {
      zap.S().Errorw("[List] 查询 【商品列表】失败")
      HandleGrpcErrorToHttp(err, ctx)
      return
   }
   reMap := map[string]interface{}{
      "total": r.Total,
   }

   goodsList := make([]interface{}, 0)
   for _, value := range r.Data {
      goodsList = append(goodsList, map[string]interface{}{
         "id":          value.Id,
         "name":        value.Name,
         "goods_brief": value.GoodsBrief,
         "desc":        value.GoodsDesc,
         "ship_free":   value.ShipFree,
         "images":      value.Images,
         "desc_images": value.DescImages,
         "front_image": value.GoodsFrontImage,
         "shop_price":  value.ShopPrice,
         "category": map[string]interface{}{
            "id":   value.Category.Id,
            "name": value.Category.Name,
         },
         "brand": map[string]interface{}{
            "id":   value.Brand.Id,
            "name": value.Brand.Name,
            "logo": value.Brand.Logo,
         },
         "is_hot":  value.IsHot,
         "is_new":  value.IsNew,
         "on_sale": value.OnSale,
      })
   }
   reMap["data"] = goodsList

   ctx.JSON(http.StatusOK, reMap)
}
2.2新建商品
func New(ctx *gin.Context) {
   goodsForm := forms.GoodsForm{}
   if err := ctx.ShouldBindJSON(&goodsForm); err != nil {
      HandleValidatorError(ctx, err)
      return
   }
   goodsClient := global.GoodsSrvClient
   rsp, err := goodsClient.CreateGoods(context.Background(), &proto.CreateGoodsInfo{
      Name:            goodsForm.Name,
      GoodsSn:         goodsForm.GoodsSn,
      Stocks:          goodsForm.Stocks,
      MarketPrice:     goodsForm.MarketPrice,
      ShopPrice:       goodsForm.ShopPrice,
      GoodsBrief:      goodsForm.GoodsBrief,
      ShipFree:        *goodsForm.ShipFree,
      Images:          goodsForm.Images,
      DescImages:      goodsForm.DescImages,
      GoodsFrontImage: goodsForm.FrontImage,
      CategoryId:      goodsForm.CategoryId,
      BrandId:         goodsForm.Brand,
   })
   if err != nil {
      HandleGrpcErrorToHttp(err, ctx)
      return
   }
   ctx.JSON(http.StatusOK, rsp)
}
2.3商品详情
func Detail(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
   }
   r, err := global.GoodsSrvClient.GetGoodsDetail(context.WithValue(context.Background(), "ginContext", ctx), &proto.GoodInfoRequest{
      Id: int32(i),
   })
   if err != nil {
      HandleGrpcErrorToHttp(err, ctx)
   }
   rsp := map[string]interface{}{
      "id":          r.Id,
      "name":        r.Name,
      "goods_brief": r.GoodsBrief,
      "desc":        r.GoodsDesc,
      "ship_free":   r.ShipFree,
      "images":      r.Images,
      "desc_images": r.DescImages,
      "front_image": r.GoodsFrontImage,
      "shop_price":  r.ShopPrice,
      "ctegory": map[string]interface{}{
         "id":   r.Category.Id,
         "name": r.Category.Name,
      },
      "brand": map[string]interface{}{
         "id":   r.Brand.Id,
         "name": r.Brand.Name,
         "logo": r.Brand.Logo,
      },
      "is_hot":  r.IsHot,
      "is_new":  r.IsNew,
      "on_sale": r.OnSale,
   }
   ctx.JSON(http.StatusOK, rsp)
}
2.4商品删除、更新
func Delete(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
   }
   _, err = global.GoodsSrvClient.DeleteGoods(context.Background(), &proto.DeleteGoodsInfo{Id: int32(i)})
   if err != nil {
      HandleGrpcErrorToHttp(err, ctx)
      return
   }
   ctx.Status(http.StatusOK)
   return
}
func Update(ctx *gin.Context) {
   goodsForm := forms.GoodsForm{}
   if err := ctx.ShouldBindJSON(&goodsForm); err != nil {
      HandleValidatorError(ctx, err)
      return
   }

   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if _, err = global.GoodsSrvClient.UpdateGoods(context.Background(), &proto.CreateGoodsInfo{
      Id:              int32(i),
      Name:            goodsForm.Name,
      GoodsSn:         goodsForm.GoodsSn,
      Stocks:          goodsForm.Stocks,
      MarketPrice:     goodsForm.MarketPrice,
      ShopPrice:       goodsForm.ShopPrice,
      GoodsBrief:      goodsForm.GoodsBrief,
      ShipFree:        *goodsForm.ShipFree,
      Images:          goodsForm.Images,
      DescImages:      goodsForm.DescImages,
      GoodsFrontImage: goodsForm.FrontImage,
      CategoryId:      goodsForm.CategoryId,
      BrandId:         goodsForm.Brand,
   }); err != nil {
      HandleGrpcErrorToHttp(err, ctx)
      return
   }
   ctx.JSON(http.StatusOK, gin.H{
      "msg": "更新成功",
   })
}
2.5商品分类接口
package category

import (
   "context"
   "encoding/json"
   "github.com/gin-gonic/gin"
   "github.com/golang/protobuf/ptypes/empty"
   "go.uber.org/zap"
   "mxshop_api/goods-web/api"
   "mxshop_api/goods-web/forms"
   "mxshop_api/goods-web/global"
   "mxshop_api/goods-web/proto"
   "net/http"
   "strconv"
)

func List(ctx *gin.Context) {
   r, err := global.GoodsSrvClient.GetAllCategorysList(context.Background(), &empty.Empty{})
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   data := make([]interface{}, 0)
   err = json.Unmarshal([]byte(r.JsonData), &data)
   if err != nil {
      zap.S().Errorw("[List] 查询 【分类列表】失败: ", err.Error())
   }

   ctx.JSON(http.StatusOK, data)
}

func Detail(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
      return
   }

   reMap := make(map[string]interface{})
   subCategorys := make([]interface{}, 0)
   if r, err := global.GoodsSrvClient.GetSubCategory(context.Background(), &proto.CategoryListRequest{
      Id: int32(i),
   }); err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   } else {
      //写文档 特别是数据多的时候很慢, 先开发后写文档
      for _, value := range r.SubCategorys {
         subCategorys = append(subCategorys, map[string]interface{}{
            "id":              value.Id,
            "name":            value.Name,
            "level":           value.Level,
            "parent_category": value.ParentCategory,
            "is_tab":          value.IsTab,
         })
      }
      reMap["id"] = r.Info.Id
      reMap["name"] = r.Info.Name
      reMap["level"] = r.Info.Level
      reMap["parent_category"] = r.Info.ParentCategory
      reMap["is_tab"] = r.Info.IsTab
      reMap["sub_categorys"] = subCategorys

      ctx.JSON(http.StatusOK, reMap)
   }
   return
}
func New(ctx *gin.Context) {
   categoryForm := forms.CategoryForm{}
   if err := ctx.ShouldBindJSON(&categoryForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   rsp, err := global.GoodsSrvClient.CreateCategory(context.Background(), &proto.CategoryInfoRequest{
      Name:           categoryForm.Name,
      IsTab:          *categoryForm.IsTab,
      Level:          categoryForm.Level,
      ParentCategory: categoryForm.ParentCategory,
   })
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   request := make(map[string]interface{})
   request["id"] = rsp.Id
   request["name"] = rsp.Name
   request["parent"] = rsp.ParentCategory
   request["level"] = rsp.Level
   request["is_tab"] = rsp.IsTab

   ctx.JSON(http.StatusOK, request)
}
func Delete(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
      return
   }

   //1. 先查询出该分类写的所有子分类
   //2. 将所有的分类全部逻辑删除
   //3. 将该分类下的所有的商品逻辑删除
   _, err = global.GoodsSrvClient.DeleteCategory(context.Background(), &proto.DeleteCategoryRequest{Id: int32(i)})
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ctx.Status(http.StatusOK)
}
func Update(ctx *gin.Context) {
   categoryForm := forms.UpdateCategoryForm{}
   if err := ctx.ShouldBindJSON(&categoryForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
      return
   }

   request := &proto.CategoryInfoRequest{
      Id: int32(i),
      Name: categoryForm.Name,
   }
   if categoryForm.IsTab != nil {
      request.IsTab = *categoryForm.IsTab
   }
   _, err = global.GoodsSrvClient.UpdateCategory(context.Background(), request)
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ctx.Status(http.StatusOK)
}
2.6轮播图接口
package banners

import (
   "context"
   "github.com/gin-gonic/gin"
   "github.com/golang/protobuf/ptypes/empty"
   "mxshop_api/goods-web/api"
   "mxshop_api/goods-web/forms"
   "mxshop_api/goods-web/global"
   "mxshop_api/goods-web/proto"
   "net/http"
   "strconv"
)

func List(ctx *gin.Context) {
   rsp, err := global.GoodsSrvClient.BannerList(context.Background(), &empty.Empty{})
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   result := make([]interface{}, 0)
   for _, value := range rsp.Data {
      reMap := make(map[string]interface{})
      reMap["id"] = value.Id
      reMap["index"] = value.Index
      reMap["image"] = value.Image
      reMap["url"] = value.Url

      result = append(result, reMap)
   }

   ctx.JSON(http.StatusOK, result)
}

func New(ctx *gin.Context) {
   bannerForm := forms.BannerForm{}
   if err := ctx.ShouldBindJSON(&bannerForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   rsp, err := global.GoodsSrvClient.CreateBanner(context.Background(), &proto.BannerRequest{
      Index: int32(bannerForm.Index),
      Url:   bannerForm.Url,
      Image: bannerForm.Image,
   })
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   response := make(map[string]interface{})
   response["id"] = rsp.Id
   response["index"] = rsp.Index
   response["url"] = rsp.Url
   response["image"] = rsp.Image

   ctx.JSON(http.StatusOK, response)
}

func Update(ctx *gin.Context) {
   bannerForm := forms.BannerForm{}
   if err := ctx.ShouldBindJSON(&bannerForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
      return
   }

   _, err = global.GoodsSrvClient.UpdateBanner(context.Background(), &proto.BannerRequest{
      Id:    int32(i),
      Index: int32(bannerForm.Index),
      Url:   bannerForm.Url,
   })
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ctx.Status(http.StatusOK)
}

func Delete(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
      return
   }
   _, err = global.GoodsSrvClient.DeleteBanner(context.Background(), &proto.BannerRequest{Id: int32(i)})
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ctx.JSON(http.StatusOK, "")
}
2.7品牌列表接口
func BrandList(ctx *gin.Context) {
	pn := ctx.DefaultQuery("pn", "0")
	pnInt, _ := strconv.Atoi(pn)
	pSize := ctx.DefaultQuery("psize", "10")
	pSizeInt, _ := strconv.Atoi(pSize)

	rsp, err := global.GoodsSrvClient.BrandList(context.Background(), &proto.BrandFilterRequest{
		Pages:       int32(pnInt),
		PagePerNums: int32(pSizeInt),
	})

	if err != nil {
		api.HandleGrpcErrorToHttp(err, ctx)
		return
	}

	result := make([]interface{}, 0)
	reMap := make(map[string]interface{})
	reMap["total"] = rsp.Total
	for _, value := range rsp.Data[pnInt : pnInt*pSizeInt+pSizeInt] {
		reMap := make(map[string]interface{})
		reMap["id"] = value.Id
		reMap["name"] = value.Name
		reMap["logo"] = value.Logo

		result = append(result, reMap)
	}

	reMap["data"] = result

	ctx.JSON(http.StatusOK, reMap)
}

func NewBrand(ctx *gin.Context) {
	brandForm := forms.BrandForm{}
	if err := ctx.ShouldBindJSON(&brandForm); err != nil {
		api.HandleValidatorError(ctx, err)
		return
	}

	rsp, err := global.GoodsSrvClient.CreateBrand(context.Background(), &proto.BrandRequest{
		Name: brandForm.Name,
		Logo: brandForm.Logo,
	})
	if err != nil {
		api.HandleGrpcErrorToHttp(err, ctx)
		return
	}

	request := make(map[string]interface{})
	request["id"] = rsp.Id
	request["name"] = rsp.Name
	request["logo"] = rsp.Logo

	ctx.JSON(http.StatusOK, request)
}

func DeleteBrand(ctx *gin.Context) {
	id := ctx.Param("id")
	i, err := strconv.ParseInt(id, 10, 32)
	if err != nil {
		ctx.Status(http.StatusNotFound)
		return
	}
	_, err = global.GoodsSrvClient.DeleteBrand(context.Background(), &proto.BrandRequest{Id: int32(i)})
	if err != nil {
		api.HandleGrpcErrorToHttp(err, ctx)
		return
	}

	ctx.Status(http.StatusOK)
}

func UpdateBrand(ctx *gin.Context) {
	brandForm := forms.BrandForm{}
	if err := ctx.ShouldBindJSON(&brandForm); err != nil {
		api.HandleValidatorError(ctx, err)
		return
	}

	id := ctx.Param("id")
	i, err := strconv.ParseInt(id, 10, 32)
	if err != nil {
		ctx.Status(http.StatusNotFound)
		return
	}

	_, err = global.GoodsSrvClient.UpdateBrand(context.Background(), &proto.BrandRequest{
		Id:   int32(i),
		Name: brandForm.Name,
		Logo: brandForm.Logo,
	})
	if err != nil {
		api.HandleGrpcErrorToHttp(err, ctx)
		return
	}
	ctx.Status(http.StatusOK)
}
2.8品牌分类接口
func GetCategoryBrandList(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
      return
   }

   rsp, err := global.GoodsSrvClient.GetCategoryBrandList(context.Background(), &proto.CategoryInfoRequest{
      Id: int32(i),
   })
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   result := make([]interface{}, 0)
   for _, value := range rsp.Data {
      reMap := make(map[string]interface{})
      reMap["id"] = value.Id
      reMap["name"] = value.Name
      reMap["logo"] = value.Logo

      result = append(result, reMap)
   }

   ctx.JSON(http.StatusOK, result)
}

func CategoryBrandList(ctx *gin.Context) {
   //所有的list返回的数据结构
   /*
      {
         "total": 100,
         "data":[{},{}]
      }
   */
   rsp, err := global.GoodsSrvClient.CategoryBrandList(context.Background(), &proto.CategoryBrandFilterRequest{})
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   reMap := map[string]interface{}{
      "total": rsp.Total,
   }

   result := make([]interface{}, 0)
   for _, value := range rsp.Data {
      reMap := make(map[string]interface{})
      reMap["id"] = value.Id
      reMap["category"] = map[string]interface{}{
         "id":   value.Category.Id,
         "name": value.Category.Name,
      }
      reMap["brand"] = map[string]interface{}{
         "id":   value.Brand.Id,
         "name": value.Brand.Name,
         "logo": value.Brand.Logo,
      }

      result = append(result, reMap)
   }

   reMap["data"] = result
   ctx.JSON(http.StatusOK, reMap)
}

func NewCategoryBrand(ctx *gin.Context) {
   categoryBrandForm := forms.CategoryBrandForm{}
   if err := ctx.ShouldBindJSON(&categoryBrandForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   rsp, err := global.GoodsSrvClient.CreateCategoryBrand(context.Background(), &proto.CategoryBrandRequest{
      CategoryId: int32(categoryBrandForm.CategoryId),
      BrandId:    int32(categoryBrandForm.BrandId),
   })
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   response := make(map[string]interface{})
   response["id"] = rsp.Id

   ctx.JSON(http.StatusOK, response)
}

func UpdateCategoryBrand(ctx *gin.Context) {
   categoryBrandForm := forms.CategoryBrandForm{}
   if err := ctx.ShouldBindJSON(&categoryBrandForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
      return
   }

   _, err = global.GoodsSrvClient.UpdateCategoryBrand(context.Background(), &proto.CategoryBrandRequest{
      Id:         int32(i),
      CategoryId: int32(categoryBrandForm.CategoryId),
      BrandId:    int32(categoryBrandForm.BrandId),
   })
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   ctx.Status(http.StatusOK)
}

func DeleteCategoryBrand(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.ParseInt(id, 10, 32)
   if err != nil {
      ctx.Status(http.StatusNotFound)
      return
   }
   _, err = global.GoodsSrvClient.DeleteCategoryBrand(context.Background(), &proto.CategoryBrandRequest{Id: int32(i)})
   if err != nil {
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ctx.JSON(http.StatusOK, "")
}
2.10接口路由设置
2.10.1商品接口路由
package router

import (
   "github.com/gin-gonic/gin"
   "mxshop_api/goods-web/api/goods"
   "mxshop_api/goods-web/middlewares"
)

func InitGoodsRouter(Router *gin.RouterGroup) {
   GoodsRouter := Router.Group("goods")
   {
      GoodsRouter.GET("", goods.List)                                                            //商品列表
      GoodsRouter.POST("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.New)          //改接口需要管理员权限
      GoodsRouter.GET("/:id", goods.Detail)                                                      //获取商品的详情
      GoodsRouter.DELETE("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Delete) //删除商品
      GoodsRouter.PUT("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Update)
   }
}
2.10.2商品分类路由
package router

import (
   "github.com/gin-gonic/gin"
   "mxshop_api/goods-web/api/category"
)

func InitCategoryRouter(Router *gin.RouterGroup) {
   CategoryRouter := Router.Group("categorys")
   {
      CategoryRouter.GET("", category.List)          // 商品类别列表页
      CategoryRouter.DELETE("/:id", category.Delete) // 删除分类
      CategoryRouter.GET("/:id", category.Detail)    // 获取分类详情
      CategoryRouter.POST("", category.New)          //新建分类
      CategoryRouter.PUT("/:id", category.Update)    //修改分类信息
   }
}
2.10.3banner接中路由
package router

import (
   "github.com/gin-gonic/gin"
   "mxshop_api/goods-web/api/banners"
   "mxshop_api/goods-web/middlewares"
)

func InitBannerRouter(Router *gin.RouterGroup) {
   BannerRouter := Router.Group("banners")
   {
      BannerRouter.GET("", banners.List)                                                            // 轮播图列表页
      BannerRouter.DELETE("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), banners.Delete) // 删除轮播图
      BannerRouter.POST("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), banners.New)          //新建轮播图
      BannerRouter.PUT("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), banners.Update)    //修改轮播图信息
   }
}
2.10.4品牌分类接口路由
package router

import (
   "github.com/gin-gonic/gin"
)

// InitBrandRouter 1. 商品的api接口开发完成
//2. 图片的坑
func InitBrandRouter(Router *gin.RouterGroup) {
   BrandRouter := Router.Group("brands")
   {
      BrandRouter.GET("", brands.BrandList)          // 品牌列表页
      BrandRouter.DELETE("/:id", brands.DeleteBrand) // 删除品牌
      BrandRouter.POST("", brands.NewBrand)          //新建品牌
      BrandRouter.PUT("/:id", brands.UpdateBrand)    //修改品牌信息
   }

   CategoryBrandRouter := Router.Group("categorybrands")
   {
      CategoryBrandRouter.GET("", brands.CategoryBrandList)          // 类别品牌列表页
      CategoryBrandRouter.DELETE("/:id", brands.DeleteCategoryBrand) // 删除类别品牌
      CategoryBrandRouter.POST("", brands.NewCategoryBrand)          //新建类别品牌
      CategoryBrandRouter.PUT("/:id", brands.UpdateCategoryBrand)    //修改类别品牌
      CategoryBrandRouter.GET("/:id", brands.GetCategoryBrandList)   //获取分类的品牌
   }
}
2.11商品服务表单
2.11.1商品表单
package forms

type GoodsForm struct {
   Name        string   `form:"name" json:"name" binding:"required,min=2,max=100"`
   GoodsSn     string   `form:"goods_sn" json:"goods_sn" binding:"required,min=2,lt=20"`
   Stocks      int32    `form:"stocks" json:"stocks" binding:"required,min=1"`
   CategoryId  int32    `form:"category" json:"category" binding:"required"`
   MarketPrice float32  `form:"market_price" json:"market_price" binding:"required,min=0"`
   ShopPrice   float32  `form:"shop_price" json:"shop_price" binding:"required,min=0"`
   GoodsBrief  string   `form:"goods_brief" json:"goods_brief" binding:"required,min=3"`
   Images      []string `form:"images" json:"images" binding:"required,min=1"`
   DescImages  []string `form:"desc_images" json:"desc_images" binding:"required,min=1"`
   ShipFree    *bool    `form:"ship_free" json:"ship_free" binding:"required"`
   FrontImage  string   `form:"front_image" json:"front_image" binding:"required,url"`
   Brand       int32    `form:"brand" json:"brand" binding:"required"`
}

type GoodsStatusForm struct {
   IsNew  *bool `form:"new" json:"new" binding:"required"`
   IsHot  *bool `form:"hot" json:"hot" binding:"required"`
   OnSale *bool `form:"sale" json:"sale" binding:"required"`
}
2.11.2分类表单
package forms

type CategoryForm struct {
   Name           string `form:"name" json:"name" binding:"required,min=3,max=20"`
   ParentCategory int32  `form:"parent" json:"parent"`
   Level          int32  `form:"level" json:"level" binding:"required,oneof=1 2 3"`
   IsTab          *bool  `form:"is_tab" json:"is_tab" binding:"required"`
}

type UpdateCategoryForm struct {
   Name  string `form:"name" json:"name" binding:"required,min=3,max=20"`
   IsTab *bool  `form:"is_tab" json:"is_tab"`
}
2.11.3Banner表单
package forms

type BannerForm struct {
   Image string `form:"image" json:"image" binding:"url"`
   Index int    `form:"index" json:"index" binding:"required"`
   Url   string `form:"url" json:"url" binding:"url"`
}
2.11.4商品品牌表单
package forms

type BrandForm struct {
   Name string `form:"name" json:"name" binding:"required,min=3,max=10"`
   Logo string `form:"logo" json:"logo" binding:"url"`
}

type CategoryBrandForm struct {
   CategoryId int `form:"category_id" json:"category_id" binding:"required"`
   BrandId    int `form:"brand_id" json:"brand_id" binding:"required"`
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值