zoukankan      html  css  js  c++  java
  • go-zero实战

    文档地址
    官方examples
    前提:
    安装 protoc, protoc-gen-go, goctl

    api

    1. clone 项目或者 生成目录, init go mod
    mkdir zeroService && cd zeroService && go mod init zeroService
    
    1. 限制grpc版本, 打开go.mod 加入replace google.golang.org/grpc => google.golang.org/grpc v1.29.1
    module zeroService
    
    go 1.15
    
    replace google.golang.org/grpc => google.golang.org/grpc v1.29.1
    
    1. 创建api和rpc目录
    mkdir rpc && mkdir api
    
    1. 创建api文档, api语法
    cd api
    vim user.api
    
    type HttpResponse {
    	Code int         `json:"code"`
    	Msg  string      `json:"msg"`
    	Data interface{} `json:"data"`
    }
    
    type (
    	RegisterReq {
    		UserName string `form:"username"`
    		Pwd      string `form:"pwd"`
    		NickName string `form:"nickname"`
    		Age      int    `form:"age"`
    	}
    	RegisterRsp {
    		Rid int `json:"rid"`
    	}
    )
    
    type (
    	InfoReq {
    		Rid int `form:"rid"`
    	}
    	InfoRsp {
    		Rid      int    `json:"rid"`
    		UserName string `json:"username"`
    		Pwd      string `json:"pwd"`
    		NickName string `json:"nickname"`
    		Age      int    `json:"age"`
    	}
    )
    
    // 用户相关api
    service user-api{
    	@doc "用户注册"
    	@handler register
    	post /register (RegisterReq) returns (HttpResponse)
    	
    	@doc "获取用户信息"
    	@handler info
    	get /info (InfoReq) returns (HttpResponse)
    }
    
    
    
    1. 生成项目
    goctl api go -api user.api -dir .
    
    
    ./
    ├── api
    │   ├── etc
    │   │   └── user-api.yaml //配置文件
    │   ├── internal
    │   │   ├── config
    │   │   │   └── config.go
    │   │   ├── handler
    │   │   │   ├── infohandler.go
    │   │   │   ├── registerhandler.go
    │   │   │   └── routes.go
    │   │   ├── logic
    │   │   │   ├── infologic.go //业务逻辑
    │   │   │   └── registerlogic.go //业务逻辑
    │   │   ├── svc
    │   │   │   └── servicecontext.go
    │   │   └── types
    │   │       └── types.go
    │   ├── user.api
    │   └── user.go
    ├── go.mod
    └── rpc
    
    1. 修改配置文件
    vim etc/user-api.yaml
    
    Name: user-api
    Host: 0.0.0.0
    Port: 48888
    DataSource: zmwb:realize2012@tcp(127.0.0.1:3306)/zero
    Cache:
      - Host: 127.0.0.1:6379
    Log:
      Model: console
      
    vim internal/config/config.go
    
    //加入下面两个配置声明
    type Config struct {
    	rest.RestConf
    	DataSource string //新加
    	Cache      cache.CacheConf //新加
    }
    
    1. 设计数据库
    CREATE TABLE `userinfo` (
    `id` int(10) NOT NULL AUTO_INCREMENT,
    `username` varchar(255) not null,
    `nickname` varchar(255) not null,
    `age` int(10) not null default 0,
    `pwd` varchar(255) not null,
    `created_at` datetime NOT NULL,
    `updated_at` datetime DEFAULT NULL,
    `deleted_at` datetime DEFAULT NULL,
    key `n_idx` (`username`),
    key `q_idx` (`age`, `nickname`),
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    
    //生成model文件, 目录在api/model里
    goctl model mysql datasource -url="zmwb:realize2012@tcp(127.0.0.1:3306)/zero" -table="*"  -dir="./model"
    
    //修改服务上下文, 注入model
    vim internal/svc/servicecontext.go
    
    
    type ServiceContext struct {
    	Config config.Config
    	Model  model.UserinfoModel //新加
    }
    
    func NewServiceContext(c config.Config) *ServiceContext {
    	return &ServiceContext{
    		Config: c,
    		Model:  model.NewUserinfoModel(sqlx.NewMysql(c.DataSource)), //新加
    	}
    }
    
    
    1. 实现业务逻辑, 两个接口, 用这种方式实现info接口, 另一个接口后面用rpc方式实现
    vim internal/logic/infologic.go
    
    func (l *InfoLogic) Info(req types.InfoReq) (*types.HttpResponse, error) {
    	// 加入实现逻辑
    	userinfo, err := l.svcCtx.Model.FindOne(int64(req.Rid))
    	rsp := types.HttpResponse{}
    	if err != nil {
    		rsp.Code = 2
    		rsp.Msg = "not found"
    		return &rsp, err
    	}
    	rsp.Data = types.InfoRsp{
    		Rid:      int(userinfo.Id),
    		UserName: userinfo.Username,
    		NickName: userinfo.Nickname,
    		Age:      int(userinfo.Age),
    	}
    	return &rsp, nil
    }
    
    
    1. 启动服务
    go run user.go
    
    //进行接口测试
    curl -v http://127.0.0.1:48888/info?rid=1
    

    rpc

    1. 编写pb文件
    cd ../rpc
    vim userService.proto
    
    
    syntax = "proto3";
    
    package userService;
    
    
    message RegisterRequest {
        string username = 1;
        string nickname = 2;
        string pwd = 3;
        int64  age = 4;
    }
    
    message RegisterResponse {
        int64 rid = 1;
    }
    
    service UserService {
        //注册
        rpc Register (RegisterRequest) returns (RegisterResponse);
    
    }
    
    
    1. 根据pb文件生成rpc代码
    goctl rpc proto -src userService.proto  -dir .
    
    //执行后项目结构
    ./
    ├── api
    │   ├── etc
    │   │   └── user-api.yaml
    │   ├── internal
    │   │   ├── config
    │   │   │   └── config.go
    │   │   ├── handler
    │   │   │   ├── infohandler.go
    │   │   │   ├── registerhandler.go
    │   │   │   └── routes.go
    │   │   ├── logic
    │   │   │   ├── infologic.go
    │   │   │   └── registerlogic.go
    │   │   ├── svc
    │   │   │   └── servicecontext.go
    │   │   ├── table.sql
    │   │   └── types
    │   │       └── types.go
    │   ├── model
    │   │   ├── userinfomodel.go
    │   │   └── vars.go
    │   ├── user.api
    │   └── user.go
    ├── go.mod
    ├── go.sum
    └── rpc
        ├── etc
        │   └── userservice.yaml
        ├── internal
        │   ├── config
        │   │   └── config.go
        │   ├── logic
        │   │   └── registerlogic.go
        │   ├── server
        │   │   └── userserviceserver.go
        │   └── svc
        │       └── servicecontext.go
        ├── userService
        │   └── userService.pb.go
        ├── userService.proto
        ├── userservice.go
        └── userserviceclient
            └── userservice.go
    
    1. 修改配置文件
    vim etc/userservice.yaml
    
    Name: userservice.rpc
    ListenOn: 127.0.0.1:48080
    Etcd:
      Hosts:
      - 127.0.0.1:2379 //可以指向自己部署的etcd, 用于服务发现
      Key: userservice.rpc
    DataSource: zmwb:realize2012@tcp(127.0.0.1:3306)/zero
    Cache:
      - Host: 127.0.0.1:6379
    Log:
      Model: console
    
      
    vim internal/config/config.go
    
    //加入下面两个配置声明
    type Config struct {
    	zrpc.RpcServerConf
    	DataSource string          //新加
    	Cache      cache.CacheConf //新加
    }
    
    1. 注入model等
    //修改服务上下文, 注入model
    vim internal/svc/servicecontext.go
    
    
    type ServiceContext struct {
    	Config config.Config
    	Model  model.UserinfoModel //新加
    }
    
    func NewServiceContext(c config.Config) *ServiceContext {
    	return &ServiceContext{
    		Config: c,
    		Model:  model.NewUserinfoModel(sqlx.NewMysql(c.DataSource)), //新加
    	}
    }
    
    
    1. 实现业务逻辑
    vim internal/logic/registerlogic.go
    
    // 注册
    func (l *RegisterLogic) Register(in *userService.RegisterRequest) (*userService.RegisterResponse, error) {
    	user := model.Userinfo{
    		Username: in.Username,
    		Nickname: in.Nickname,
    		Pwd: in.Pwd,
    		Age: in.Age,
    	}
    	res, err := l.svcCtx.Model.Insert(user)
    	if err != nil {
    		return nil, err
    	}
    	rid, err := res.LastInsertId()
    	if err != nil {
    		return nil, err
    	}
    	return &userService.RegisterResponse{Rid: rid}, nil
    }
    
    
    1. api 中注册rpc客户端
    cd ../api
    
    vim etc/user-api.yaml
    //加入以下几行服务发现配置
    Rpc:
      Etcd:
        Hosts:
        - 127.0.0.1:2379
        Key: userservice.rpc
    	
    
    vim internal/config/config.go 
    type Config struct {
    	rest.RestConf
    	DataSource string
    	Cache      cache.CacheConf
    	Rpc        zrpc.RpcClientConf //新加
    }
    
    vim internal/svc/servicecontext.go
    
    type ServiceContext struct {
    	Config         config.Config
    	Model          model.UserinfoModel
    	UserServiceRpc userserviceclient.UserService //新加
    }
    
    func NewServiceContext(c config.Config) *ServiceContext {
    	return &ServiceContext{
    		Config:         c,
    		Model:          model.NewUserinfoModel(sqlx.NewMysql(c.DataSource)),
    		UserServiceRpc: userserviceclient.NewUserService(zrpc.MustNewClient(c.Rpc)), //新加
    	}
    }
    
    
    1. api 中实现register逻辑
    vim internal/logic/registerlogic.go 
    
    func (l *RegisterLogic) Register(req types.RegisterReq) (*types.HttpResponse, error) {
    
    	in := &userService.RegisterRequest{
    		Username: req.UserName,
    		Nickname: req.NickName,
    		Pwd:      req.Pwd,
    		Age:      int64(req.Age),
    	}
    	regRsp, err := l.svcCtx.UserServiceRpc.Register(l.ctx, in)
    	if err != nil {
    		return nil, err
    	}
    	rsp := types.HttpResponse{}
    
    	rsp.Data = types.RegisterRsp{
    		Rid: int(regRsp.Rid),
    	}
    	return &rsp, nil
    }
    
    
    1. 启动api 和 rpc 服务
    go run user.go &
    go run userservice.go &
    
    //进行接口测试
    
    1. docker 部署
    goctl docker -go rpc/userService.go -port 48080
    goctl docker -go api.user.go -port 48888
    //会在两个目录中生成两个dockerfile
    //build 两个镜像
    docker build -t user.service:v1 
    docker build -t user.api:v1 .
    //build 失败, 看Dockerfile发现很多目录写死, 可能是要固定的机器上把目录生成好, 才能build成功
    
    //启动两个容器
    
    

    总结

    1. goctl功能很好用
    2. 部分细节比较固定, 比如, mysql的time.Time有些情况不行, 大部分是ok, goctl docker功能参数太少了, 如果要使用的话可能需要改一改
    3. 看介绍, goctl model生成如果配置了缓存的话, 会自动缓存很多数据, 减轻数据库压力, 这一块算是个特色
  • 相关阅读:
    ASP.NET Aries 高级开发教程:如何写WebAPI接口
    ASP.NET Aries 高级开发教程:行内编辑事件怎么新增数据到后台(番外篇)
    ASP.NET Aries 高级开发教程:表单检测字段是否已存(番外篇)
    Gemini.Workflow 双子工作流正式上线(支持.NET Core)
    Gemini.Workflow 双子工作流入门教程五:业务表单开发
    Gemini.Workflow 双子工作流入门教程四:流程应用
    Gemini.Workflow 双子工作流入门教程三:定义流程:流程节点、迁移条件参数配置
    Gemini.Workflow 双子工作流入门教程二:定义流程:流程节点介绍
    Gemini.Workflow 双子工作流入门教程一:定义流程:流程图属性
    CYQ.Data 支持分布式数据库(主从备)高可用及负载调试
  • 原文地址:https://www.cnblogs.com/leescre/p/14797326.html
Copyright © 2011-2022 走看看