我这一辈子啊 發表於 2022-3-26 10:04:00

03. go-zero简介及如何学go-zero

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>一、go-zero简介及如何学go-zero<ul><li>1.go-zero官方文档</li><li>2.go-zero微服务框架入门教程</li><li>3.go-zero最佳实践</li><li>4.学习资料</li></ul></li><li>二、go-zero环境搭建<ul><li>1.GO环境和Gopath的配置</li><li>1.需要安装以下环境和依赖</li><li>2.goctl安装</li><li>3.其它依赖安装</li></ul></li><li>三、go-zero杀手锏goctl详细使用<ul><li>1.官方文档:</li><li>2.开发准备工作</li><li>3.编写API代码</li><li>4.编写RPC代码</li><li>5.编写Model代码</li></ul></li><li>五、API服务之API文档<ul><li>1.生成API文档</li><li>2.atServer关键key描述说明</li></ul></li></ul></div><p></p>
<h2 id="一go-zero简介及如何学go-zero">一、go-zero简介及如何学go-zero</h2>
<h3 id="1go-zero官方文档">1.go-zero官方文档</h3>
<p>http://go-zero.dev/</p>
<h3 id="2go-zero微服务框架入门教程">2.go-zero微服务框架入门教程</h3>
<p>作者:Mikael</p>
<p>https://www.bilibili.com/medialist/play/389552232?from=space&amp;business=space_series&amp;business_id=2122723</p>
<h3 id="3go-zero最佳实践">3.go-zero最佳实践</h3>
<p>go-zero-looklook</p>
<p>项目地址:</p>
<p>https://github.com/Mikaelemmmm/go-zero-looklook</p>
<h3 id="4学习资料">4.学习资料</h3>
<ol>
<li>公众号:微服务器实践</li>
<li>go-zero-expmple: https://github.com/zeromicro/zero-examples</li>
<li>zero-contrib: https://github.com/zeromicro/zero-contrib</li>
<li>微信社区群</li>
<li>go-zero-issue: https://github.com/zeromicro/go-zero/issues</li>
</ol>
<h2 id="二go-zero环境搭建">二、go-zero环境搭建</h2>
<h3 id="1go环境和gopath的配置">1.GO环境和Gopath的配置</h3>
<p>linux配置</p>
<pre><code class="language-sh">export GOROOT="/home/haima/local/go" #go的源码包
export GOPATH=/media/haima/34E401CC64DD0E282/site/go#工作地址路径
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
</code></pre>
<p>更多详细参考以下连接:<br>
https://www.cnblogs.com/haima/p/12057933.html</p>
<h3 id="1需要安装以下环境和依赖">1.需要安装以下环境和依赖</h3>
<ul>
<li>go-zero go mod tidy 会自动下载</li>
<li>goctl</li>
<li>protoc: https://github.com/protocolbuffers/protobuf/releases</li>
<li>protoc-gen-go</li>
<li>protoc-gen-go-grpc</li>
</ul>
<h3 id="2goctl安装">2.goctl安装</h3>
<p><strong>Go 1.16 及以后版本</strong></p>
<pre><code class="language-sh">GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest
查看版本
haima@haima-PC:~/Desktop$ goctl -v
goctl version 1.3.5 linux/amd64
</code></pre>
<h3 id="3其它依赖安装">3.其它依赖安装</h3>
<p>如果<code>goctl</code>安装的版本是&gt;=1.3.3版本的,执行以命令就可以自动安装protoc,protoc-gen-go,protoc-gen-go-grpc三个依赖</p>
<pre><code class="language-sh">haima@haima-PC:/media/haima/34E401CC64DD0E282/site/go/src/haimait/learn/go-zero/zero-demo$ goctl -v
goctl version 1.3.3 linux/amd64
haima@haima-PC:/media/haima/34E401CC64DD0E282/site/go/src/haimait/learn/go-zero/zero-demo$ goctl env check -i -f
: preparing to check env

: looking up "protoc"
: "protoc" is installed

: looking up "protoc-gen-go"
: "protoc-gen-go" is installed

: looking up "protoc-gen-go-grpc"
: "protoc-gen-go-grpc" is installed

: congratulations! your goctl environment is ready!

</code></pre>
<p>查看已经安装的环境</p>
<pre><code class="language-sh">haima@haima-PC:~/Desktop$ protoc --version
libprotoc 3.19.4

haima@haima-PC:~/Desktop$ protoc-gen-go --version
protoc-gen-go v1.28.0

haima@haima-PC:~/Desktop$ protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.2.0

