[golang 微服务] 9.go-micro + gorm实现商品微服务的分页查询

一.引入

上一节讲解 go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务等技术,这一节来看看 go-micro + gorm实现 商品微服务分页查询操作,go-micro微服务中使用GORM和go web框架gin、beego中使用 GORM都是一样的

二.创建goodsinfo服务端,以及启动consul服务发现

  1. 启动consul服务发现

这里以前面goodsinfo微服务为案例,参考前几节步骤,这里就不再讲解了
启动consul服务发现命令 :consul agent -dev
  1. 创建goodsinfo服务端

参考前面案例,启动服务端,测试看看是否启动启动

启动成功,下面对proto/goodsinfo.proto代码进行完善

因为需要进行grom分页查询,故完善 message GoodsModel 中代:增加需要展示的字段( 一般和数据模型中对应,见下面步骤5 ),以及message GetGoodsRequest 代码:增加请求参数 page(页码数),pageSize(页大小),如下:
syntax = "proto3";

package goodsinfo;

option go_package = "./proto;goodsinfo";

//商品相关方法
service Goodsinfo {
    //AddGoods: 定义增加商品的微服务, 这里的写法和gRPC中的写法一致
    rpc AddGoods(AddGoodsRequest) returns (AddGoodsResponse) {}
    //获取分页商品数据
    rpc GetGoods(GetGoodsRequest) returns (GetGoodsResponse) {}
}

//定义GoodsModel结构体,以便增加商品,获取商品数据时使用,该内容可以和models/goods.go保持一致
message GoodsModel{
    string title = 1;
    double price = 2;
    string content = 3;
}

//增加商品请求: 和gRPC中的写法一致
message AddGoodsRequest {
    GoodsModel parame = 1;
}

//增加商品响应:和gRPC中的写法一致
message AddGoodsResponse {
    string message = 1;
    bool success = 2;
}

//获取商品请求
message GetGoodsRequest {
    //请求参数
    int64 page = 1;
    int64 pageSize = 2;
}
//获取商品响应
message GetGoodsResponse {
    repeated GoodsModel GoodsList = 1;
}

然后运行命令:protoc --proto_path=. --micro_out=. --go_out=:. proto/goodsinfo.proto,生成.pb.micro.go,以及pb.go文件

  1. 生成conf/app.ini配置文件

该配置文件里面保存数据库,以及其他云服务相关账号等数据,具体.ini配置见:
[golang gin框架] 9.Gin GORM 中使用事务以及go-ini加载.ini配置文件章节
app_name  = app测试
# 错误级别: DEBUG,INFO,WARNING,ERROR,FATAL
log_level = DEBUG
app_mode  = production

[mysql]
ip       = 127.0.0.1
port     = 3306
user     = root
password = 123456
database = ginshop

[redis]
ip       = 127.0.0.1
port     = 9376
database = 1
  1. 创建models下面文件

要通过gorm连接数据库,就要有goods.go结构体,以及连接数据库核心代码,创建models/goods.go以及models/mysqlCore.go文件,具体可参考 [golang gin框架] 20.Gin 商城项目-商品模块功能

goods.go

package models

//商品表

type Goods struct {
    Id            int
    Title         string  //商品标题
    SubTitle      string  //附属标题
    GoodsSn       string  //商品编号
    CateId        int     //商品分类id: goods_cate.id
    ClickCount    int     //商品点击数量
    GoodsNumber   int     //商品库存
    Price         float64 //价格
    MarketPrice   float64 //商品市场价(原价)
    RelationGoods string  //关联商品id,如: 1, 23,55 ,商品id以逗号隔开
    GoodsAttr     string  //商品更多属性
    GoodsVersion  string  //商品版本
    GoodsImg      string  //图片
    GoodsGift     string  //商品赠品
    GoodsFitting  string  //商品配件
    GoodsColor    string  //颜色
    GoodsKeywords string  //SEO关键字
    GoodsDesc     string  //SEO商品描述
    GoodsContent  string  //商品详情
    IsDelete      int     //是否删除
    IsHot         int     //是否热销
    IsBest        int     //是否精品
    IsNew         int     //是否新品
    GoodsTypeId   int     //商品类型id,关联GoodsType.Id
    Sort          int     //排序
    Status        int     //状态
    AddTime       int     //添加时间
}

func (Goods) TableName() string {
    return "goods"
}

mysqlCore.go

package models

//gorm文档: https://gorm.io/zh_CN/docs/index.html
//连接数据库核心代码

import (
    "fmt"
    "gopkg.in/ini.v1"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "os"
)

//全局使用DB,就需要把DB定义成公有的
var DB *gorm.DB
var err error

