五.商品微服务(goods_api)
1.项目初始化
1.1添加配置文件
在goods-web/config-debug.yaml
host: '192.168.0.4'
port: 8848
namespace: 'ba14206d-403f-4377-b7e7-70a3e8fa2bbf'
user: 'nacos'
password: 'nacos'
dataid: 'goods-web.json'
group: 'dev'
1.2配置文件结构体创建
在goods-web/config/config.go添加
package config
type GoodsSrvConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
Name string `mapstructure:"name" json:"name"`
}
type JWTConfig struct {
SigningKey string `mapstructure:"key" json:"key"`
}
type ConsulConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
}
type RedisConfig struct {
Host string `mapstructure:"host" json:"host"`
Port int `mapstructure:"port" json:"port"`
Expire int `mapstructure:"expire" json:"expire"`
}
type ServerConfig struct {
Name string `mapstructure:"name" json:"name"`
Host string `mapstructure:"host" json:"host"`
Tags []string `mapstructure:"tags" json:"tags"`
Port int `mapstructure:"port" json:"port"`
UserSrvInfo GoodsSrvConfig `mapstructure:"goods_srv" json:"goods_srv"`
JWTInfo JWTConfig `mapstructure:"jwt" json:"jwt"`
RedisInfo RedisConfig `mapstructure:"redis" json:"redis"`
ConsulInfo ConsulConfig `mapstructure:"consul" json:"consul"`
}
type NacosConfig struct {
Host string `mapstructure:"host"`
Port uint64 `mapstructure:"port"`
Namespace string `mapstructure:"namespace"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
DataId string `mapstructure:"dataid"`
Group string `mapstructure:"group"`
}
1.3建立全局变量
在goods-web/global/global.go添加
package global
import (
ut "github.com/go-playground/universal-translator"
"mxshop_api/goods-web/config"
"mxshop_api/goods-web/proto"
)
var (
Trans ut.Translator
ServerConfig *config.ServerConfig = &config.ServerConfig{}
GoodsSrvClient proto.GoodsClient
NacosConfig *config.NacosConfig = &config.NacosConfig{}
)
1.4配置日志初始化
在goods-web/initalize目录下添加logger.go
package initalize
import "go.uber.org/zap"
func InitLogger() {
logger, _ := zap.NewDevelopment()
zap.ReplaceGlobals(logger)
}
1.5路由初始化
package initalize
import (
"github.com/gin-gonic/gin"
"mxshop_api/goods-web/middlewares"
"mxshop_api/goods-web/router"
)
func Routers() *gin.Engine {
Router := gin.Default()
//配置跨域
Router.Use(middlewares.Cors())
ApiGroup := Router.Group("/g/v1")
router.InitGoodsRouter(ApiGroup)
return Router
}
1.6服务注册初始化
package initalize
import (
"fmt"
_ "github.com/mbobakov/grpc-consul-resolver"
"go.uber.org/zap"
"google.golang.org/grpc"
"mxshop_api/goods-web/global"
"mxshop_api/goods-web/proto"
)
func InitSrvConn() {
consulInfo := global.ServerConfig.ConsulInfo
goodsConn, err := grpc.Dial(
fmt.Sprintf("consul://%s:%d/%s?wait=14s", consulInfo.Host, consulInfo.Port, global.ServerConfig.UserSrvInfo.Name),
grpc.WithInsecure(),
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
)
if err != nil {
zap.S().Fatal("[InitSrvConn] 连接 【用户服务失败】")
}
goodsSrvClient := proto.NewGoodsClient(goodsConn)
global.GoodsSrvClient = goodsSrvClient
}
1.7服务注册接口开发
goods-web/utils/registry/registry.go
package consul
import (
"fmt"
"github.com/hashicorp/consul/api"
)
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)
client, err := api.NewClient(cfg)
if err != nil {
panic(err)
}
//生成对应的检查对象
check := &api.AgentServiceCheck{
HTTP: fmt.Sprintf("http://%s:%d/health", address, port),
Timeout: "5s",
Interval: "5s",
DeregisterCriticalServiceAfter: "10s",
}
//生成注册对象
registration := new(api.AgentServiceRegistration)
registration.Name = name
registration.ID = id
registration.Port = port
registration.Tags = tags
registration.Address = address
registration.Check = check
err = client.Agent().ServiceRegister(registration)
if err != nil {
panic(err)
}
return nil
}
func (r *Registry)DeRegister(serviceId string) error{
cfg := api.DefaultConfig()
cfg.Address = fmt.Sprintf("%s:%d", r.Host, r.Port)
client, err := api.NewClient(cfg)
if err != nil {
return err
}
err = client.Agent().ServiceDeregister(serviceId)
return err
}
1.8整合main.go
package main
import (
"fmt"
_ "github.com/gin-gonic/gin/binding"
_ "github.com/go-playground/universal-translator"
uuid "github.com/satori/go.uuid"
"github.com/spf13/viper"
"go.uber.org/zap"
"mxshop_api/goods-web/global"
"mxshop_api/goods-web/initalize"
"mxshop_api/goods-web/utils"
"mxshop_api/goods-web/utils/registry/consul"
_ "mxshop_api/goods-web/validator"
"os"
"os/signal"
"syscall"
)
func main() {
//1.初始化logger
initalize.InitLogger()
//2. 初始化配置文件
initalize.InitConfig()
//3.初始化routers
Router := initalize.Routers()
zap.S().Debugf("启动服务器,端口:%d", global.ServerConfig.Port)
//4. 初始化翻译
if err := initalize.InitTrans("zh"); err != nil {
panic(err)
}
//5.初始化SRV的连接
initalize.InitSrvConn()
viper.AutomaticEnv()
debug := viper.GetBool("MXSHOP_DEBUG")
if !debug {
port, err := utils.GetFreePort()
if err == nil {
global.ServerConfig.Port = port
}
}
register_client := consul.NewRegistryClient(global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port)
serviceId := fmt.Sprintf("%s", uuid.NewV4())
err := register_client.Register(global.ServerConfig.Host, global.ServerConfig.Port, global.ServerConfig.Name, global.ServerConfig.Tags, serviceId)
if err != nil {
zap.S().Panic("服务注册失败:", err.Error())
}
zap.S().Debugf("启动服务器, 端口: %d", global.ServerConfig.Port)
go func() {
if err := Router.Run(fmt.Sprintf(":%d", global.ServerConfig.Port)); err != nil {
zap.S().Panic("启动失败:", err.Error())
}
}()
//接收终止信号
quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
if err = register_client.DeRegister(serviceId); err != nil {
zap.S().Info("注销失败:", err.Error())
} else {
zap.S().Info("注销成功:")
}
}
2.goods_api接口
2.1商品的列表页接口
package goods
import (
"context"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"mxshop_api/goods-web/global"
"mxshop_api/goods-web/proto"
"net/http"
"strconv"
"strings"
)
func removeTopStruct(fileds map[string]string) map[string]string {
rsp := map[string]string{}
for field, err := range fileds {
rsp[field[strings.Index(field, ".")+1:]] = err
}
return rsp
}
func HandleGrpcErrorToHttp(err error, c *gin.Context) {
//将grpc的code转换成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": "参数错误",
})
case codes.Unavailable:
c.JSON(http.StatusInternalServerError, gin.H{
"msg": "用户服务不可用",
})
default:
c.JSON(http.StatusInternalServerError, gin.H{
"msg": e.Code(),
})
}
return
}
}
}
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{
"error": removeTopStruct(errs.Translate(global.Trans)),
})
return
}
func List(ctx *gin.Context) {
request := &proto.GoodsFilterRequest{}
priceMin := ctx.DefaultQuery("pmin", "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.WithValue(context.Background(), "ginContext", ctx), request)
if err != nil {
zap.S().Errorw("[List] 查询 【商品列表】失败")
HandleGrpcErrorToHttp(err, ctx)
return
}
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)
}
2.2新建商品
func New(ctx *gin.Context) {
goodsForm := forms.GoodsForm{}
if err := ctx.ShouldBindJSON(&goodsForm); err != nil {
HandleValidatorError(ctx, err)
return
}
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,
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
}
ctx.JSON(http.StatusOK, rsp)
}
2.3商品详情
func Detail(ctx *gin.Context) {
id := ctx.Param("id")
i, err := strconv.ParseInt(id, 10, 32)
if err != nil {
ctx.Status(http.StatusNotFound)
}
r, err := global.GoodsSrvClient.GetGoodsDetail(context.WithValue(context.Background(), "ginContext", ctx), &proto.GoodInfoRequest{
Id: int32(i),
})
if err != nil {
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,
"ctegory": 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)
}
2.4商品删除、更新
func Delete(ctx *gin.Context) {
id := ctx.Param("id")
i, err := strconv.ParseInt(id, 10, 32)
if err != nil {
ctx.Status(http.StatusNotFound)
}
_, err = global.GoodsSrvClient.DeleteGoods(context.Background(), &proto.DeleteGoodsInfo{Id: int32(i)})
if err != nil {
HandleGrpcErrorToHttp(err, ctx)
return
}
ctx.Status(http.StatusOK)
return
}
func Update(ctx *gin.Context) {
goodsForm := forms.GoodsForm{}
if err := ctx.ShouldBindJSON(&goodsForm); err != nil {
HandleValidatorError(ctx, err)
return
}
id := ctx.Param("id")
i, err := strconv.ParseInt(id, 10, 32)
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,
ShipFree: *goodsForm.ShipFree,
Images: goodsForm.Images,
DescImages: goodsForm.DescImages,
GoodsFrontImage: goodsForm.FrontImage,
CategoryId: goodsForm.CategoryId,
BrandId: goodsForm.Brand,
}); err != nil {
HandleGrpcErrorToHttp(err, ctx)
return
}
ctx.JSON(http.StatusOK, gin.H{
"msg": "更新成功",
})
}
2.5商品分类接口
package category
import (
"context"
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/golang/protobuf/ptypes/empty"
"go.uber.org/zap"
"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(), &empty.Empty{})
if err != nil {
api.HandleGrpcErrorToHttp(err, ctx)
return
}
data := make([]interface{}, 0)
err = json.Unmarshal([]byte(r.JsonData), &data)
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["is_tab"] = r.Info.IsTab
reMap["sub_categorys"] = 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)
return
}
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)
}
2.6轮播图接口
package banners
import (
"context"
"github.com/gin-gonic/gin"
"github.com/golang/protobuf/ptypes/empty"
"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(), &empty.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),
Url: bannerForm.Url,
Image: bannerForm.Image,
})
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, "")
}
2.7品牌列表接口
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)
}
2.8品牌分类接口
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, "")
}
2.10接口路由设置
2.10.1商品接口路由
package router
import (
"github.com/gin-gonic/gin"
"mxshop_api/goods-web/api/goods"
"mxshop_api/goods-web/middlewares"
)
func InitGoodsRouter(Router *gin.RouterGroup) {
GoodsRouter := Router.Group("goods")
{
GoodsRouter.GET("", goods.List) //商品列表
GoodsRouter.POST("", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.New) //改接口需要管理员权限
GoodsRouter.GET("/:id", goods.Detail) //获取商品的详情
GoodsRouter.DELETE("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Delete) //删除商品
GoodsRouter.PUT("/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), goods.Update)
}
}
2.10.2商品分类路由
package router
import (
"github.com/gin-gonic/gin"
"mxshop_api/goods-web/api/category"
)
func InitCategoryRouter(Router *gin.RouterGroup) {
CategoryRouter := Router.Group("categorys")
{
CategoryRouter.GET("", category.List) // 商品类别列表页
CategoryRouter.DELETE("/:id", category.Delete) // 删除分类
CategoryRouter.GET("/:id", category.Detail) // 获取分类详情
CategoryRouter.POST("", category.New) //新建分类
CategoryRouter.PUT("/:id", category.Update) //修改分类信息
}
}
2.10.3banner接中路由
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("banners")
{
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) //修改轮播图信息
}
}
2.10.4品牌分类接口路由
package router
import (
"github.com/gin-gonic/gin"
)
// InitBrandRouter 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) //获取分类的品牌
}
}
2.11商品服务表单
2.11.1商品表单
package forms
type GoodsForm struct {
Name string `form:"name" json:"name" binding:"required,min=2,max=100"`
GoodsSn string `form:"goods_sn" json:"goods_sn" binding:"required,min=2,lt=20"`
Stocks int32 `form:"stocks" json:"stocks" binding:"required,min=1"`
CategoryId int32 `form:"category" json:"category" binding:"required"`
MarketPrice float32 `form:"market_price" json:"market_price" binding:"required,min=0"`
ShopPrice float32 `form:"shop_price" json:"shop_price" binding:"required,min=0"`
GoodsBrief string `form:"goods_brief" json:"goods_brief" binding:"required,min=3"`
Images []string `form:"images" json:"images" binding:"required,min=1"`
DescImages []string `form:"desc_images" json:"desc_images" binding:"required,min=1"`
ShipFree *bool `form:"ship_free" json:"ship_free" binding:"required"`
FrontImage string `form:"front_image" json:"front_image" binding:"required,url"`
Brand int32 `form:"brand" json:"brand" binding:"required"`
}
type GoodsStatusForm struct {
IsNew *bool `form:"new" json:"new" binding:"required"`
IsHot *bool `form:"hot" json:"hot" binding:"required"`
OnSale *bool `form:"sale" json:"sale" binding:"required"`
}
2.11.2分类表单
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"`
}
2.11.3Banner表单
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"`
}
2.11.4商品品牌表单
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"`
}
119

被折叠的 条评论
为什么被折叠?



