【Go】十八、http 调用服务的编写

打印 上一主题 下一主题

主题 908|帖子 908|积分 2724

http接口框架的搭建

这个http接口框架的搭建参考之前的全量搭建,这里是快速搭建的模式:
直接对已有的http模块举行复制修改,主要修改点在于 proto部门与api、router 部门,剩余的要针对举行修改模块名称。
接口的详细编写

在 api/goods/goods.go 中编写详细的代码:
例如:goods的List接口的开辟:
  1. func List(ctx *gin.Context) {
  2.         request := &proto.GoodsFilterRequest{}
  3.         priceMin := ctx.DefaultQuery("pmin", "0") // 取出设定的最小价格,默认为 0
  4.         priceMinInt, _ := strconv.Atoi(priceMin)
  5.         request.PriceMin = int32(priceMinInt)
  6.         priceMax := ctx.DefaultQuery("pmax", "0")
  7.         priceMaxInt, _ := strconv.Atoi(priceMax)
  8.         request.PriceMax = int32(priceMaxInt)
  9.         isHot := ctx.DefaultQuery("ih", "0")
  10.         if isHot == "1" {
  11.                 request.IsHot = true
  12.         }
  13.         isNew := ctx.DefaultQuery("in", "0")
  14.         if isNew == "1" {
  15.                 request.IsNew = true
  16.         }
  17.         isTab := ctx.DefaultQuery("it", "0")
  18.         if isTab == "1" {
  19.                 request.IsTab = true
  20.         }
  21.         categoryId := ctx.DefaultQuery("c", "0")
  22.         categoryIdInt, _ := strconv.Atoi(categoryId)
  23.         request.TopCategory = int32(categoryIdInt)
  24.         pages := ctx.DefaultQuery("p", "0")
  25.         pagesInt, _ := strconv.Atoi(pages)
  26.         request.Pages = int32(pagesInt)
  27.         perNums := ctx.DefaultQuery("pnum", "0")
  28.         perNumsInt, _ := strconv.Atoi(perNums)
  29.         request.PagePerNums = int32(perNumsInt)
  30.         keywords := ctx.DefaultQuery("q", "")
  31.         request.KeyWords = keywords
  32.         brandId := ctx.DefaultQuery("b", "0")
  33.         brandIdInt, _ := strconv.Atoi(brandId)
  34.         request.Brand = int32(brandIdInt)
  35.         r, err := global.GoodsSrvClient.GoodsList(context.Background(), request)
  36.         if err != nil {
  37.                 zap.S().Errorw("[List] 查询 【商品列表】 失败")
  38.                 HandleGrpcErrorToHttp(err, ctx)
  39.                 return
  40.         }
  41.         reMap := map[string]interface{}{
  42.                 "total": r.Total,
  43.                 "data":  r.Data,
  44.         }
  45.         ctx.JSON(http.StatusOK, reMap)
  46. }
复制代码
但是呢,这种写法存在一定的问题,就是在http接口中未存在对于 后端数据的修正,如许子未便于前端与后端的数据对接,以是我们在 http 端一般可以做一个修改确定:
  1.         reMap := map[string]interface{}{
  2.                 "total": r.Total,
  3.         }
  4.         // 这里一般会进行数据处理
  5.         goodsList := make([]interface{}, 0)
  6.         for _, value := range r.Data {
  7.                 goodsList = append(goodsList, map[string]interface{}{
  8.                         "id":          value.Id,
  9.                         "name":        value.Name,
  10.                         "goods_brief": value.GoodsBrief,
  11.                         "desc":        value.GoodsDesc,
  12.                         "ship_free":   value.ShipFree,
  13.                         "images":      value.Images,
  14.                         "desc_images": value.DescImages,
  15.                         "front_image": value.GoodsFrontImage,
  16.                         "shop_price":  value.ShopPrice,
  17.                         "category": map[string]interface{}{
  18.                                 "id":   value.Category.Id,
  19.                                 "name": value.Category.Name,
  20.                         },
  21.                         "brand": map[string]interface{}{
  22.                                 "id":   value.Brand.Id,
  23.                                 "name": value.Brand.Name,
  24.                                 "logo": value.Brand.Logo,
  25.                         },
  26.                         "is_hot":  value.IsHot,
  27.                         "is_new":  value.IsNew,
  28.                         "on_sale": value.OnSale,
  29.                 })
  30.         }
  31.         reMap["data"] = goodsList
  32.         ctx.JSON(http.StatusOK, reMap)
复制代码
注册中央内容抽取

偶然候,我们的项目不是完全基于某一个注册中央,我们不希望将注册中央的逻辑集成在 main文件中,我们希望我们的项目具有快速替换性,这个时候就需要我们将注册中央的内容抽取出来
注册中央服务注册

