天天看點

【Go語言實戰】 (15) Gin+gRPC 微服務實作備忘錄 (下) | 備忘錄子產品

文章目錄

  • ​​寫在前面​​
  • ​​源碼位址:​​
  • ​​1. 備忘錄部分​​
  • ​​1.1 proto子產品定義​​
  • ​​1.2 資料庫結構定義​​
  • ​​1.3 接入ETCD​​
  • ​​2. 網關接入​​
  • ​​2.1 服務接入​​
  • ​​2.2 controller​​
  • ​​3. 測試傳回​​

寫在前面

和上篇文章類似,這次我們完成具體功能部分。

源碼位址:

​​https://github.com/CocaineCong/gRPC-todoList​​

1. 備忘錄部分

1.1 proto子產品定義

taskModel.proto

syntax="proto3";
package pb;
option go_package = "/internal/service;service";

message TaskModel {
    // @inject_tag: json:"favorite_id"
    uint32 TaskID=1;
    // @inject_tag: json:"user_id"
    uint32 UserID=2;
    // @inject_tag: json:"status"
    uint32 Status=3;
    // @inject_tag: json:"title"
    string Title=4;
    // @inject_tag: json:"content"
    string Content=5;
    // @inject_tag: json:"start_time"
    uint32 StartTime=6;
    // @inject_tag: json:"end_time"
    uint32 EndTime=7;
}      

taskService.proto

syntax="proto3";
package pb;
import "taskModels.proto";
option go_package = "/internal/service;service";

message TaskRequest{
    uint32 TaskID=1;
    uint32 UserID=2;
    uint32 Status=3;
    string Title=4;
    string Content=5;
    uint32 StartTime=6;
    uint32 EndTime=7;
}

message TasksDetailResponse{
  repeated TaskModel TaskDetail=1;
  uint32 Code=2;
}

message CommonResponse{
    uint32 Code=1;
    string Msg=2;
    string Data=3;
}

service TaskService{
  rpc TaskCreate(TaskRequest) returns(CommonResponse);
  rpc TaskUpdate(TaskRequest) returns(CommonResponse);
  rpc TaskShow(TaskRequest) returns(TasksDetailResponse);
  rpc TaskDelete(TaskRequest) returns(CommonResponse);
}      

擷取所有生成pb.go檔案

protoc -I internal/service/pb internal/service/pb/*.proto --go_out=plugins=grpc:.      
【Go語言實戰】 (15) Gin+gRPC 微服務實作備忘錄 (下) | 備忘錄子產品

1.2 資料庫結構定義

  • 模型定義
type Task struct {
    TaskID    uint   `gorm:"primarykey"` // 收藏夾id
    UserID    uint   `gorm:"index"`      // 使用者id
    Status    int    `gorm:"default:0"`
    Title     string
    Content   string `gorm:"type:longtext"`
    StartTime int64
    EndTime   int64
}      
  • 展示所有的任務
func (*Task) Show (req *service.TaskRequest)(taskList []Task,err error) {
    err = DB.Model(Task{}).Where("user_id=?", req.UserID).Find(&taskList).Error
    if err != nil {
        return taskList, err
    }
    return taskList, nil
}      
  • 建立備忘錄
func (*Task) Create (req *service.TaskRequest) error {
    task := Task{
        UserID: uint(req.UserID),
        Title : req.Title,
        Content : req.Content,
        Status : int(req.Status),
        StartTime : int64(req.StartTime),
        EndTime : int64(req.EndTime),
    }
    if err := DB.Create(&task).Error; err != nil {
        util.LogrusObj.Error("Insert Task Error:" + err.Error())
        return err
    }
    return nil
}      
  • 删除備忘錄
func (*Task) Delete(req *service.TaskRequest) error {
    err := DB.Where("task_id=?", req.TaskID).Delete(Task{}).Error
    return err
}      
  • 更新
func (*Task) Update(req *service.TaskRequest) error {
    t := Task{}
    err := DB.Where("task_id=?", req.TaskID).First(&t).Error
    if err != nil {
        return err
    }
    t.Title = req.Title
    t.Content = req.Content
    t.Status = int(req.Status)
    t.StartTime = int64(req.StartTime)
    t.EndTime = int64(req.EndTime)
    err = DB.Save(&t).Error
    return err
}      

1.3 接入ETCD

  • ETCD服務初始化
etcdAddress := []string{viper.GetString("etcd.address")}
etcdRegister := discovery.NewRegister(etcdAddress, logrus.New())
grpcAddress := viper.GetString("server.grpcAddress")      
  • 節點接入ETCD
taskNode := discovery.Server{
    Name: viper.GetString("server.domain"),
    Addr: grpcAddress,
}
server := grpc.NewServer()      
  • 服務注冊節點
service.RegisterTaskServiceServer(server, handler.NewTaskService())
lis, err := net.Listen("tcp", grpcAddress)
if err != nil {
    panic(err)
}
if _, err := etcdRegister.Register(taskNode, 10); err != nil {
    panic(fmt.Sprintf("start server failed, err: %v", err))
}      

2. 網關接入

2.1 服務接入

  • 擷取ETCD的服務
taskConn, _ := grpc.Dial("127.0.0.1:10002", opts...)
taskService := service.NewTaskServiceClient(taskConn)      
  • 路由注入
authed := v1.Group("/")
authed.Use(middleware.JWT())
{
    // 任務子產品
    authed.GET("task", handler.GetTaskList)
    authed.POST("task", handler.CreateTask)
    authed.PUT("task", handler.UpdateTask)
    authed.DELETE("task", handler.DeleteTask)
}      
func InitMiddleware(service []interface{}) gin.HandlerFunc {
    return func(context *gin.Context) {
        // 将執行個體存在gin.Keys中
        context.Keys = make(map[string]interface{})
        context.Keys["user"] = service[0]
        context.Keys["task"] = service[1]
        context.Next()
    }
}      

2.2 controller

  • 擷取token,擷取是哪個使用者
claim, _ := util.ParseToken(ginCtx.GetHeader("Authorization"))      
  • 擷取task服務
TaskService := ginCtx.Keys["task"].(service.TaskServiceClient)      
  • 調用服務
TaskResp, err := TaskService.TaskShow(context.Background(), &fReq)      
  • 完整代碼
func GetTaskList(ginCtx *gin.Context) {
    var fReq service.TaskRequest
    PanicIfTaskError(ginCtx.Bind(&fReq))
    claim, _ := util.ParseToken(ginCtx.GetHeader("Authorization"))
    fReq.UserID = uint32(claim.UserID)
    TaskService := ginCtx.Keys["task"].(service.TaskServiceClient)
    TaskResp, err := TaskService.TaskShow(context.Background(), &fReq)
    PanicIfTaskError(err)
    r := res.Response{
        Data:   TaskResp,
        Status: uint(TaskResp.Code),
        Msg:    e.GetMsg(uint(TaskResp.Code)),
    }
    ginCtx.JSON(http.StatusOK, r)
}      

3. 測試傳回