Go-kratos 框架商城微服务实战之商品服务 (七) 商品类型

这篇咱们开始编写商品服务的商品类型了。一个电商的商品设计是比较复杂的,咱们这里不过多的深究表是否合理,是否漏写之类的问题,主要是为了搞明白 kratos 的使用和微服务相关的调用关系。当然我真正的编写时也会尽可能的让此项目的商品设计合理一些。但大量的表设计呀,重复性的 curd 就不会再文章中体现了,具体参看 GitHub 上的源码,当然你觉得不合理的地方,也可以给项目提 PR。

文章写的不清晰的地方可通过 GitHub 源码进行查看, 也感谢您指出不足之处,欢迎大佬指教。

注:竖排 … 代码省略,为了保持文章的篇幅简洁,我会将一些不必要的代码使用竖排的 . 来代替,你在复制本文代码块的时候,切记不要将 . 也一同复制进去。

商品类型

商品类型不同于商品分类,它指的是依据某一类商品的相同规格和属性归纳成的一个类型集合,例如手机类型都有机身颜色、内存大小、屏幕尺寸、铃声、网络制式等共同的规格属性;书籍类型都有出版社、作者、ISBN 号等共同的属性。

编写代码

  • 设计表字段

新增 service/goods/internal/data/good_type.go 文件;编写如下代码

package data

import (
    "context"
    "github.com/go-kratos/kratos/v2/log"
    "goods/internal/biz"
    "gorm.io/gorm"
    "time"
)

// GoodsType 商品类型表
type GoodsType struct {
    ID        int64          `gorm:"primarykey;type:int" json:"id"`
    Name      string         `gorm:"type:varchar(50);not null;comment:商品类型名称" json:"name"`
    TypeCode  string         `gorm:"type:varchar(50);not null;comment:商品类型编码" json:"type_code"`
    NameAlias string         `gorm:"type:varchar(50);not null;comment:商品类型别名" json:"name_alias"`
    IsVirtual bool           `gorm:"comment:是否是虚拟商品显示;default:false" json:"is_virtual"`
    Desc      string         `gorm:"type:varchar(50);not null;comment:商品类型描述" json:"desc"`
    Sort      int32          `gorm:"comment:类型排序;default:99;not null;type:int" json:"sort"`
    CreatedAt time.Time      `gorm:"column:add_time" json:"created_at"`
    UpdatedAt time.Time      `gorm:"column:update_time" json:"updated_at"`
    DeletedAt gorm.DeletedAt `json:"deleted_at"`
}

type goodsTypeRepo struct {
    data *Data
    log  *log.Helper
}

// NewGoodsTypeRepo .
func NewGoodsTypeRepo(data *Data, logger log.Logger) biz.GoodsTypeRepo {
    return &goodsTypeRepo{
        data: data,
        log:  log.NewHelper(logger),
    }
}

注入 GoodsType 修改 service/goods/internal/data/data.go 文件

var ProviderSet = wire.NewSet(
    NewData,
    NewDB, NewRedis,
    NewBrandRepo,
    NewCategoryRepo,
    NewGoodsTypeRepo,
)

⚠️ ⚠️ ⚠️ 注意: 接下来新增或修改的代码, wire 注入的文件中需要修改的代码,都不会再本文中提及了。例如 biz、service 层的修改,自己编写的过程中,千万不要忘记 wire 注入,更不要忘记,执行 make wire 命令,重新生成项目的 wire 文件 ⚠️ ⚠️ ⚠️

  • goods.proto 文件中新加入创建商品类型的方法

...

import "validate/validate.proto";
...

service Goods {
...
 // 商品类型基本信息创建
 rpc CreateGoodsType(GoodsTypeRequest) returns(GoodsTypeResponse);
}

...

message GoodsTypeRequest {
  int64 id = 1;
  string name = 2 [(validate.rules).string.min_len =  3];;
  string typeCode = 3 [(validate.rules).string.min_len =  3];;
  string nameAlias = 4;
  bool isVirtual = 5;
  string desc = 6;
  int32 sort = 7;
}

message GoodsTypeResponse {
  int64 id = 1;
}
  • 实现 rpc 接口

新增 service/goods/internal/service/goods_type.go 文件,内容如下:

package service

import (
    "context"
    v1 "goods/api/goods/v1"
    "goods/internal/domain"
)