</code></pre>
<p>文件会安装到gopath目录里<br>
<img src="https://img2022.cnblogs.com/blog/1441611/202204/1441611-20220410195715779-1303724747.png" alt="" loading="lazy"></p>
<p>goctl版本小于 1.3.3 参考以下文章安装</p>
<p>https://www.cnblogs.com/haima/p/15859782.html</p>
<h2 id="三go-zero杀手锏goctl详细使用">三、go-zero杀手锏goctl详细使用</h2>
<h3 id="1官方文档">1.官方文档:</h3>
<p>http://go-zero.dev/cn/goctl.html</p>
<p>goctl -help</p>
<h3 id="2开发准备工作">2.开发准备工作</h3>
<ol>
<li>
<p>ide插件市场里安装goctl插件</p>
</li>
<li>
<p>安装<code>protobuf</code>插件</p>
</li>
<li>
<p>配置命令别名</p>
</li>
</ol>
<p>vim ~/.bashrc</p>
<pre><code class="language-sh">alias apigen="goctl api go -api *.api -dir ../--style=goZero"
alias rpcgen="goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../--zrpc_out=../ --style=goZero"
</code></pre>
<p>source ~/.bashrc</p>
<h3 id="3编写api代码">3.编写API代码</h3>
<ol>
<li>新建.api文件</li>
</ol>
<ul>
<li>
<p>手动创建<br>
zero-demo/user-api/api/user.api</p>
</li>
<li>
<p>命令行自动创建<br>
mkdir zero-demo &amp;&amp; cd zero-demo/<br>
goctl api new user</p>
</li>
</ul>
<pre><code class="language-golang">syntax = "v1"

info(
        author: "user-api"
        date:   "2022-03-26"
        desc:   "api语法示例及语法说明"
)

type UserInfoRequest {
        UserId int64 `json:"userId"`
}

type UserInfoResponse {
        UserId   int64`json:"userId"`
        Nickname string `json:"nickname"`
}

service user-api{
        @doc "获取用户信息"
        @handler userInfo
        post /user/info (UserInfoRequest) returns (UserInfoResponse)
}
</code></pre>
<ol start="2">
<li>
<p>进入api目标<br>
cd user-api/api/</p>
</li>
<li>
<p>生成api</p>
</li>
</ol>
<p>方法一:</p>
<p>用原始命令:</p>
<p><code>goctl api go -api *.api -dir ../--style=goZero</code></p>
<p>方法二:</p>
<p>用别名:</p>
<p>apigen</p>
<p>命令说明:</p>
<p>-dir 代码输出目录<br>
--api 指定api源文件<br>
--style 指定生成代码文件的文件名称风格,详情见文件名称命名style说明</p>
<p>会在<code>user-api</code>目录里生成代码</p>
<ol start="4">
<li>目标结构:</li>
</ol>
<pre><code class="language-sh">zero-demo/user-api/api$ cd ..
zero-demo/user-api$ cd ..
zero-demo$ tree
.
├── go.mod
└── user-api
    ├── api
    │   └── user.api
    ├── etc
    │   └── user-api.yaml
    ├── internal
    │   ├── config
    │   │   └── config.go
    │   ├── handler
    │   │   ├── routes.go
    │   │   └── userInfoHandler.go
    │   ├── logic
    │   │   └── userInfoLogic.go
    │   ├── svc
    │   │   └── serviceContext.go
    │   └── types
    │       └── types.go
    └── user.go
</code></pre>
<ol start="5">
<li>下载依赖</li>
</ol>
<p><code>zero-demo$ go mod tidy</code></p>
<ol start="6">
<li>生成Dockerfile文件</li>
</ol>
<p><code>zero-demo/user-api$ goctl docker --go user.go</code></p>
<p>会生成<code>Dockerfile</code>文件</p>
<p><code>zero-demo/user-api/Dockerfile</code></p>
<ol start="7">
<li>生成k8s配置文件<br>
<code>go-zero/zero-demo/user-api$ goctl kube deploy -name user-api-namespace go-zero-looklook -image user-api:v1.0 -o user-api.yml -port 1001 -nodePort 31001</code></li>
</ol>
<p>会生成配置文件</p>
<p>zero-demo/user-api/user-api.yml</p>
<h3 id="4编写rpc代码">4.编写RPC代码</h3>
<ol>
<li>新建user.proto</li>
</ol>
<p>zero-demo/user-rpc/pb/user.proto</p>
<p>写入以下内容</p>
<pre><code class="language-proto">syntax = "proto3";

option go_package = "./pb";

package pb;


//model

message GetUserInfoReq {
int64id = 1;
}
message GetUserInfoResp {
   int64id = 1;
   string nickname = 2;
}


