http接口框架的搭建
这个http接口框架的搭建参考之前的全量搭建,这里是快速搭建的模式:
直接对已有的http模块举行复制修改,主要修改点在于 proto部门与api、router 部门,剩余的要针对举行修改模块名称。
接口的详细编写
在 api/goods/goods.go 中编写详细的代码:
例如:goods的List接口的开辟:
- func List(ctx *gin.Context) {
- request := &proto.GoodsFilterRequest{}
- priceMin := ctx.DefaultQuery("pmin", "0") // 取出设定的最小价格,默认为 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.Background(), request)
- if err != nil {
- zap.S().Errorw("[List] 查询 【商品列表】 失败")
- HandleGrpcErrorToHttp(err, ctx)
- return
- }
- reMap := map[string]interface{}{
- "total": r.Total,
- "data": r.Data,
- }
- ctx.JSON(http.StatusOK, reMap)
- }
复制代码 但是呢,这种写法存在一定的问题,就是在http接口中未存在对于 后端数据的修正,如许子未便于前端与后端的数据对接,以是我们在 http 端一般可以做一个修改确定:
- 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)
复制代码 注册中央内容抽取
偶然候,我们的项目不是完全基于某一个注册中央,我们不希望将注册中央的逻辑集成在 main文件中,我们希望我们的项目具有快速替换性,这个时候就需要我们将注册中央的内容抽取出来
注册中央服务注册
我们在 util 包下创建一个 register 包,再在 register包下创建 consul包,再在 consul包下创建register.go:
- package consul
- import (
- "fmt"
- "github.com/hashicorp/consul/api"
- "mxshop-api/goods-web/global"
- )
- // 重新配置Register,令其单独拎出来
- // 注册类,这是一个类
- 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) // consul 的地址
- client, err := api.NewClient(cfg)
- if err != nil {
- panic(err)
- }
- // 生成 consul 的注册对象
- // 配置基础信息
- registration := new(api.AgentServiceRegistration)
- registration.Name = name
- registration.ID = id
- registration.Tags = tags
- registration.Port = port
- registration.Address = address
- // 配置检查对象,也就是健康检查机制
- check := &api.AgentServiceCheck{
- HTTP: fmt.Sprintf("http://%s:%d/health", global.ServerConfig.Host, global.ServerConfig.Port), // 发送 GET 请求来进行健康检查,服务的地址
- Timeout: "5s", // 每次健康检查中,多久没有回复视为健康检查失败
- Interval: "5s", // 进行健康检查的频率
- DeregisterCriticalServiceAfter: "10s", // 不健康服务允许存活的时间,当一个服务被检查为不健康时,若 10s 内其没有转为健康,则将其从服务中删除
- }
- // 将检查对象配置进 consul 的注册对象 registration 中
- registration.Check = check
- // 将配置的 consul 注册进去
- err = client.Agent().ServiceRegister(registration)
- client.Agent().ServiceDeregister(name)
- if err != nil {
- panic(err)
- }
- return nil
- }
- func (r *Registry) DeRegister(serviceId string) error {
- return nil
- }
复制代码 在这个程序中,我们要注意的是程序的注册与鸭子范例的实际应用,同时理解golang的计划思想
main.go
- // 动态配置 Consul 相关信息
- 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())
- }
复制代码 注册中央服务注销
优雅的使用go 的队列机制注销服务
- quit := make(chan os.Signal)
- // 如果接收到了 kill 或 ctrl C,则进入quit
- signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
- <-quit
- if err = register_client.DeRegister(serviceId); err != nil {
- zap.S().Panic("注销失败:", err.Error())
- } else {
- zap.S().Panic("注销成功")
- }
复制代码 新建商品接口
在router中添加路由,这个商品需要管理员权限才可以新建
- func InitGoodsRouter(Router *gin.RouterGroup) {
- // 这样就需要 /user/list 才可以进行访问了
- GoodsRouter := Router.Group("goods")
- {
- // 在这里添加拦截器的作用响应位置
- GoodsRouter.GET("", goods.List)
- GoodsRouter.POST("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.New)
- }
- }
复制代码 同时我们在 api/goods.go 中添加新建商品的接口
- func New(ctx *gin.Context) {
- // 由于这里使用了 类似于 Vo 的感觉,所以先构建一个用来绑定获取到的前端数据
- goodsForm := forms.GoodsForm{}
- // 绑定 ShouldBind可以同时绑定form和json,这里就写的明确一点,视为json形式
- if err := ctx.ShouldBindJSON(&goodsForm); err != nil {
- HandleValidatorError(ctx, err)
- return
- }
- // 利用proto 从 grpc服务中获取所需的信息
- 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,
- GoodsDesc: goodsForm.GoodsDesc,
- 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
- }
- // todo 如何设置库存
- ctx.JSON(http.StatusOK, rsp)
- }
复制代码 商品详情接口
在 router 中创建 单独商品详情接口:
- GoodsRouter.GET("/:id", goods.Detail) // 捕捉类似于/goods/123 的内容中的 123
复制代码- func Detail(ctx *gin.Context) {
- // 获取拼接在 链接之后的参数
- id := ctx.Param("id") // 获取 /goods/123
- i, err := strconv.ParseInt(id, 10, 32)
- if err != nil {
- ctx.Status(http.StatusNotFound)
- return
- }
- // 发送 grpc 请求查询相关内容
- r, err := global.GoodsSrvClient.GetGoodsDetail(context.Background(), &proto.GoodInfoRequest{
- Id: int32(i),
- })
- if err != nil {
- api.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,
- "category": 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)
- }
复制代码 删除商品接口
在 router 中创建 删除商品的接口:
- GoodsRouter.DELETE("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Delete)
复制代码- 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.DeleteGoods(context.Background(), &proto.DeleteGoodsInfo{Id: int32(i)})
- if err != nil {
- api.HandleGrpcErrorToHttp(err, ctx)
- return
- }
- ctx.Status(http.StatusOK)
- return
- }
复制代码 获取商品库存接口
库存接口正在开辟中
在router 中新增接口
- GoodsRouter.GET("/:id/stocks", goods.Stocks) // 获取商品库存
复制代码- func Stocks(ctx *gin.Context) {
- id := ctx.Param("id")
- _, err := strconv.ParseInt(id, 10, 32)
- if err != nil {
- ctx.Status(http.StatusNotFound)
- return
- }
- // TODO 商品库存相关信息
- }
复制代码 更新商品状态接口
- GoodsRouter.PATCH("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.UpdateStatus)
复制代码- func UpdateStatus(ctx *gin.Context) {
- id := ctx.Param("id")
- i, err := strconv.ParseInt(id, 10, 32)
- if err != nil {
- ctx.Status(http.StatusNotFound)
- return
- }
- goodsStatusForm := forms.GoodsStatusForm{}
- if err := ctx.ShouldBindJSON(&goodsStatusForm); err != nil {
- api.HandleValidatorError(ctx, err)
- return
- }
- if _, err = global.GoodsSrvClient.UpdateGoods(context.Background(), &proto.CreateGoodsInfo{
- Id: int32(i),
- IsNew: *goodsStatusForm.IsNew,
- IsHot: *goodsStatusForm.IsHot,
- OnSale: *goodsStatusForm.OnSale,
- }); err != nil {
- api.HandleGrpcErrorToHttp(err, ctx)
- return
- }
- ctx.JSON(http.StatusOK, gin.H{
- "msg": "修改成功",
- })
- }
复制代码 更新商品接口
- GoodsRouter.PUT("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Update)
复制代码- func Update(ctx *gin.Context) {
- id := ctx.Param("id")
- i, err := strconv.ParseInt(id, 10, 32)
- if err != nil {
- ctx.Status(http.StatusNotFound)
- return
- }
- goodsForm := forms.GoodsForm{}
- if err = ctx.ShouldBindJSON(&goodsForm); err != nil {
- api.HandleValidatorError(ctx, err)
- return
- }
- 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,
- GoodsDesc: goodsForm.GoodsDesc,
- ShipFree: *goodsForm.ShipFree,
- Images: goodsForm.Images,
- DescImages: goodsForm.DescImages,
- GoodsFrontImage: goodsForm.FrontImage,
- CategoryId: goodsForm.CategoryId,
- BrandId: goodsForm.Brand,
- }); err != nil {
- api.HandleGrpcErrorToHttp(err, ctx)
- return
- }
- ctx.JSON(http.StatusOK, gin.H{
- "msg": "修改成功",
- })
- }
复制代码 分类的相干接口
我们在做分类接口之前,意识到有三个接口是各人都共用的,分别是:removeTopStruct、HandleGrpcErrorToHttp、HandleValidatorError ,以是我们可以把这三个接口都抽到base.go 中:
base.go(在 api 包下创建的新接口)
- package api
- import (
- "github.com/gin-gonic/gin"
- "github.com/go-playground/validator/v10"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
- "mxshop-api/goods-web/global"
- "net/http"
- "strings"
- )
- func HandleGrpcErrorToHttp(err error, c *gin.Context) {
- // 将 grpc 的状态码转换为 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": "参数错误",
- })
- default:
- c.JSON(http.StatusInternalServerError, gin.H{
- "msg": "其他错误:" + e.Message(),
- })
- }
- }
- }
- }
- // 在最后返回错误时调用,用来将返回中的对象名去掉
- func RemoveTopStruct(fields map[string]string) map[string]string {
- rsp := map[string]string{}
- for field, err := range fields {
- rsp[field[strings.Index(field, ".")+1:]] = err // 将map中的 key 中的 . 前面的信息去掉
- }
- return rsp
- }
- 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{
- "msg": RemoveTopStruct(errs.Translate(global.Trans)),
- })
- return
- }
复制代码 创建所需表单
forms/category.go
- 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"`
- }
复制代码 创建接口
全部接口:
- package category
- import (
- "context"
- "encoding/json"
- "github.com/gin-gonic/gin"
- "go.uber.org/zap"
- "google.golang.org/protobuf/types/known/emptypb"
- "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(), &emptypb.Empty{})
- if err != nil {
- api.HandleGrpcErrorToHttp(err, ctx)
- return
- }
- // 创建一个数组
- data := make([]interface{}, 0)
- err = json.Unmarshal([]byte(r.JsonData), &data) // 这里是逻辑写成这样了,所有的分级分类会以JSON的形式存储在r.JsonData 中,这里是对应的反解
- 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["sub_category"] = 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)
- }
- 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)
- }
复制代码 添加 router
router/category.go
- package router
- import (
- "github.com/gin-gonic/gin"
- "mxshop-api/goods-web/api/category"
- )
- func InitCategoryRouter(Router *gin.RouterGroup) {
- CategoryRouter := Router.Group("category")
- {
- CategoryRouter.GET("", category.List)
- CategoryRouter.DELETE("/:id", category.Delete)
- CategoryRouter.GET("/:id", category.Detail)
- CategoryRouter.POST("", category.New)
- CategoryRouter.PUT("/:id", category.Update)
- }
- }
复制代码 在Init 中添加category
initialize/router.go:
- ApiGroup := Router.Group("/g/v1")
- router2.InitGoodsRouter(ApiGroup)
- router2.InitCategoryRouter(ApiGroup) // q添加
- router2.InitHealthCheckRouter(Router.Group(""))
复制代码 轮播图接口
添加轮播图Form
创建文件 forms/banner.go
- 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"`
- }
复制代码 编写API
创建文件 api/banner/banner.go
- package banners
- import (
- "context"
- "github.com/gin-gonic/gin"
- "google.golang.org/protobuf/types/known/emptypb"
- "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(), &emptypb.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),
- Image: bannerForm.Image,
- Url: bannerForm.Url,
- })
- 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, "")
- }
复制代码 编写Router
创建文件 router/banner.go
- 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("banner")
- {
- 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)
- }
- }
复制代码 将Router添加至InitRouter
- ApiGroup := Router.Group("/g/v1")
- router2.InitGoodsRouter(ApiGroup)
- router2.InitCategoryRouter(ApiGroup)
- router2.InitBannerRouter(ApiGroup)
- router2.InitHealthCheckRouter(Router.Group(""))
- return Router
复制代码 品牌接口
添加品牌表单
- 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"`
- }
复制代码 添加品牌API
注意这里的分页是不好的写法,正确的应该在service层中实现,以是这里不要参考,详细可以参考商品那里的接口
- package brands
- import (
- "context"
- "net/http"
- "strconv"
- "github.com/gin-gonic/gin"
- "mxshop-api/goods-web/api"
- "mxshop-api/goods-web/forms"
- "mxshop-api/goods-web/global"
- "mxshop-api/goods-web/proto"
- )
- 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)
- }
- 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, "")
- }
复制代码 添加品牌Router
- package router
- import (
- "github.com/gin-gonic/gin"
- "mxshop-api/goods-web/api/brands"
- )
- // 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) //获取分类的品牌
- }
- }
复制代码 品牌路由导入路由表
- ApiGroup := Router.Group("/g/v1")
- router2.InitGoodsRouter(ApiGroup)
- router2.InitCategoryRouter(ApiGroup)
- router2.InitBannerRouter(ApiGroup)
- router2.InitBrandRouter(ApiGroup)
- router2.InitHealthCheckRouter(Router.Group(""))
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |