一.引入
上一节讲解 go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务等技术,这一节来看看 go-micro + gorm实现 商品微服务的 分页查询操作,go-micro微服务中使用GORM和go web框架gin、beego中使用 GORM都是一样的
二.创建goodsinfo服务端,以及启动consul服务发现
启动consul服务发现
这里以前面goodsinfo微服务为案例,参考前几节步骤,这里就不再讲解了
启动consul服务发现命令 :consul agent -dev
![](https://img-blog.csdnimg.cn/img_convert/92ecf71fa0e3608c400ec7848287b935.png)
![](https://img-blog.csdnimg.cn/img_convert/bf160745477b4611d4ec666d669bc96c.png)
创建goodsinfo服务端
参考前面案例,启动服务端,测试看看是否启动启动
![](https://img-blog.csdnimg.cn/img_convert/60ba907e2d9f152e0d21996d96f0cc14.png)
启动成功,下面对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文件
生成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
创建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加载需要的包
完善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
}
通过gorm操作数据库
gorm操作数据库请看: [golang gin框架] 6.Gin GORM简介以及安装相关文章,这里就不再讲解
,然后 通过go run main.go命令启动微服务端
![](https://img-blog.csdnimg.cn/img_convert/0e0148adc126fbb597441f5bc90039e9.png)
三.创建gin项目客户端代码
这里 以Gin框架为例,在Gin项目中编写访问微服务服务端的客户端分页功能,功能接 上一节
生成proto相关文件
把服务端中的proto文件复制到client/gindemo下,这样就可以使用相关.proto功能了(当然,也可以只复制goods.proto,详细的见 前面的小节
完善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
通过浏览器访问,看看是否成功
![](https://img-blog.csdnimg.cn/img_convert/6768f13e831af19415cffe60b96924c7.png)
好了,通过使用go-micro + gorm在这里就实现了商品微服务的分页查询
[上一节][golang 微服务] 8.go-micro的负载均衡操作,go Web框(Gin,Beego)调用go-micro微服务