//service
service usercenter {
rpc GetUserInfo(GetUserInfoReq) returns(GetUserInfoResp);
}

</code></pre>
<ol start="2">
<li>生成代码</li>
</ol>
<p>进入目录:<br>
<code>cd zero-demo/user-rpc/pb</code></p>
<p>执行命令:</p>
<p>windows下*号改成具体的文件名,如user.proto</p>
<pre><code class="language-sh">zero-demo/user-rpc/pb$ goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../--zrpc_out=../ --style=goZero
</code></pre>
<p>或者用别名:</p>
<pre><code class="language-sh">zero-demo/user-rpc/pb$ rpcgen
</code></pre>
<p>会在<code>user-rpc</code>目录里生成代码</p>
<ol start="3">
<li>查看生成目录</li>
</ol>
<pre><code class="language-sh">haima@haima-PC:/media/haima/34E401CC64DD0E282/site/go/src/haimait/learn/go-zero/zero-demo$ tree
.
├── go.mod
├── go.sum
└── user-rpc
    ├── etc
    │   └── user.yaml
    ├── internal
    │   ├── config
    │   │   └── config.go
    │   ├── logic
    │   │   └── getUserInfoLogic.go
    │   ├── server
    │   │   └── usercenterServer.go
    │   └── svc
    │       └── serviceContext.go
    ├── pb
    │   ├── user_grpc.pb.go
    │   ├── user.pb.go
    │   └── user.proto
    ├── usercenter
    │   └── usercenter.go
    └── user.go

</code></pre>
<ol start="4">
<li>下载依赖</li>
</ol>
<pre><code class="language-sh">zero-demo$ go mod tidy
</code></pre>
<h3 id="5编写model代码">5.编写Model代码</h3>
<ol>
<li>编写脚本文件<code>genModel.sh</code></li>
</ol>
<p>go-zero/zero-demo/genModel.sh</p>
<pre><code class="language-sh">#!/usr/bin/env bash

# 使用方法: 第一个参数为数据库名 第二个参数为表名
# ./genModel.sh mall user
# ./genModel.sh usercenter user_auth
# 再将./genModel下的文件剪切到对应服务的model目录里面,记得改package


#生成的表名
tables=$2
#表生成的genmodel目录
modeldir=./genModel

# 数据库配置
host=127.0.0.1
port=3306
#dbname=looklook_$1
dbname=$1
username=root
passwd=123456


echo "开始创建库:$dbname 的表:$2"
# -cache=true 带缓存
#goctl model mysql datasource -url="${username}:${passwd}@tcp(${host}:${port})/${dbname}" -table="${tables}"-dir="${modeldir}" -cache=true --style=goZero

# 不带缓存
goctl model mysql datasource -url="${username}:${passwd}@tcp(${host}:${port})/${dbname}" -table="${tables}"-dir="${modeldir}" --style=goZero
</code></pre>
<ol start="2">
<li>生成代码</li>
</ol>
<p><code>./genModel.sh</code></p>
<p>会生成目录<br>
./genModel</p>
<ol start="3">
<li>查看生成代码</li>
</ol>
<pre><code class="language-sh">haima@haima-PC:/media/haima/34E401CC64DD0E282/site/go/src/haimait/learn/go-zero/zero-demo$ tree
.
├── genModel/
│        ├── userModel_gen.go
│        ├── userModel.go
│        └── vars.go
</code></pre>
<blockquote>
<p>重复执行生成代码时,文件 userModel.go 和 vars.go 不会修改,自定义的代码可以写在这两个文件个文件中<br>
如何生成带缓存的model,会根据主键和唯一索引作为key生成生成缓存。</p>
</blockquote>
<p>如下面粟子:<br>
goZeroDemoUserIdKey 和 goZeroDemoUserMobileKey即为缓存的key</p>
<pre><code class="language-golang">func (m *defaultUserModel) Insert(ctx context.Context, data *User) (sql.Result, error) {
        goZeroDemoUserIdKey := fmt.Sprintf("%s%v", cacheGoZeroDemoUserIdPrefix, data.Id)
        goZeroDemoUserMobileKey := fmt.Sprintf("%s%v", cacheGoZeroDemoUserMobilePrefix, data.Mobile)
        ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
                query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet)
                return conn.ExecCtx(ctx, query, data.Id, data.Name, data.Age, data.Gender, data.Mobile, data.Password, data.CreatedAt, data.UpdatedAt, data.DeletedAt)
        }, goZeroDemoUserIdKey, goZeroDemoUserMobileKey)
        return ret, err
}
</code></pre>
<ol start="4">
<li>下载依赖</li>
</ol>
<pre><code class="language-sh">zero-demo$ go mod tidy
</code></pre>
<p>原文笔记:<br>
https://www.cnblogs.com/haima/p/16057786.html</p>
<h2 id="五api服务之api文档">五、API服务之API文档</h2>
<h3 id="1生成api文档">1.生成API文档</h3>
<p>根据user.api文件生成.md文档</p>
<p>执行命令:</p>
<p><code>go-zero-demo\user-api\api&gt; goctl api doc --dir ./</code></p>
<p>会生成 <code>go-zero-demo\user-api/api/user.md</code>        文件</p>
<h3 id="2atserver关键key描述说明">2.atServer关键key描述说明</h3>
<p>修饰service时</p>
<p>路由组(group)和路由前缀(prefix)</p>
<p>参考文档:</p>
<p>http://go-zero.dev/cn/api-grammar.html</p>
<p>语法:</p>
<pre><code class="language-go">// service block
@server(
        group: user
        prefix: api/v1
)
</code></pre>
<p>例子:</p>
<pre><code class="language-go">syntax = "v1"