func (g *GoodsService) CreateGoodsType(ctx context.Context, r *v1.GoodsTypeRequest) (*v1.GoodsTypeResponse, error) {
    id, err := g.gt.GoosTypeCreate(ctx, &domain.GoodsType{
        Name:      r.Name,
        TypeCode:  r.TypeCode,
        NameAlias: r.NameAlias,
        IsVirtual: r.IsVirtual,
        Desc:      r.Desc,
        Sort:      r.Sort,
    })
    if err != nil {
        return nil, err
    }
    return &v1.GoodsTypeResponse{
        Id: id,
    }, nil
}

你应该也注意到了,代码中接受不了到的值,经过 domain 进行转换了,之前都是直接通过 biz 层下面定义的参数结构体去转换。这里为什么又引入了一层 domain 呢?主要是,之前编写的服务都比较单一化,一个请求方法,只操作一张表,也没有过多的业务逻辑,但接下来商品服务会有更多的,新增商品、商品 SKU、商品属性、商品规格,一系列的业务逻辑处理,考虑到 biz 层尽量做到只编排 repo 和一些少量的业务逻辑处理,其他处理类似于参数校验呀、插入之前判断是否存在呀之类的,都放到了 domain 层去处理。

  • 新增 domain 层

新建 service/goods/internal/domain/goods_type.go 文件,编写内容如下:


package domain

type GoodsType struct {
    ID        int64
    Name      string
    TypeCode  string
    NameAlias string
    IsVirtual bool
    Desc      string
    Sort      int32
}
  • 修改 biz 层

新增 service/goods/internal/biz/goods_type.go 文件,编写内容如下:

package biz

import (
    "context"
    "errors"
    "github.com/go-kratos/kratos/v2/log"
    "goods/internal/domain"
)

type GoodsTypeRepo interface {
    CreateGoodsType(context.Context, *domain.GoodsType) (int64, error)
}

type GoodsTypeUsecase struct {
    repo  GoodsTypeRepo
    bRepo BrandRepo
    log   *log.Helper
}

func NewGoodsTypeUsecase(repo GoodsTypeRepo, tx Transaction, bRepo BrandRepo, logger log.Logger) *GoodsTypeUsecase {
    return &GoodsTypeUsecase{
        repo:  repo,
        tx:    tx,
        bRepo: bRepo,
        log:   log.NewHelper(logger),
    }
}

// GoosTypeCreate 创建商品类型
func (gt *GoodsTypeUsecase) GoosTypeCreate(ctx context.Context, r *domain.GoodsType) (int64, error) {
    id, err := gt.repo.CreateGoodsType(ctx, r)
    if err != nil {
        return err
    }
    return id, nil
}

修改 datagoods_type.go , 加入 createGoodsType 方法

package data

...

// CreateGoodsType 创建基本的商品类型
func (g *goodsTypeRepo) CreateGoodsType(ctx context.Context, req *domain.GoodsType) (int64, error) {
    goodsType := &GoodsType{
        Name:      req.Name,
        TypeCode:  req.TypeCode,
        NameAlias: req.NameAlias,
        IsVirtual: req.IsVirtual,
        Desc:      req.Desc,
        Sort:      req.Sort,
        CreatedAt: time.Time{},
        UpdatedAt: time.Time{},
    }
    result := g.data.db.Save(goodsType)
    return goodsType.ID, result.Error
}
  • 测试提交
    由于之前推荐的使用 goland ide 自带的工具进行 rpc 方法测试,很多同学反应各种问题,连接失败、协议缓冲区等错误,今天咱们推荐另一个免费的开源工具,BloomRPC ,安装比较简单,这里就不演示了,自己进去他的 GitHub 主页就能看到安装步骤,使用起来也超级简单。

打开 BloomRPC 工具,导入你的 proto 文件,它就会把你写好的 rpc 方法全部列在左侧,修改好你的 IP 和 port ,
它甚至把你每个请求的方法所需要的数据都构造好了,你只要稍作修改,就可以发起请求进行测试了。如下图启动服务之后,点击绿色的按钮,得到创建成功的 ID。

结束语

本篇只提供了一个商品类型的创建方法,其他方法没有在文章中体现,单元测试方法也没有编写,重复性的工作这里就不编写了,通过前几篇的文章,相信你可以自己完善剩余的方法。

这篇引入的 domain 层,并未做其他处理,只是接收参数之后通过 domain 下定义的结构体进行转换,你会想说那么跟之前一样,通过 biz 定义的结构体不也一样转换吗?事实确实是如此。这一篇只是带你先了解一下 domain 层,具体 domain 如何利用起来,期待下一篇文章吧。

感谢您的耐心阅读,动动手指点个赞吧。

本作品采用《CC 协议》,转载必须注明作者和本文链接
微信搜索:上帝喜爱笨人
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!