//自动初始化数据库
func init() {
    //演示gopkg.in/ini.v1模块的使用
    cfg, err := ini.Load("./conf/app.ini")
    if err != nil {
        fmt.Printf("Fail to read file: %v", err)
        os.Exit(1)
    }
    ip := cfg.Section("mysql").Key("ip").String()
    port := cfg.Section("mysql").Key("port").String()
    user := cfg.Section("mysql").Key("user").String()
    password := cfg.Section("mysql").Key("password").String()
    database := cfg.Section("mysql").Key("database").String()

    // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
    //dsn := "root:123456@tcp(127.0.0.1:3306)/gin?charset=utf8mb4&parseTime=True&loc=Local"
    dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", user, password, ip, port, database)
    DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
        //SkipDefaultTransaction : true, //禁用事物
        QueryFields: true, // 打印sql
    })
    if err != nil {
        fmt.Println(err)
    }
}
然后通过go mod tidy加载需要的包
  1. 完善handler/goods.go代码

完善方法 GetGoods(),在这里面获取请求的分页参数,构建通过GORM获取分页数据的逻辑代码
package handler

import (
    "context"
    "go-micro.dev/v4/logger"
    "goodsinfo/models"
    pb "goodsinfo/proto"
)

//微服务里面操作数据库的建议:一个微服务对应一个数据库,一个数据库里面可能只有1个或者2个表

type Goodsinfo struct{}

//增加商品
func (e *Goodsinfo) AddGoods(ctx context.Context, req *pb.AddGoodsRequest, rsp *pb.AddGoodsResponse) error {
    logger.Infof("request: %v", req)
    //书写返回的逻辑结果
    rsp.Message = "增加成功"
    rsp.Success = true
    return nil
}

//获取商品
func (e *Goodsinfo) GetGoods(ctx context.Context, req *pb.GetGoodsRequest, rsp *pb.GetGoodsResponse) error {
    //获取page和pageSize
    page := req.Page
    pageSize := req.PageSize
    //查询数据库
    goodsList := []models.Goods{}
    models.DB.Offset(int((page - 1) * pageSize)).Limit(int(pageSize)).Find(&goodsList)
    //定义一个临时的切片
    var tempList []*pb.GoodsModel
    for _, v := range goodsList {
        tempList = append(tempList, &pb.GoodsModel{
            Title:    v.Title,
            Price:    v.Price,
            Content:    v.GoodsContent,
        })
    }
    rsp.GoodsList = tempList
    return nil
}
  1. 通过gorm操作数据库

gorm操作数据库请看: [golang gin框架] 6.Gin GORM简介以及安装相关文章,这里就不再讲解
,然后 通过go run main.go命令启动微服务端

三.创建gin项目客户端代码

这里 以Gin框架为例,在Gin项目中编写访问微服务服务端的客户端分页功能,功能接 上一节
  1. 生成proto相关文件

把服务端中的proto文件复制到client/gindemo下,这样就可以使用相关.proto功能了(当然,也可以只复制goods.proto,详细的见 前面的小节
  1. 完善frontend.GoodsController.Index方法

该控制器中的index方法,就是通过访问微服务分页查询的方法
package frontend

import (
    "context"
    "gindemo/models"
    pb "gindemo/proto"
    "github.com/gin-gonic/gin"
    log "go-micro.dev/v4/logger"
    "strconv"
)

type GoodsController struct{}

//获取商品列表
func (con GoodsController) Index(c *gin.Context) {
    //第几页
    page, _ := strconv.Atoi(c.Query("page"))
    if page == 0 {
        page = 1
    }
    //页大小
    pageSize := 5

    // Create client: 这里的服务名称需要和服务端注册的名称一致
    microClient := pb.NewGoodsinfoService("goodsinfo", models.MicroClient)
    // Call service: 创建连接goodsinfo 微服务的连接,并传递参数,
    //该方法最终是请求server端handler中的gooodsinfo.go中的GetGoodsf方法
    rsp, err := microClient.GetGoods(context.Background(), &pb.GetGoodsRequest{
        Page:     int64(page),
        PageSize: int64(pageSize),
    })
    //判断是否获取商品成功: 这里会调用服务端handler/goodsinfo.go中的方法GetGoods()
    if err != nil {
        log.Fatal(err)
    }
    //记录log
    log.Info(rsp)
    //返回
    c.JSON(200, gin.H{
        "result": rsp.GoodsList,
    })
}

//添加商品
func (con GoodsController) Add(c *gin.Context) {
    // Create client
    microClient := pb.NewGoodsinfoService("goodsinfo", models.MicroClient)
    // Call service
    rsp, err := microClient.AddGoods(context.Background(), &pb.AddGoodsRequest{
        Parame: &pb.GoodsModel{
            Title:   "我是一个商品",  //这里的商品数据是模拟数据, 一般项目中是从前端获取
            Price:   12.0,
            Content: "我是一个内容",
        },
    })
    //判断是否增加成功
    if err != nil {
        log.Fatal(err)
    }
    //记录log
    log.Info(rsp)
    //返回
    c.JSON(200, gin.H{
        "message": rsp.Message,
        "success": rsp.Success,
    })
}

然后启动客户端: go run main.go

  1. 通过浏览器访问,看看是否成功

好了,通过使用go-micro + gorm在这里就实现了商品微服务的分页查询

[上一节][golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务

[下一节][golang gin框架] 39.Gin商城项目-微服务实战之微服务架构

猜你喜欢

转载自blog.csdn.net/zhoupenghui168/article/details/131524699
今日推荐