info(
        author: "user-api"
        date:   "2022-03-26"
        desc:   "api语法示例及语法说明"
)

type UserInfoRequest {
        UserId int64 `json:"userId"`
}

type UserInfoResponse {
        UserId   int64`json:"userId"`
        Nickname string `json:"nickname"`
}
type UserUpdateRequest {
        UserId   int64`json:"userId"`
        Nickname string `json:"nickname"`
}

type UserUpdateResponse {
        Flag bool `json:"flag"`
}

// 看这里 声名 路由组(group)和路由前缀(prefix)
// service block
@server(
        group: user
        prefix: api/v1
)

service user-api{
        @doc "获取用户信息"
        @handler userInfo
        post /user/info (UserInfoRequest) returns (UserInfoResponse)
       
        @doc "修改用户信息"
        @handler upDateUser
        post /user/update (UserUpdateRequest) returns (UserUpdateResponse)
}
</code></pre>
<p>执行生成命令:</p>
<p><code>go-zero-demo\user-api\api&gt; goctl api go -api user.api -dir ../--style=goZero</code></p>
<p>生成的路由:</p>
<pre><code class="language-go">// Code generated by goctl. DO NOT EDIT.
package handler

import (
        "net/http"

        user "go-zero-demo/user-api/internal/handler/user"
        "go-zero-demo/user-api/internal/svc"

        "github.com/zeromicro/go-zero/rest"
)

func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
        server.AddRoutes(
                []rest.Route{
                        {
                                Method:http.MethodPost,
                                Path:    "/user/info",
                                Handler: user.UserInfoHandler(serverCtx),
                        },
                        {
                                Method:http.MethodPost,
                                Path:    "/user/update",
                                Handler: user.UpDateUserHandler(serverCtx),
                        },
                },
                rest.WithPrefix("/api/v1"), #生成的路由前缀
        )
}
</code></pre>
<p>生成文件</p>
<p>go-zero-demo\user-api\internal\handler\user\upDateUserHandler.go</p>
<p>go-zero-demo\user-api\internal\handler\user\userInfoHandler.go</p>
<p>go-zero-demo\user-api\internal\logic\user\upDateUserLogic.go</p>
<p>go-zero-demo\user-api\internal\logic\user\userInfoLogic.go</p>
<pre><code class="language-sh">├── user-api
│   ├── api
│   │   └── user.api
│   ├── Dockerfile
│   ├── etc
│   │   └── user-api.yaml
│   ├── internal
│   │   ├── config
│   │   │   └── config.go
│   │   ├── handler
│   │   │   ├── user
│   │   │   │   ├── upDateUserHandler.go
│   │   │   │   └── userInfoHandler.go
│   │   │   ├── routes.go
│   │   ├── logic
│   │   │   ├── user
│   │   │   │   ├── upDateUserLogic.go
│   │   │   └── └── userInfoLogic.go
│   │   ├── svc
│   │   │   └── serviceContext.go
│   │   └── types
│   │       └── types.go
│   ├── user-api.yml
│   └── user.go
</code></pre>
<p>访问路由:</p>
<pre><code class="language-http">/api/v1/user/info
/api/v1/user/update
</code></pre>


</div>
<div id="MySignature" role="contentinfo">
   
http://www.cnblogs.com/haima/<br><br>
来源:https://www.cnblogs.com/haima/p/16057786.html
頁: [1]
查看完整版本: 03. go-zero简介及如何学go-zero