25、订单和购物车-web服务

发布于:2023-01-19 ⋅ 阅读:(692) ⋅ 点赞:(0)

一、快速启动order_web项目

  • 将之前的goods_web项目的文件拷贝到order_web目录下
  • 选择路径 D:\GOProject\mxshop_srvs\mxshop_api\order_web 替换:将 goods_web 全部替换为 order_web
  • 添加 order_web 的 nacos配置
{
  "host": "192.168.78.1",
  "name": "order_web",
  "port": 8083,
  "tags": ["mxshop","imooc","bobby","order","web"],
  "goods_srv": {
    "name": "goods_srv"
  },
  "order_srv": {
    "name": "order_srv"
  },
  "jwt": {
    "key": "VYLDYq3&hGWjWqF$K1ih"
  },
  "consul": {
    "host": "192.168.78.131",
    "port": 8500
  }
}

在这里插入图片描述

  • 修改api、router、proto:具体的查看源码

在这里插入图片描述


二、购物车api接口

1 - 测试中间件

  • order_web/middlewares/test_set_userid.go:这里为了测试效率去掉了jwt的验证,并且直接指定userId = 1 来进行接口测试
package middlewares

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

func SetUserId() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var userId uint = 1
		ctx.Set("userId", userId)
		ctx.Next()
	}
}

  • order_web/router/router_shop_cart.go:添加设置userId的中间件
package router

import (
	"github.com/gin-gonic/gin"
	"web_api/order_web/api/shop_cart"
	"web_api/order_web/middlewares"
)

func InitShopCartRouter(Router *gin.RouterGroup) {
	//ShopCartRouter := Router.Group("shopcarts").Use(middlewares.JWTAuth()) // 测试删除jwt验证
	ShopCartRouter := Router.Group("shopcarts").Use(middlewares.SetUserId())
	{
		ShopCartRouter.GET("", shop_cart.List)          //购物车列表
		ShopCartRouter.DELETE("/:id", shop_cart.Delete) //删除条目
		ShopCartRouter.POST("", shop_cart.New)          //添加商品到购物车
		ShopCartRouter.PATCH("/:id", shop_cart.Update)  //修改条目
	}
}

2 - 订单列表接口

  • order_web/api/shop_cart/api_shop_cart.go
func List(ctx *gin.Context) {
	//获取购物车商品
	userId, _ := ctx.Get("userId")
	fmt.Println(userId)
	rsp, err := global.OrderSrvClient.CartItemList(context.Background(), &proto.UserInfo{
		Id: int32(userId.(uint)),
	})
	if err != nil {
		zap.S().Errorw("[List] 查询 【购物车列表】失败")
		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(), &proto.BatchGoodsIdInfo{
		Id: ids,
	})
	if err != nil {
		zap.S().Errorw("[List] 批量查询【商品列表】失败")
		api.HandleGrpcErrorToHttp(err, ctx)
		return
	}

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

	/*
		{
			"total":12,
			"data":[
				{
					"id":1,
					"goods_id":421,
					"goods_name":421,
					"goods_price":421,
					"goods_image":421,
					"nums":421,
					"checked":421,
				}
			]
		}
	*/
	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)
}
  • YApi测试
    在这里插入图片描述

3 - 添加商品到购物车接口

  • order_web/api/shop_cart/api_shop_cart.go
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(), &proto.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,
	})
}
  • YApi
    在这里插入图片描述
    在这里插入图片描述

4 - 删除购物车记录

  • order_web/api/shop_cart/api_shop_cart.go
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)
}

在这里插入图片描述

5 - 更新购物车

  • order_web/api/shop_cart/api_shop_cart.go
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)
}

在这里插入图片描述


三、订单api接口

1 - 订单列表

  • order_web/middlewares/test_set_userid.go:中间件中添加上claims的验证
package middlewares

import (
	"github.com/gin-gonic/gin"
	"web_api/order_web/models"
)

func SetUserId() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var userId uint = 1
		ctx.Set("claims", &models.CustomClaims{
			AuthorityId: 1,
		})
		ctx.Set("userId", userId)
		ctx.Next()
	}
}

  • order_web/api/order/api_order.go
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
	}

	/*
		{
			"total":100,
			"data":[
				{
					"
				}
			]
		}
	*/
	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 - 订单详情

  • order_web/api/order/api_order.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

	ctx.JSON(http.StatusOK, reMap)
}

在这里插入图片描述

3 - 新建订单

  • order_web/forms/form_order.go:新建表单form
package forms

type CreateOrderForm struct {
	Address string `json:"address" binding:"required"`
	Name    string `json:"name" binding:"required"`
	Mobile  string `json:"mobile" binding:"required,mobile"`
	Post    string `json:"post" binding:"required"`
}

  • order_web/api/order/api_order.go
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.Background(), &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
	}
	// todo 还需要返回支付宝的支付链接,后续再实现
	ctx.JSON(http.StatusOK, gin.H{
		"id": rsp.Id,
	})
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


四、完整源码

  • 完整源码下载mxshop_srvsV8.9.rar
  • 源码说明:(nacos的ip配置自行修改,全局变量DEV_CONFIG设置:1=zsz,2=comp,3=home)
    • goods_srv/model/sql/mxshop_goods.sql:包含了建表语句
    • other_import/api.json:YApi的导入文件
    • other_import/nacos_config_export_user.zip:nacos的user配置集导入文件
    • other_import/nacos_config_export_goods.zip:nacos的goods配置集导入文件
    • other_import/nacos_config_export_inventory.zip:nacos的inventory的配置导入文件
    • other_import/nacos_config_export_orders.zip:nacos的orders的配置导入文件

网站公告

今日签到

点亮在社区的每一天
去签到