ToB企服应用市场:ToB评测及商务社交产业平台
标题:
【Go】十八、http 调用服务的编写
[打印本页]
作者:
反转基因福娃
时间:
9 小时前
标题:
【Go】十八、http 调用服务的编写
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企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4