八.订单微服务API(order-web)

八.订单微服务API(order-web)

1.项目初始化
1.1初始化目录

在这里插入图片描述

1.2添加yaml配置文件

order-web/order-web.yaml

host: '192.168.0.4'
port: 8848
namespace: 'ba14206d-403f-4377-b7e7-70a3e8fa2bbf'
user: 'nacos'
password: 'nacos'
dataid: 'order-web.json'
group: 'dev'

1.3建立全局变量

order-web/global/global.go

package global

import (
   ut "github.com/go-playground/universal-translator"
   goodsProto "mxshop_api/goods-web/proto"
   "mxshop_api/order-web/config"
   "mxshop_api/order-web/proto"
)

var (
   Trans ut.Translator

   ServerConfig *config.ServerConfig = &config.ServerConfig{}

   NacosConfig *config.NacosConfig = &config.NacosConfig{}

   GoodsSrvClient goodsProto.GoodsClient

   OrderSrvClient proto.OrderClient

   InventorySrvClient proto.InventoryClient
)
1.4在nacos建立配置文件

在这里插入图片描述

1.5建立配置文件的映射文件

order-web/config/config.go

package config

type GoodsSrvConfig struct {
   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 AlipayConfig struct {
   AppID        string `mapstructure:"app_id" json:"app_id"`
   PrivateKey   string `mapstructure:"private_key" json:"private_key"`
   AliPublicKey string `mapstructure:"ali_public_key" json:"ali_public_key"`
   NotifyURL    string `mapstructure:"notify_url" json:"notify_url"`
   ReturnURL    string `mapstructure:"return_url" json:"return_url"`
}

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"`
   GoodsSrvInfo     GoodsSrvConfig `mapstructure:"goods_srv" json:"goods_srv"`
   OrderSrvInfo     GoodsSrvConfig `mapstructure:"order_srv" json:"order_srv"`
   InventorySrvInfo GoodsSrvConfig `mapstructure:"inventory_srv" json:"inventory_srv"`
   JWTInfo          JWTConfig      `mapstructure:"jwt" json:"jwt"`
   RedisInfo        RedisConfig    `mapstructure:"redis" json:"redis"`
   ConsulInfo       ConsulConfig   `mapstructure:"consul" json:"consul"`
   AliPayInfo       AlipayConfig   `mapstructure:"alipay" json:"alipay"`
}

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.6配 置文件初始化

order-web/initalize/config.go

package initalize

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/order-web/global"
)

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

func InitConfig() {
   debug := GetEnvInfo("MXSHOP_DEBUG")
   configFilePrefix := "config"
   configFileName := fmt.Sprintf("order-web/%s-pro.yaml", configFilePrefix)
   if debug {
      configFileName = fmt.Sprintf("order-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)
   //viper功能,动态监控变化
   //v.WatchConfig()
   //v.OnConfigChange(func(e fsnotify.Event) {
   // zap.S().Infof("配置信息产生变化:%v", e.Name)
   // _ = v.ReadInConfig()
   // _ = v.Unmarshal(global.ServerConfig)
   // fmt.Println(global.ServerConfig)
   //})
   //从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) //字符串 - 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)
}

order-web/initalize/srv_conn.go

package initalize

import (
   "fmt"
   _ "github.com/mbobakov/grpc-consul-resolver"
   "go.uber.org/zap"
   "google.golang.org/grpc"
   goodsProto "mxshop_api/goods-web/proto"
   "mxshop_api/order-web/global"
   "mxshop_api/order-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.GoodsSrvInfo.Name),
      grpc.WithInsecure(),
      grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
   )
   if err != nil {
      zap.S().Fatal("[InitSrvConn] 连接 【商品服务失败】")
   }

   global.GoodsSrvClient = goodsProto.NewGoodsClient(goodsConn)

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

   global.OrderSrvClient = proto.NewOrderClient(orderConn)

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

   global.InventorySrvClient = proto.NewInventoryClient(invConn)
}

order-web/initalize/logger.go

package initalize

import "go.uber.org/zap"

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

order-web/initalize/router.go

package initalize

import (
   "github.com/gin-gonic/gin"
   "mxshop_api/order-web/middlewares"
   "mxshop_api/order-web/router"
   "net/http"
)

func Routers() *gin.Engine {
   Router := gin.Default()
   Router.GET("/health", func(c *gin.Context) {
      c.JSON(http.StatusOK, gin.H{
         "code":    http.StatusOK,
         "success": true,
      })
   })

   //配置跨域
   Router.Use(middlewares.Cors())

   ApiGroup := Router.Group("/o/v1")
   router.InitOrderRouter(ApiGroup)
   router.InitShopCartRouter(ApiGroup)

   return Router
}

order-web/initalize/validator.go

package initalize

import (
   "fmt"
   "mxshop_api/order-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
}
1.7main.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/order-web/global"
   "mxshop_api/order-web/initalize"
   "mxshop_api/order-web/utils"
   "mxshop_api/order-web/utils/registry/consul"
   _ "mxshop_api/order-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.API接口开发
2.1订单列表开发
func List(ctx *gin.Context) {
   //订单的列表
   userId, _ := ctx.Get("userId")
   claims, _ := ctx.Get("claims")

   request := proto.OrderFilterRequest{}

   //如果是管理员用户则返回所有的订单
   model := claims.(*models.CustomClaims)
   if model.AuthorityId == 1 {
      request.UserId = int32(userId.(uint))
   }

   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)

   request.Pages = int32(pagesInt)
   request.PagePerNums = int32(perNumsInt)

   rsp, err := global.OrderSrvClient.OrderList(context.Background(), &request)
   if err != nil {
      zap.S().Errorw("获取订单列表失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   reMap := gin.H{
      "total": rsp.Total,
   }
   orderList := make([]interface{}, 0)

   for _, item := range rsp.Data {
      tmpMap := map[string]interface{}{}

      tmpMap["id"] = item.Id
      tmpMap["status"] = item.Status
      tmpMap["pay_type"] = item.PayType
      tmpMap["user"] = item.UserId
      tmpMap["post"] = item.Post
      tmpMap["total"] = item.Total
      tmpMap["address"] = item.Address
      tmpMap["name"] = item.Name
      tmpMap["mobile"] = item.Mobile
      tmpMap["order_sn"] = item.OrderSn
      tmpMap["id"] = item.Id
      tmpMap["add_time"] = item.AddTime

      orderList = append(orderList, tmpMap)
   }
   reMap["data"] = orderList
   ctx.JSON(http.StatusOK, reMap)
}
2.2创建订单
func New(ctx *gin.Context) {
   orderForm := forms.CreateOrderForm{}
   if err := ctx.ShouldBindJSON(&orderForm); err != nil {
      api.HandleValidatorError(ctx, err)
   }
   userId, _ := ctx.Get("userId")
   rsp, err := global.OrderSrvClient.CreateOrder(context.WithValue(context.Background(), "ginContext", ctx), &proto.OrderRequest{
      UserId:  int32(userId.(uint)),
      Name:    orderForm.Name,
      Mobile:  orderForm.Mobile,
      Address: orderForm.Address,
      Post:    orderForm.Post,
   })
   if err != nil {
      zap.S().Errorw("新建订单失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   //生成支付宝的支付url
   client, err := alipay.New(global.ServerConfig.AliPayInfo.AppID, global.ServerConfig.AliPayInfo.PrivateKey, false)
   if err != nil {
      zap.S().Errorw("实例化支付宝失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }
   err = client.LoadAliPayPublicKey((global.ServerConfig.AliPayInfo.AliPublicKey))
   if err != nil {
      zap.S().Errorw("加载支付宝的公钥失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }

   var p = alipay.TradePagePay{}
   p.NotifyURL = global.ServerConfig.AliPayInfo.NotifyURL
   p.ReturnURL = global.ServerConfig.AliPayInfo.ReturnURL
   p.Subject = "慕学生鲜订单-" + rsp.OrderSn
   p.OutTradeNo = rsp.OrderSn
   p.TotalAmount = strconv.FormatFloat(float64(rsp.Total), 'f', 2, 64)
   p.ProductCode = "FAST_INSTANT_TRADE_PAY"

   url, err := client.TradePagePay(p)
   if err != nil {
      zap.S().Errorw("生成支付url失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }

   ctx.JSON(http.StatusOK, gin.H{
      "id":         rsp.Id,
      "alipay_url": url.String(),
   })
}
2.3订单详情
func Detail(ctx *gin.Context) {
   id := ctx.Param("id")
   userId, _ := ctx.Get("userId")
   i, err := strconv.Atoi(id)
   if err != nil {
      ctx.JSON(http.StatusNotFound, gin.H{
         "msg": "url格式出错",
      })
      return
   }

   //如果是管理员用户则返回所有的订单
   request := proto.OrderRequest{
      Id: int32(i),
   }
   claims, _ := ctx.Get("claims")
   model := claims.(*models.CustomClaims)
   if model.AuthorityId == 1 {
      request.UserId = int32(userId.(uint))
   }

   rsp, err := global.OrderSrvClient.OrderDetail(context.Background(), &request)
   if err != nil {
      zap.S().Errorw("获取订单详情失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   reMap := gin.H{}
   reMap["id"] = rsp.OrderInfo.Id
   reMap["status"] = rsp.OrderInfo.Status
   reMap["user"] = rsp.OrderInfo.UserId
   reMap["post"] = rsp.OrderInfo.Post
   reMap["total"] = rsp.OrderInfo.Total
   reMap["address"] = rsp.OrderInfo.Address
   reMap["name"] = rsp.OrderInfo.Name
   reMap["mobile"] = rsp.OrderInfo.Mobile
   reMap["pay_type"] = rsp.OrderInfo.PayType
   reMap["order_sn"] = rsp.OrderInfo.OrderSn

   goodsList := make([]interface{}, 0)
   for _, item := range rsp.Goods {
      tmpMap := gin.H{
         "id":    item.GoodsId,
         "name":  item.GoodsName,
         "image": item.GoodsImage,
         "price": item.GoodsPrice,
         "nums":  item.Nums,
      }

      goodsList = append(goodsList, tmpMap)
   }
   reMap["goods"] = goodsList

   //生成支付宝的支付url
   client, err := alipay.New(global.ServerConfig.AliPayInfo.AppID, global.ServerConfig.AliPayInfo.PrivateKey, false)
   if err != nil {
      zap.S().Errorw("实例化支付宝失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }
   err = client.LoadAliPayPublicKey((global.ServerConfig.AliPayInfo.AliPublicKey))
   if err != nil {
      zap.S().Errorw("加载支付宝的公钥失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }

   var p = alipay.TradePagePay{}
   p.NotifyURL = global.ServerConfig.AliPayInfo.NotifyURL
   p.ReturnURL = global.ServerConfig.AliPayInfo.ReturnURL
   p.Subject = "慕学生鲜订单-" + rsp.OrderInfo.OrderSn
   p.OutTradeNo = rsp.OrderInfo.OrderSn
   p.TotalAmount = strconv.FormatFloat(float64(rsp.OrderInfo.Total), 'f', 2, 64)
   p.ProductCode = "FAST_INSTANT_TRADE_PAY"

   url, err := client.TradePagePay(p)
   if err != nil {
      zap.S().Errorw("生成支付url失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }
   reMap["alipay_url"] = url.String()

   ctx.JSON(http.StatusOK, reMap)
}
2.4购物车列表
func List(ctx *gin.Context) {
   //获取购物车商品
   userId, _ := ctx.Get("userId")
   rsp, err := global.OrderSrvClient.CartItemList(context.Background(), &proto.UserInfo{
      Id: int32(userId.(uint)),
   })
   if err != nil {
      zap.S().Errorw("[List] 查询 【购物车列表】失败")
      panic(err)
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ids := make([]int32, 0)
   for _, item := range rsp.Data {
      ids = append(ids, item.GoodsId)
   }
   if len(ids) == 0 {
      ctx.JSON(http.StatusOK, gin.H{
         "total": 0,
      })
      return
   }

   //请求商品服务获取商品信息
   goodsRsp, err := global.GoodsSrvClient.BatchGetGoods(context.Background(), &goodsProto.BatchGoodsIdInfo{
      Id: ids,
   })
   if err != nil {
      zap.S().Errorw("[List] 批量查询【商品列表】失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   reMap := gin.H{
      "total": rsp.Total,
   }

   goodsList := make([]interface{}, 0)
   for _, item := range rsp.Data {
      for _, good := range goodsRsp.Data {
         if good.Id == item.GoodsId {
            tmpMap := map[string]interface{}{}
            tmpMap["id"] = item.Id
            tmpMap["goods_id"] = item.GoodsId
            tmpMap["good_name"] = good.Name
            tmpMap["good_image"] = good.GoodsFrontImage
            tmpMap["good_price"] = good.ShopPrice
            tmpMap["nums"] = item.Nums
            tmpMap["checked"] = item.Checked

            goodsList = append(goodsList, tmpMap)
         }
      }
   }
   reMap["data"] = goodsList
   ctx.JSON(http.StatusOK, reMap)
}
2.5创建购物车
func New(ctx *gin.Context) {
   //添加商品到购物车
   itemForm := forms.ShopCartItemForm{}
   if err := ctx.ShouldBindJSON(&itemForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   //为了严谨性,添加商品到购物车之前,记得检查一下商品是否存在
   _, err := global.GoodsSrvClient.GetGoodsDetail(context.Background(), &goodsProto.GoodInfoRequest{
      Id: itemForm.GoodsId,
   })
   if err != nil {
      zap.S().Errorw("[List] 查询【商品信息】失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   //如果现在添加到购物车的数量和库存的数量不一致
   invRsp, err := global.InventorySrvClient.InvDetail(context.Background(), &proto.GoodsInvInfo{
      GoodsId: itemForm.GoodsId,
   })
   if err != nil {
      zap.S().Errorw("[List] 查询【库存信息】失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   if invRsp.Num < itemForm.Nums {
      ctx.JSON(http.StatusBadRequest, gin.H{
         "nums": "库存不足",
      })
      return
   }

   userId, _ := ctx.Get("userId")
   rsp, err := global.OrderSrvClient.CreateCartItem(context.Background(), &proto.CartItemRequest{
      GoodsId: itemForm.GoodsId,
      UserId:  int32(userId.(uint)),
      Nums:    itemForm.Nums,
   })

   if err != nil {
      zap.S().Errorw("添加到购物车失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ctx.JSON(http.StatusOK, gin.H{
      "id": rsp.Id,
   })
}
2.6更新购物车
func Update(ctx *gin.Context) {
   // o/v1/421
   id := ctx.Param("id")
   i, err := strconv.Atoi(id)
   if err != nil {
      ctx.JSON(http.StatusNotFound, gin.H{
         "msg": "url格式出错",
      })
      return
   }

   itemForm := forms.ShopCartItemUpdateForm{}
   if err := ctx.ShouldBindJSON(&itemForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   userId, _ := ctx.Get("userId")
   request := proto.CartItemRequest{
      UserId:  int32(userId.(uint)),
      GoodsId: int32(i),
      Nums:    itemForm.Nums,
      Checked: false,
   }
   if itemForm.Checked != nil {
      request.Checked = *itemForm.Checked
   }

   _, err = global.OrderSrvClient.UpdateCartItem(context.Background(), &request)
   if err != nil {
      zap.S().Errorw("更新购物车记录失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   ctx.Status(http.StatusOK)
}
2.7删除购物车
func Delete(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.Atoi(id)
   if err != nil {
      ctx.JSON(http.StatusNotFound, gin.H{
         "msg": "url格式出错",
      })
      return
   }

   userId, _ := ctx.Get("userId")
   _, err = global.OrderSrvClient.DeleteCartItem(context.Background(), &proto.CartItemRequest{
      UserId:  int32(userId.(uint)),
      GoodsId: int32(i),
   })
   if err != nil {
      zap.S().Errorw("删除购物车记录失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   ctx.Status(http.StatusOK)
}

lipay.TradePagePay{}
p.NotifyURL = global.ServerConfig.AliPayInfo.NotifyURL
p.ReturnURL = global.ServerConfig.AliPayInfo.ReturnURL
p.Subject = “慕学生鲜订单-” + rsp.OrderSn
p.OutTradeNo = rsp.OrderSn
p.TotalAmount = strconv.FormatFloat(float64(rsp.Total), ‘f’, 2, 64)
p.ProductCode = “FAST_INSTANT_TRADE_PAY”

url, err := client.TradePagePay§
if err != nil {
zap.S().Errorw(“生成支付url失败”)
ctx.JSON(http.StatusInternalServerError, gin.H{
“msg”: err.Error(),
})
return
}

ctx.JSON(http.StatusOK, gin.H{
“id”: rsp.Id,
“alipay_url”: url.String(),
})
}


##### 2.3订单详情

```go
func Detail(ctx *gin.Context) {
   id := ctx.Param("id")
   userId, _ := ctx.Get("userId")
   i, err := strconv.Atoi(id)
   if err != nil {
      ctx.JSON(http.StatusNotFound, gin.H{
         "msg": "url格式出错",
      })
      return
   }

   //如果是管理员用户则返回所有的订单
   request := proto.OrderRequest{
      Id: int32(i),
   }
   claims, _ := ctx.Get("claims")
   model := claims.(*models.CustomClaims)
   if model.AuthorityId == 1 {
      request.UserId = int32(userId.(uint))
   }

   rsp, err := global.OrderSrvClient.OrderDetail(context.Background(), &request)
   if err != nil {
      zap.S().Errorw("获取订单详情失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   reMap := gin.H{}
   reMap["id"] = rsp.OrderInfo.Id
   reMap["status"] = rsp.OrderInfo.Status
   reMap["user"] = rsp.OrderInfo.UserId
   reMap["post"] = rsp.OrderInfo.Post
   reMap["total"] = rsp.OrderInfo.Total
   reMap["address"] = rsp.OrderInfo.Address
   reMap["name"] = rsp.OrderInfo.Name
   reMap["mobile"] = rsp.OrderInfo.Mobile
   reMap["pay_type"] = rsp.OrderInfo.PayType
   reMap["order_sn"] = rsp.OrderInfo.OrderSn

   goodsList := make([]interface{}, 0)
   for _, item := range rsp.Goods {
      tmpMap := gin.H{
         "id":    item.GoodsId,
         "name":  item.GoodsName,
         "image": item.GoodsImage,
         "price": item.GoodsPrice,
         "nums":  item.Nums,
      }

      goodsList = append(goodsList, tmpMap)
   }
   reMap["goods"] = goodsList

   //生成支付宝的支付url
   client, err := alipay.New(global.ServerConfig.AliPayInfo.AppID, global.ServerConfig.AliPayInfo.PrivateKey, false)
   if err != nil {
      zap.S().Errorw("实例化支付宝失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }
   err = client.LoadAliPayPublicKey((global.ServerConfig.AliPayInfo.AliPublicKey))
   if err != nil {
      zap.S().Errorw("加载支付宝的公钥失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }

   var p = alipay.TradePagePay{}
   p.NotifyURL = global.ServerConfig.AliPayInfo.NotifyURL
   p.ReturnURL = global.ServerConfig.AliPayInfo.ReturnURL
   p.Subject = "慕学生鲜订单-" + rsp.OrderInfo.OrderSn
   p.OutTradeNo = rsp.OrderInfo.OrderSn
   p.TotalAmount = strconv.FormatFloat(float64(rsp.OrderInfo.Total), 'f', 2, 64)
   p.ProductCode = "FAST_INSTANT_TRADE_PAY"

   url, err := client.TradePagePay(p)
   if err != nil {
      zap.S().Errorw("生成支付url失败")
      ctx.JSON(http.StatusInternalServerError, gin.H{
         "msg": err.Error(),
      })
      return
   }
   reMap["alipay_url"] = url.String()

   ctx.JSON(http.StatusOK, reMap)
}
2.4购物车列表
func List(ctx *gin.Context) {
   //获取购物车商品
   userId, _ := ctx.Get("userId")
   rsp, err := global.OrderSrvClient.CartItemList(context.Background(), &proto.UserInfo{
      Id: int32(userId.(uint)),
   })
   if err != nil {
      zap.S().Errorw("[List] 查询 【购物车列表】失败")
      panic(err)
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ids := make([]int32, 0)
   for _, item := range rsp.Data {
      ids = append(ids, item.GoodsId)
   }
   if len(ids) == 0 {
      ctx.JSON(http.StatusOK, gin.H{
         "total": 0,
      })
      return
   }

   //请求商品服务获取商品信息
   goodsRsp, err := global.GoodsSrvClient.BatchGetGoods(context.Background(), &goodsProto.BatchGoodsIdInfo{
      Id: ids,
   })
   if err != nil {
      zap.S().Errorw("[List] 批量查询【商品列表】失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   reMap := gin.H{
      "total": rsp.Total,
   }

   goodsList := make([]interface{}, 0)
   for _, item := range rsp.Data {
      for _, good := range goodsRsp.Data {
         if good.Id == item.GoodsId {
            tmpMap := map[string]interface{}{}
            tmpMap["id"] = item.Id
            tmpMap["goods_id"] = item.GoodsId
            tmpMap["good_name"] = good.Name
            tmpMap["good_image"] = good.GoodsFrontImage
            tmpMap["good_price"] = good.ShopPrice
            tmpMap["nums"] = item.Nums
            tmpMap["checked"] = item.Checked

            goodsList = append(goodsList, tmpMap)
         }
      }
   }
   reMap["data"] = goodsList
   ctx.JSON(http.StatusOK, reMap)
}
2.5创建购物车
func New(ctx *gin.Context) {
   //添加商品到购物车
   itemForm := forms.ShopCartItemForm{}
   if err := ctx.ShouldBindJSON(&itemForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   //为了严谨性,添加商品到购物车之前,记得检查一下商品是否存在
   _, err := global.GoodsSrvClient.GetGoodsDetail(context.Background(), &goodsProto.GoodInfoRequest{
      Id: itemForm.GoodsId,
   })
   if err != nil {
      zap.S().Errorw("[List] 查询【商品信息】失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   //如果现在添加到购物车的数量和库存的数量不一致
   invRsp, err := global.InventorySrvClient.InvDetail(context.Background(), &proto.GoodsInvInfo{
      GoodsId: itemForm.GoodsId,
   })
   if err != nil {
      zap.S().Errorw("[List] 查询【库存信息】失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   if invRsp.Num < itemForm.Nums {
      ctx.JSON(http.StatusBadRequest, gin.H{
         "nums": "库存不足",
      })
      return
   }

   userId, _ := ctx.Get("userId")
   rsp, err := global.OrderSrvClient.CreateCartItem(context.Background(), &proto.CartItemRequest{
      GoodsId: itemForm.GoodsId,
      UserId:  int32(userId.(uint)),
      Nums:    itemForm.Nums,
   })

   if err != nil {
      zap.S().Errorw("添加到购物车失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }

   ctx.JSON(http.StatusOK, gin.H{
      "id": rsp.Id,
   })
}
2.6更新购物车
func Update(ctx *gin.Context) {
   // o/v1/421
   id := ctx.Param("id")
   i, err := strconv.Atoi(id)
   if err != nil {
      ctx.JSON(http.StatusNotFound, gin.H{
         "msg": "url格式出错",
      })
      return
   }

   itemForm := forms.ShopCartItemUpdateForm{}
   if err := ctx.ShouldBindJSON(&itemForm); err != nil {
      api.HandleValidatorError(ctx, err)
      return
   }

   userId, _ := ctx.Get("userId")
   request := proto.CartItemRequest{
      UserId:  int32(userId.(uint)),
      GoodsId: int32(i),
      Nums:    itemForm.Nums,
      Checked: false,
   }
   if itemForm.Checked != nil {
      request.Checked = *itemForm.Checked
   }

   _, err = global.OrderSrvClient.UpdateCartItem(context.Background(), &request)
   if err != nil {
      zap.S().Errorw("更新购物车记录失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   ctx.Status(http.StatusOK)
}
2.7删除购物车
func Delete(ctx *gin.Context) {
   id := ctx.Param("id")
   i, err := strconv.Atoi(id)
   if err != nil {
      ctx.JSON(http.StatusNotFound, gin.H{
         "msg": "url格式出错",
      })
      return
   }

   userId, _ := ctx.Get("userId")
   _, err = global.OrderSrvClient.DeleteCartItem(context.Background(), &proto.CartItemRequest{
      UserId:  int32(userId.(uint)),
      GoodsId: int32(i),
   })
   if err != nil {
      zap.S().Errorw("删除购物车记录失败")
      api.HandleGrpcErrorToHttp(err, ctx)
      return
   }
   ctx.Status(http.StatusOK)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值