我们在 util 包下创建一个 register 包,再在 register包下创建 consul包,再在 consul包下创建register.go:
  1. package consul
  2. import (
  3.         "fmt"
  4.         "github.com/hashicorp/consul/api"
  5.         "mxshop-api/goods-web/global"
  6. )
  7. // 重新配置Register,令其单独拎出来
  8. // 注册类,这是一个类
  9. type Registry struct {
  10.         Host string
  11.         Port int
  12. }
  13. // 这个是类的能力,能干什么
  14. type RegistryClient interface {
  15.         Register(address string, port int, name string, tags []string, id string) error
  16.         DeRegister(serviceId string) error
  17. }
  18. func NewRegistryClient(host string, port int) RegistryClient {
  19.         return &Registry{
  20.                 Host: host,
  21.                 Port: port,
  22.         }
  23. }
  24. func (r *Registry) Register(address string, port int, name string, tags []string, id string) error {
  25.         cfg := api.DefaultConfig()
  26.         cfg.Address = fmt.Sprintf("%s:%d", r.Host, r.Port) // consul 的地址
  27.         client, err := api.NewClient(cfg)
  28.         if err != nil {
  29.                 panic(err)
  30.         }
  31.         // 生成 consul 的注册对象
  32.         // 配置基础信息
  33.         registration := new(api.AgentServiceRegistration)
  34.         registration.Name = name
  35.         registration.ID = id
  36.         registration.Tags = tags
  37.         registration.Port = port
  38.         registration.Address = address
  39.         // 配置检查对象,也就是健康检查机制
  40.         check := &api.AgentServiceCheck{
  41.                 HTTP:                           fmt.Sprintf("http://%s:%d/health", global.ServerConfig.Host, global.ServerConfig.Port), // 发送 GET 请求来进行健康检查,服务的地址
  42.                 Timeout:                        "5s",                                                                                   // 每次健康检查中,多久没有回复视为健康检查失败
  43.                 Interval:                       "5s",                                                                                   // 进行健康检查的频率
  44.                 DeregisterCriticalServiceAfter: "10s",                                                                                  // 不健康服务允许存活的时间,当一个服务被检查为不健康时,若 10s 内其没有转为健康,则将其从服务中删除
  45.         }
  46.         // 将检查对象配置进 consul 的注册对象 registration 中
  47.         registration.Check = check
  48.         // 将配置的 consul 注册进去
  49.         err = client.Agent().ServiceRegister(registration)
  50.         client.Agent().ServiceDeregister(name)
  51.         if err != nil {
  52.                 panic(err)
  53.         }
  54.         return nil
  55. }
  56. func (r *Registry) DeRegister(serviceId string) error {
  57.         return nil
  58. }
复制代码
在这个程序中,我们要注意的是程序的注册与鸭子范例的实际应用,同时理解golang的计划思想
main.go
  1.         // 动态配置 Consul 相关信息
  2.         register_client := consul.NewRegistryClient(global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port)
  3.         serviceId := fmt.Sprintf("%s", uuid.NewV4())
  4.         err := register_client.Register(global.ServerConfig.Host, global.ServerConfig.Port, global.ServerConfig.Name, global.ServerConfig.Tags, serviceId)
  5.         if err != nil {
  6.                 zap.S().Panic("服务注册失败", err.Error())
  7.         }
复制代码
注册中央服务注销

优雅的使用go 的队列机制注销服务
  1.         quit := make(chan os.Signal)
  2.         // 如果接收到了 kill 或 ctrl C,则进入quit
  3.         signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
  4.         <-quit
  5.         if err = register_client.DeRegister(serviceId); err != nil {
  6.                 zap.S().Panic("注销失败:", err.Error())
  7.         } else {
  8.                 zap.S().Panic("注销成功")
  9.         }
复制代码
新建商品接口

在router中添加路由,这个商品需要管理员权限才可以新建
  1. func InitGoodsRouter(Router *gin.RouterGroup) {
  2.         // 这样就需要 /user/list 才可以进行访问了
  3.         GoodsRouter := Router.Group("goods")
  4.         {
  5.                 // 在这里添加拦截器的作用响应位置
  6.                 GoodsRouter.GET("", goods.List)
  7.                 GoodsRouter.POST("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.New)
  8.         }
  9. }
复制代码
同时我们在 api/goods.go 中添加新建商品的接口
  1. func New(ctx *gin.Context) {
  2.         // 由于这里使用了 类似于 Vo 的感觉,所以先构建一个用来绑定获取到的前端数据
  3.         goodsForm := forms.GoodsForm{}
  4.         // 绑定 ShouldBind可以同时绑定form和json,这里就写的明确一点,视为json形式
  5.         if err := ctx.ShouldBindJSON(&goodsForm); err != nil {
  6.                 HandleValidatorError(ctx, err)
  7.                 return
  8.         }
  9.         // 利用proto 从 grpc服务中获取所需的信息
  10.         goodsClient := global.GoodsSrvClient
  11.         rsp, err := goodsClient.CreateGoods(context.Background(), &proto.CreateGoodsInfo{
  12.                 Name:            goodsForm.Name,
  13.                 GoodsSn:         goodsForm.GoodsSn,
  14.                 Stocks:          goodsForm.Stocks,
  15.                 MarketPrice:     goodsForm.MarketPrice,
  16.                 ShopPrice:       goodsForm.ShopPrice,
  17.                 GoodsBrief:      goodsForm.GoodsBrief,
  18.                 GoodsDesc:       goodsForm.GoodsDesc,
  19.                 ShipFree:        *goodsForm.ShipFree,
  20.                 Images:          goodsForm.Images,
  21.                 DescImages:      goodsForm.DescImages,
  22.                 GoodsFrontImage: goodsForm.FrontImage,
  23.                 CategoryId:      goodsForm.CategoryId,
  24.                 BrandId:         goodsForm.Brand,
  25.         })
  26.         if err != nil {
  27.                 HandleGrpcErrorToHttp(err, ctx)
  28.                 return
  29.         }
  30.         // todo 如何设置库存
  31.         ctx.JSON(http.StatusOK, rsp)
  32. }
复制代码
商品详情接口

在 router 中创建 单独商品详情接口:
  1. GoodsRouter.GET("/:id", goods.Detail) // 捕捉类似于/goods/123 的内容中的 123
复制代码
  1. func Detail(ctx *gin.Context) {
  2.         // 获取拼接在 链接之后的参数
  3.         id := ctx.Param("id") // 获取 /goods/123
  4.         i, err := strconv.ParseInt(id, 10, 32)
  5.         if err != nil {
  6.                 ctx.Status(http.StatusNotFound)
  7.                 return
  8.         }
  9.         // 发送 grpc 请求查询相关内容
  10.         r, err := global.GoodsSrvClient.GetGoodsDetail(context.Background(), &proto.GoodInfoRequest{
  11.                 Id: int32(i),
  12.         })
  13.         if err != nil {
  14.                 api.HandleGrpcErrorToHttp(err, ctx)
  15.         }
  16.         rsp := map[string]interface{}{
  17.                 "id":          r.Id,
  18.                 "name":        r.Name,
  19.                 "goods_brief": r.GoodsBrief,
  20.                 "desc":        r.GoodsDesc,
  21.                 "ship_free":   r.ShipFree,
  22.                 "images":      r.Images,
  23.                 "desc_images": r.DescImages,
  24.                 "front_image": r.GoodsFrontImage,
  25.                 "shop_price":  r.ShopPrice,
  26.                 "category": map[string]interface{}{
  27.                         "id":   r.Category.Id,
  28.                         "name": r.Category.Name,
  29.                 },
  30.                 "brand": map[string]interface{}{
  31.                         "id":   r.Brand.Id,
  32.                         "name": r.Brand.Name,
  33.                         "logo": r.Brand.Logo,
  34.                 },
  35.                 "is_hot":  r.IsHot,
  36.                 "is_new":  r.IsNew,
  37.                 "on_sale": r.OnSale,
  38.         }
  39.         ctx.JSON(http.StatusOK, rsp)
  40. }
复制代码
删除商品接口

在 router 中创建 删除商品的接口:
  1. GoodsRouter.DELETE("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Delete)
复制代码
  1. func Delete(ctx *gin.Context) {
  2.         id := ctx.Param("id")
  3.         i, err := strconv.ParseInt(id, 10, 32)
  4.         if err != nil {
  5.                 ctx.Status(http.StatusNotFound)
  6.                 return
  7.         }
  8.         _, err = global.GoodsSrvClient.DeleteGoods(context.Background(), &proto.DeleteGoodsInfo{Id: int32(i)})
  9.         if err != nil {
  10.                 api.HandleGrpcErrorToHttp(err, ctx)
  11.                 return
  12.         }
  13.         ctx.Status(http.StatusOK)
  14.         return
  15. }
复制代码
获取商品库存接口

库存接口正在开辟中
在router 中新增接口
  1. GoodsRouter.GET("/:id/stocks", goods.Stocks) // 获取商品库存
复制代码
  1. func Stocks(ctx *gin.Context) {
  2.         id := ctx.Param("id")
  3.         _, err := strconv.ParseInt(id, 10, 32)
  4.         if err != nil {
  5.                 ctx.Status(http.StatusNotFound)
  6.                 return
  7.         }
  8.         // TODO 商品库存相关信息
  9. }
复制代码
更新商品状态接口

  1. GoodsRouter.PATCH("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.UpdateStatus)
复制代码
  1. func UpdateStatus(ctx *gin.Context) {
  2.         id := ctx.Param("id")
  3.         i, err := strconv.ParseInt(id, 10, 32)
  4.         if err != nil {
  5.                 ctx.Status(http.StatusNotFound)
  6.                 return
  7.         }
  8.         goodsStatusForm := forms.GoodsStatusForm{}
  9.         if err := ctx.ShouldBindJSON(&goodsStatusForm); err != nil {
  10.                 api.HandleValidatorError(ctx, err)
  11.                 return
  12.         }
  13.         if _, err = global.GoodsSrvClient.UpdateGoods(context.Background(), &proto.CreateGoodsInfo{
  14.                 Id:     int32(i),
  15.                 IsNew:  *goodsStatusForm.IsNew,
  16.                 IsHot:  *goodsStatusForm.IsHot,
  17.                 OnSale: *goodsStatusForm.OnSale,
  18.         }); err != nil {
  19.                 api.HandleGrpcErrorToHttp(err, ctx)
  20.                 return
  21.         }
  22.         ctx.JSON(http.StatusOK, gin.H{
  23.                 "msg": "修改成功",
  24.         })
  25. }
复制代码
更新商品接口

  1. GoodsRouter.PUT("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Update)
复制代码
  1. func Update(ctx *gin.Context) {
  2.         id := ctx.Param("id")
  3.         i, err := strconv.ParseInt(id, 10, 32)
  4.         if err != nil {
  5.                 ctx.Status(http.StatusNotFound)
  6.                 return
  7.         }
  8.         goodsForm := forms.GoodsForm{}
  9.         if err = ctx.ShouldBindJSON(&goodsForm); err != nil {
  10.                 api.HandleValidatorError(ctx, err)
  11.                 return
  12.         }
  13.         if _, err = global.GoodsSrvClient.UpdateGoods(context.Background(), &proto.CreateGoodsInfo{
  14.                 Id:              int32(i),
  15.                 Name:            goodsForm.Name,
  16.                 GoodsSn:         goodsForm.GoodsSn,
  17.                 Stocks:          goodsForm.Stocks,
  18.                 MarketPrice:     goodsForm.MarketPrice,
  19.                 ShopPrice:       goodsForm.ShopPrice,
  20.                 GoodsBrief:      goodsForm.GoodsBrief,
  21.                 GoodsDesc:       goodsForm.GoodsDesc,
  22.                 ShipFree:        *goodsForm.ShipFree,
  23.                 Images:          goodsForm.Images,
  24.                 DescImages:      goodsForm.DescImages,
  25.                 GoodsFrontImage: goodsForm.FrontImage,
  26.                 CategoryId:      goodsForm.CategoryId,
  27.                 BrandId:         goodsForm.Brand,
  28.         }); err != nil {
  29.                 api.HandleGrpcErrorToHttp(err, ctx)
  30.                 return
  31.         }
  32.         ctx.JSON(http.StatusOK, gin.H{
  33.                 "msg": "修改成功",
  34.         })
  35. }
复制代码
分类的相干接口

我们在做分类接口之前,意识到有三个接口是各人都共用的,分别是:removeTopStruct、HandleGrpcErrorToHttp、HandleValidatorError ,以是我们可以把这三个接口都抽到base.go 中:
base.go(在 api 包下创建的新接口)
  1. package api
  2. import (
  3.         "github.com/gin-gonic/gin"
  4.         "github.com/go-playground/validator/v10"
  5.         "google.golang.org/grpc/codes"
  6.         "google.golang.org/grpc/status"
  7.         "mxshop-api/goods-web/global"
  8.         "net/http"
  9.         "strings"
  10. )
  11. func HandleGrpcErrorToHttp(err error, c *gin.Context) {
  12.         // 将 grpc 的状态码转换为 http 的状态码
  13.         if err != nil {
  14.                 if e, ok := status.FromError(err); ok {
  15.                         switch e.Code() {
  16.                         case codes.NotFound:
  17.                                 c.JSON(http.StatusNotFound, gin.H{
  18.                                         "msg": e.Message(),
  19.                                 })
  20.                         case codes.Internal:
  21.                                 c.JSON(http.StatusInternalServerError, gin.H{
  22.                                         "msg": "内部错误",
  23.                                 })
  24.                         case codes.InvalidArgument:
  25.                                 c.JSON(http.StatusBadRequest, gin.H{
  26.                                         "msg": "参数错误",
  27.                                 })
  28.                         default:
  29.                                 c.JSON(http.StatusInternalServerError, gin.H{
  30.                                         "msg": "其他错误:" + e.Message(),
  31.                                 })
  32.                         }
  33.                 }
  34.         }
  35. }
  36. // 在最后返回错误时调用,用来将返回中的对象名去掉
  37. func RemoveTopStruct(fields map[string]string) map[string]string {
  38.         rsp := map[string]string{}
  39.         for field, err := range fields {
  40.                 rsp[field[strings.Index(field, ".")+1:]] = err // 将map中的 key 中的 . 前面的信息去掉
  41.         }
  42.         return rsp
  43. }
  44. func HandleValidatorError(c *gin.Context, err error) {
  45.         errs, ok := err.(validator.ValidationErrors)
  46.         if !ok {
  47.                 c.JSON(http.StatusOK, gin.H{
  48.                         "msg": err.Error(),
  49.                 })
  50.         }
  51.         c.JSON(http.StatusBadRequest, gin.H{
  52.                 "msg": RemoveTopStruct(errs.Translate(global.Trans)),
  53.         })
  54.         return
  55. }
复制代码
创建所需表单

forms/category.go
  1. package forms
  2. type CategoryForm struct {
  3.         Name           string `form:"name" json:"name" binding:"required,min=3,max=20"`
  4.         ParentCategory int32  `form:"parent" json:"parent"`
  5.         Level          int32  `form:"level" json:"level" binding:"required,oneof=1 2 3"`
  6.         IsTab          *bool  `form:"is_tab" json:"is_tab" binding:"required"`
  7. }
  8. type UpdateCategoryForm struct {
  9.         Name  string `form:"name" json:"name" binding:"required,min=3,max=20"`
  10.         IsTab *bool  `form:"is_tab" json:"is_tab"`
  11. }
复制代码
创建接口

全部接口:
  1. package category
  2. import (
  3.         "context"
  4.         "encoding/json"
  5.         "github.com/gin-gonic/gin"
  6.         "go.uber.org/zap"
  7.         "google.golang.org/protobuf/types/known/emptypb"
  8.         "mxshop-api/goods-web/api"
  9.         "mxshop-api/goods-web/forms"
  10.         "mxshop-api/goods-web/global"
  11.         "mxshop-api/goods-web/proto"
  12.         "net/http"
  13.         "strconv"
  14. )
  15. func List(ctx *gin.Context) {
  16.         r, err := global.GoodsSrvClient.GetAllCategorysList(context.Background(), &emptypb.Empty{})
  17.         if err != nil {
  18.                 api.HandleGrpcErrorToHttp(err, ctx)
  19.                 return
  20.         }
  21.         // 创建一个数组
  22.         data := make([]interface{}, 0)
  23.         err = json.Unmarshal([]byte(r.JsonData), &data) // 这里是逻辑写成这样了,所有的分级分类会以JSON的形式存储在r.JsonData 中,这里是对应的反解
  24.         if err != nil {
  25.                 zap.S().Errorw("[List] 查询 【分类列表】 失败", err.Error())
  26.         }
  27.         ctx.JSON(http.StatusOK, data)
  28. }
  29. func Detail(ctx *gin.Context) {
  30.         id := ctx.Param("id")
  31.         i, err := strconv.ParseInt(id, 10, 32)
  32.         if err != nil {
  33.                 ctx.Status(http.StatusNotFound)
  34.                 return
  35.         }
  36.         reMap := make(map[string]interface{})
  37.         subCategorys := make([]interface{}, 0)
  38.         if r, err := global.GoodsSrvClient.GetSubCategory(context.Background(), &proto.CategoryListRequest{
  39.                 Id: int32(i),
  40.         }); err != nil {
  41.                 api.HandleGrpcErrorToHttp(err, ctx)
  42.                 return
  43.         } else {
  44.                 for _, value := range r.SubCategorys {
  45.                         subCategorys = append(subCategorys, map[string]interface{}{
  46.                                 "id":              value.Id,
  47.                                 "name":            value.Name,
  48.                                 "level":           value.Level,
  49.                                 "parent_category": value.ParentCategory,
  50.                                 "is_tab":          value.IsTab,
  51.                         })
  52.                 }
  53.                 reMap["id"] = r.Info.Id
  54.                 reMap["name"] = r.Info.Name
  55.                 reMap["level"] = r.Info.Level
  56.                 reMap["parent_category"] = r.Info.ParentCategory
  57.                 reMap["sub_category"] = subCategorys
  58.                 ctx.JSON(http.StatusOK, reMap)
  59.         }
  60.         return
  61. }
  62. func New(ctx *gin.Context) {
  63.         categoryForm := forms.CategoryForm{}
  64.         if err := ctx.ShouldBindJSON(&categoryForm); err != nil {
  65.                 api.HandleValidatorError(ctx, err)
  66.                 return
  67.         }
  68.         rsp, err := global.GoodsSrvClient.CreateCategory(context.Background(), &proto.CategoryInfoRequest{
  69.                 Name:           categoryForm.Name,
  70.                 IsTab:          *categoryForm.IsTab,
  71.                 Level:          categoryForm.Level,
  72.                 ParentCategory: categoryForm.ParentCategory,
  73.         })
  74.         if err != nil {
  75.                 api.HandleGrpcErrorToHttp(err, ctx)
  76.         }
  77.         request := make(map[string]interface{})
  78.         request["id"] = rsp.Id
  79.         request["name"] = rsp.Name
  80.         request["parent"] = rsp.ParentCategory
  81.         request["level"] = rsp.Level
  82.         request["is_tab"] = rsp.IsTab
  83.         ctx.JSON(http.StatusOK, request)
  84. }
  85. func Delete(ctx *gin.Context) {
  86.         id := ctx.Param("id")
  87.         i, err := strconv.ParseInt(id, 10, 32)
  88.         if err != nil {
  89.                 ctx.Status(http.StatusNotFound)
  90.                 return
  91.         }
  92.         //1. 先查询出该分类写的所有子分类
  93.         //2. 将所有的分类全部逻辑删除
  94.         //3. 将该分类下的所有的商品逻辑删除
  95.         _, err = global.GoodsSrvClient.DeleteCategory(context.Background(), &proto.DeleteCategoryRequest{Id: int32(i)})
  96.         if err != nil {
  97.                 api.HandleGrpcErrorToHttp(err, ctx)
  98.                 return
  99.         }
  100.         ctx.Status(http.StatusOK)
  101. }
  102. func Update(ctx *gin.Context) {
  103.         categoryForm := forms.UpdateCategoryForm{}
  104.         if err := ctx.ShouldBindJSON(&categoryForm); err != nil {
  105.                 api.HandleValidatorError(ctx, err)
  106.                 return
  107.         }
  108.         id := ctx.Param("id")
  109.         i, err := strconv.ParseInt(id, 10, 32)
  110.         if err != nil {
  111.                 ctx.Status(http.StatusNotFound)
  112.                 return
  113.         }
  114.         request := &proto.CategoryInfoRequest{
  115.                 Id:   int32(i),
  116.                 Name: categoryForm.Name,
  117.         }
  118.         if categoryForm.IsTab != nil {
  119.                 request.IsTab = *categoryForm.IsTab
  120.         }
  121.         _, err = global.GoodsSrvClient.UpdateCategory(context.Background(), request)
  122.         if err != nil {
  123.                 api.HandleGrpcErrorToHttp(err, ctx)
  124.                 return
  125.         }
  126.         ctx.Status(http.StatusOK)
  127. }
复制代码
添加 router

router/category.go
  1. package router
  2. import (
  3.         "github.com/gin-gonic/gin"
  4.         "mxshop-api/goods-web/api/category"
  5. )
  6. func InitCategoryRouter(Router *gin.RouterGroup) {
  7.         CategoryRouter := Router.Group("category")
  8.         {
  9.                 CategoryRouter.GET("", category.List)
  10.                 CategoryRouter.DELETE("/:id", category.Delete)
  11.                 CategoryRouter.GET("/:id", category.Detail)
  12.                 CategoryRouter.POST("", category.New)
  13.                 CategoryRouter.PUT("/:id", category.Update)
  14.         }
  15. }
复制代码
在Init 中添加category

initialize/router.go:
  1.         ApiGroup := Router.Group("/g/v1")
  2.         router2.InitGoodsRouter(ApiGroup)
  3.         router2.InitCategoryRouter(ApiGroup) // q添加
  4.         router2.InitHealthCheckRouter(Router.Group(""))
复制代码
轮播图接口

添加轮播图Form

创建文件 forms/banner.go
  1. package forms
  2. type BannerForm struct {
  3.         Image string `form:"image" json:"image" binding:"url"`
  4.         Index int `form:"index" json:"index" binding:"required"`
  5.         Url string `form:"url" json:"url" binding:"url"`
  6. }
复制代码
编写API

创建文件 api/banner/banner.go
  1. package banners
  2. import (
  3.         "context"
  4.         "github.com/gin-gonic/gin"
  5.         "google.golang.org/protobuf/types/known/emptypb"
  6.         "mxshop-api/goods-web/api"
  7.         "mxshop-api/goods-web/forms"
  8.         "mxshop-api/goods-web/global"
  9.         "mxshop-api/goods-web/proto"
  10.         "net/http"
  11.         "strconv"
  12. )
  13. func List(ctx *gin.Context) {
  14.         rsp, err := global.GoodsSrvClient.BannerList(context.Background(), &emptypb.Empty{})
  15.         if err != nil {
  16.                 api.HandleGrpcErrorToHttp(err, ctx)
  17.                 return
  18.         }
  19.         result := make([]interface{}, 0)
  20.         for _, value := range rsp.Data {
  21.                 reMap := make(map[string]interface{})
  22.                 reMap["id"] = value.Id
  23.                 reMap["index"] = value.Index
  24.                 reMap["image"] = value.Image
  25.                 reMap["url"] = value.Url
  26.                 result = append(result, reMap)
  27.         }
  28.         ctx.JSON(http.StatusOK, result)
  29. }
  30. func New(ctx *gin.Context) {
  31.         // 接收新增的信息
  32.         bannerForm := forms.BannerForm{}
  33.         if err := ctx.ShouldBindJSON(&bannerForm); err != nil {
  34.                 api.HandleValidatorError(ctx, err)
  35.                 return
  36.         }
  37.         rsp, err := global.GoodsSrvClient.CreateBanner(context.Background(), &proto.BannerRequest{
  38.                 Index: int32(bannerForm.Index),
  39.                 Image: bannerForm.Image,
  40.                 Url:   bannerForm.Url,
  41.         })
  42.         if err != nil {
  43.                 api.HandleGrpcErrorToHttp(err, ctx)
  44.                 return
  45.         }
  46.         response := make(map[string]interface{})
  47.         response["id"] = rsp.Id
  48.         response["index"] = rsp.Index
  49.         response["url"] = rsp.Url
  50.         response["image"] = rsp.Image
  51.         ctx.JSON(http.StatusOK, response)
  52. }
  53. func Update(ctx *gin.Context) {
  54.         bannerForm := forms.BannerForm{}
  55.         if err := ctx.ShouldBindJSON(&bannerForm); err != nil {
  56.                 api.HandleValidatorError(ctx, err)
  57.                 return
  58.         }
  59.         id := ctx.Param("id")
  60.         i, err := strconv.ParseInt(id, 10, 32)
  61.         if err != nil {
  62.                 ctx.Status(http.StatusNotFound)
  63.                 return
  64.         }
  65.         _, err = global.GoodsSrvClient.UpdateBanner(context.Background(), &proto.BannerRequest{
  66.                 Id:    int32(i),
  67.                 Index: int32(bannerForm.Index),
  68.                 Url:   bannerForm.Url,
  69.         })
  70.         if err != nil {
  71.                 api.HandleGrpcErrorToHttp(err, ctx)
  72.                 return
  73.         }
  74.         ctx.Status(http.StatusOK)
  75. }
  76. func Delete(ctx *gin.Context) {
  77.         id := ctx.Param("id")
  78.         i, err := strconv.ParseInt(id, 10, 32)
  79.         if err != nil {
  80.                 ctx.Status(http.StatusNotFound)
  81.                 return
  82.         }
  83.         _, err = global.GoodsSrvClient.DeleteBanner(context.Background(), &proto.BannerRequest{Id: int32(i)})
  84.         if err != nil {
  85.                 api.HandleGrpcErrorToHttp(err, ctx)
  86.                 return
  87.         }
  88.         ctx.JSON(http.StatusOK, "")
  89. }
复制代码
编写Router

创建文件 router/banner.go
  1. package router
  2. import (
  3.         "github.com/gin-gonic/gin"
  4.         "mxshop-api/goods-web/api/banners"
  5.         "mxshop-api/goods-web/middlewares"
  6. )
  7. func InitBannerRouter(Router *gin.RouterGroup) {
  8.         BannerRouter := Router.Group("banner")
  9.         {
  10.                 BannerRouter.GET("", banners.List)
  11.                 BannerRouter.DELETE("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), banners.Delete)
  12.                 BannerRouter.POST("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), banners.New)
  13.                 BannerRouter.PUT("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), banners.Update)
  14.         }
  15. }
复制代码
将Router添加至InitRouter

  1.         ApiGroup := Router.Group("/g/v1")
  2.         router2.InitGoodsRouter(ApiGroup)
  3.         router2.InitCategoryRouter(ApiGroup)
  4.         router2.InitBannerRouter(ApiGroup)
  5.         router2.InitHealthCheckRouter(Router.Group(""))
  6.         return Router
复制代码
品牌接口

添加品牌表单

  1. package forms
  2. type BrandForm struct {
  3.         Name string `form:"name" json:"name" binding:"required,min=3,max=10"`
  4.         Logo string `form:"logo" json:"logo" binding:"url"`
  5. }
  6. type CategoryBrandForm struct {
  7.         CategoryId int `form:"category_id" json:"category_id" binding:"required"`
  8.         BrandId    int `form:"brand_id" json:"brand_id" binding:"required"`
  9. }
复制代码
添加品牌API

注意这里的分页是不好的写法,正确的应该在service层中实现,以是这里不要参考,详细可以参考商品那里的接口
  1. package brands
  2. import (
  3.         "context"
  4.         "net/http"
  5.         "strconv"
  6.         "github.com/gin-gonic/gin"
  7.         "mxshop-api/goods-web/api"
  8.         "mxshop-api/goods-web/forms"
  9.         "mxshop-api/goods-web/global"
  10.         "mxshop-api/goods-web/proto"
  11. )
  12. func BrandList(ctx *gin.Context) {
  13.         pn := ctx.DefaultQuery("pn", "0")
  14.         pnInt, _ := strconv.Atoi(pn)
  15.         pSize := ctx.DefaultQuery("psize", "10")
  16.         pSizeInt, _ := strconv.Atoi(pSize)
  17.         rsp, err := global.GoodsSrvClient.BrandList(context.Background(), &proto.BrandFilterRequest{
  18.                 Pages:       int32(pnInt),
  19.                 PagePerNums: int32(pSizeInt),
  20.         })
  21.         if err != nil {
  22.                 api.HandleGrpcErrorToHttp(err, ctx)
  23.                 return
  24.         }
  25.         result := make([]interface{}, 0)
  26.         reMap := make(map[string]interface{})
  27.         reMap["total"] = rsp.Total
  28.         for _, value := range rsp.Data[pnInt : pnInt*pSizeInt+pSizeInt] {
  29.                 reMap := make(map[string]interface{})
  30.                 reMap["id"] = value.Id
  31.                 reMap["name"] = value.Name
  32.                 reMap["logo"] = value.Logo
  33.                 result = append(result, reMap)
  34.         }
  35.         reMap["data"] = result
  36.         ctx.JSON(http.StatusOK, reMap)
  37. }
  38. func NewBrand(ctx *gin.Context) {
  39.         brandForm := forms.BrandForm{}
  40.         if err := ctx.ShouldBindJSON(&brandForm); err != nil {
  41.                 api.HandleValidatorError(ctx, err)
  42.                 return
  43.         }
  44.         rsp, err := global.GoodsSrvClient.CreateBrand(context.Background(), &proto.BrandRequest{
  45.                 Name: brandForm.Name,
  46.                 Logo: brandForm.Logo,
  47.         })
  48.         if err != nil {
  49.                 api.HandleGrpcErrorToHttp(err, ctx)
  50.                 return
  51.         }
  52.         request := make(map[string]interface{})
  53.         request["id"] = rsp.Id
  54.         request["name"] = rsp.Name
  55.         request["logo"] = rsp.Logo
  56.         ctx.JSON(http.StatusOK, request)
  57. }
  58. func DeleteBrand(ctx *gin.Context) {
  59.         id := ctx.Param("id")
  60.         i, err := strconv.ParseInt(id, 10, 32)
  61.         if err != nil {
  62.                 ctx.Status(http.StatusNotFound)
  63.                 return
  64.         }
  65.         _, err = global.GoodsSrvClient.DeleteBrand(context.Background(), &proto.BrandRequest{Id: int32(i)})
  66.         if err != nil {
  67.                 api.HandleGrpcErrorToHttp(err, ctx)
  68.                 return
  69.         }
  70.         ctx.Status(http.StatusOK)
  71. }
  72. func UpdateBrand(ctx *gin.Context) {
  73.         brandForm := forms.BrandForm{}
  74.         if err := ctx.ShouldBindJSON(&brandForm); err != nil {
  75.                 api.HandleValidatorError(ctx, err)
  76.                 return
  77.         }
  78.         id := ctx.Param("id")
  79.         i, err := strconv.ParseInt(id, 10, 32)
  80.         if err != nil {
  81.                 ctx.Status(http.StatusNotFound)
  82.                 return
  83.         }
  84.         _, err = global.GoodsSrvClient.UpdateBrand(context.Background(), &proto.BrandRequest{
  85.                 Id:   int32(i),
  86.                 Name: brandForm.Name,
  87.                 Logo: brandForm.Logo,
  88.         })
  89.         if err != nil {
  90.                 api.HandleGrpcErrorToHttp(err, ctx)
  91.                 return
  92.         }
  93.         ctx.Status(http.StatusOK)
  94. }
  95. func GetCategoryBrandList(ctx *gin.Context) {
  96.         id := ctx.Param("id")
  97.         i, err := strconv.ParseInt(id, 10, 32)
  98.         if err != nil {
  99.                 ctx.Status(http.StatusNotFound)
  100.                 return
  101.         }
  102.         rsp, err := global.GoodsSrvClient.GetCategoryBrandList(context.Background(), &proto.CategoryInfoRequest{
  103.                 Id: int32(i),
  104.         })
  105.         if err != nil {
  106.                 api.HandleGrpcErrorToHttp(err, ctx)
  107.                 return
  108.         }
  109.         result := make([]interface{}, 0)
  110.         for _, value := range rsp.Data {
  111.                 reMap := make(map[string]interface{})
  112.                 reMap["id"] = value.Id
  113.                 reMap["name"] = value.Name
  114.                 reMap["logo"] = value.Logo
  115.                 result = append(result, reMap)
  116.         }
  117.         ctx.JSON(http.StatusOK, result)
  118. }
  119. func CategoryBrandList(ctx *gin.Context) {
  120.         //所有的list返回的数据结构
  121.         /*
  122.                 {
  123.                         "total": 100,
  124.                         "data":[{},{}]
  125.                 }
  126.         */
  127.         rsp, err := global.GoodsSrvClient.CategoryBrandList(context.Background(), &proto.CategoryBrandFilterRequest{})
  128.         if err != nil {
  129.                 api.HandleGrpcErrorToHttp(err, ctx)
  130.                 return
  131.         }
  132.         reMap := map[string]interface{}{
  133.                 "total": rsp.Total,
  134.         }
  135.         result := make([]interface{}, 0)
  136.         for _, value := range rsp.Data {
  137.                 reMap := make(map[string]interface{})
  138.                 reMap["id"] = value.Id
  139.                 reMap["category"] = map[string]interface{}{
  140.                         "id":   value.Category.Id,
  141.                         "name": value.Category.Name,
  142.                 }
  143.                 reMap["brand"] = map[string]interface{}{
  144.                         "id":   value.Brand.Id,
  145.                         "name": value.Brand.Name,
  146.                         "logo": value.Brand.Logo,
  147.                 }
  148.                 result = append(result, reMap)
  149.         }
  150.         reMap["data"] = result
  151.         ctx.JSON(http.StatusOK, reMap)
  152. }
  153. func NewCategoryBrand(ctx *gin.Context) {
  154.         categoryBrandForm := forms.CategoryBrandForm{}
  155.         if err := ctx.ShouldBindJSON(&categoryBrandForm); err != nil {
  156.                 api.HandleValidatorError(ctx, err)
  157.                 return
  158.         }
  159.         rsp, err := global.GoodsSrvClient.CreateCategoryBrand(context.Background(), &proto.CategoryBrandRequest{
  160.                 CategoryId: int32(categoryBrandForm.CategoryId),
  161.                 BrandId:    int32(categoryBrandForm.BrandId),
  162.         })
  163.         if err != nil {
  164.                 api.HandleGrpcErrorToHttp(err, ctx)
  165.                 return
  166.         }
  167.         response := make(map[string]interface{})
  168.         response["id"] = rsp.Id
  169.         ctx.JSON(http.StatusOK, response)
  170. }
  171. func UpdateCategoryBrand(ctx *gin.Context) {
  172.         categoryBrandForm := forms.CategoryBrandForm{}
  173.         if err := ctx.ShouldBindJSON(&categoryBrandForm); err != nil {
  174.                 api.HandleValidatorError(ctx, err)
  175.                 return
  176.         }
  177.         id := ctx.Param("id")
  178.         i, err := strconv.ParseInt(id, 10, 32)
  179.         if err != nil {
  180.                 ctx.Status(http.StatusNotFound)
  181.                 return
  182.         }
  183.         _, err = global.GoodsSrvClient.UpdateCategoryBrand(context.Background(), &proto.CategoryBrandRequest{
  184.                 Id:         int32(i),
  185.                 CategoryId: int32(categoryBrandForm.CategoryId),
  186.                 BrandId:    int32(categoryBrandForm.BrandId),
  187.         })
  188.         if err != nil {
  189.                 api.HandleGrpcErrorToHttp(err, ctx)
  190.                 return
  191.         }
  192.         ctx.Status(http.StatusOK)
  193. }
  194. func DeleteCategoryBrand(ctx *gin.Context) {
  195.         id := ctx.Param("id")
  196.         i, err := strconv.ParseInt(id, 10, 32)
  197.         if err != nil {
  198.                 ctx.Status(http.StatusNotFound)
  199.                 return
  200.         }
  201.         _, err = global.GoodsSrvClient.DeleteCategoryBrand(context.Background(), &proto.CategoryBrandRequest{Id: int32(i)})
  202.         if err != nil {
  203.                 api.HandleGrpcErrorToHttp(err, ctx)
  204.                 return
  205.         }
  206.         ctx.JSON(http.StatusOK, "")
  207. }
复制代码
添加品牌Router

  1. package router
  2. import (
  3.         "github.com/gin-gonic/gin"
  4.         "mxshop-api/goods-web/api/brands"
  5. )
  6. // 1. 商品的api接口开发完成
  7. // 2. 图片的坑
  8. func InitBrandRouter(Router *gin.RouterGroup) {
  9.         BrandRouter := Router.Group("brands")
  10.         {
  11.                 BrandRouter.GET("", brands.BrandList)          // 品牌列表页
  12.                 BrandRouter.DELETE("/:id", brands.DeleteBrand) // 删除品牌
  13.                 BrandRouter.POST("", brands.NewBrand)          //新建品牌
  14.                 BrandRouter.PUT("/:id", brands.UpdateBrand)    //修改品牌信息
  15.         }
  16.         CategoryBrandRouter := Router.Group("categorybrands")
  17.         {
  18.                 CategoryBrandRouter.GET("", brands.CategoryBrandList)          // 类别品牌列表页
  19.                 CategoryBrandRouter.DELETE("/:id", brands.DeleteCategoryBrand) // 删除类别品牌
  20.                 CategoryBrandRouter.POST("", brands.NewCategoryBrand)          //新建类别品牌
  21.                 CategoryBrandRouter.PUT("/:id", brands.UpdateCategoryBrand)    //修改类别品牌
  22.                 CategoryBrandRouter.GET("/:id", brands.GetCategoryBrandList)   //获取分类的品牌
  23.         }
  24. }
复制代码
品牌路由导入路由表

  1.         ApiGroup := Router.Group("/g/v1")
  2.         router2.InitGoodsRouter(ApiGroup)
  3.         router2.InitCategoryRouter(ApiGroup)
  4.         router2.InitBannerRouter(ApiGroup)
  5.         router2.InitBrandRouter(ApiGroup)
  6.         router2.InitHealthCheckRouter(Router.Group(""))
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

反转基因福娃

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表