前言

书接上回,继续更新GoZero微服务实战系列文章。

上一篇被GoZero作者万总点赞了,更文动力倍增,也建议大家先看巧一篇,欢迎粉丝股东们三连支持一波:Go-zero微服务快速入门和最佳实践(一)

本文将继续使用 Go-zero 提供的工具和组件,从零开始逐步构建一个基本的微服务项目。手把手带你完成:项目初始化+需求分析+表结构设计+api+rpc+goctl+apifox调试+细节处理。带你实现一个完整微服务的开发。

实战前准备

首先需要你在本地安装goctl、protoc、go-zero,goctl安装,按照教程操作即可,非常简单。

下面按顺序和我操作吧,对整体开发流程不清楚的同学务必先看我上一篇文章:GoZero的开发技巧 & 整体开发流程

实战开始

1 | 新建项目(本文使用GoLand)

左上角File-->选择New-->点击Project(如果是第一次使用直接点击New Project即可)

选择新建项目的文件夹以及命名,选择Go的版本(我使用的是Go 1.22.1)

新建文件目录如下

2 | 设计库和表,生成model(本文以文章article表举例,带你实现增删改查基础功能)

数据库表结构设计

快速定位到model目录下执行该命令(右键model-->找到Open In-->点击Terminal)

使用goctl命令生成model(username、passwd、host、port、dbname、tables换成自己的对应的数据)

goctl model mysql datasource -url="${username}:${passwd}@tcp(${host}:${port})/${dbname}" -table="${tables}" -dir="./" -cache=true --style=goZero

一键生成:

3 | 设计api层

在api目录下新建文件:

在article.api中定义文章服务的请求和响应

syntax = "v1"

info (
title: "文章服务"
desc: "文章服务"
version: "v1"
) // 数据库中对应的article表
type Article {
Id int64 `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
}
//---------------------------Req&Resp------------------------------
// 获取文章列表
type (
GetArticleListReq {
} GetArticleListResp {
Articles []Article `json:"Articles"`
}
)
// 创建文章
type (
CreateArticleReq {
Title string `json:"title"`
Content string `json:"content"`
}
CreateArticleResp {
}
)
// 删除文章
type (
DeleteArticleReq {
Id int64 `json:"id"`
}
DeleteArticleResp {
}
)
// 修改文章
type (
UpdateArticleReq {
Id int64 `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
}
UpdateArticleResp {
}
)

在main.api中定义文章服务的API

syntax = "v1"

info (
title: "文章服务"
desc: "文章服务"
version: "v1"
) // 导入article.api,直接引用
import (
"article/article.api"
) // 服务的相关配置,这里分别是前缀和分组
@server (
prefix: article/v1
group: article
)
service article {
@doc "获得文章列表"
@handler getArticles
post /getArticles (GetArticleListReq) returns (GetArticleListResp) @doc "创建文章"
@handler createArticle
post /createArticle (CreateArticleReq) returns (CreateArticleResp) @doc "删除文章"
@handler deleteArticle
post /deleteArticle (DeleteArticleReq) returns (DeleteArticleResp) @doc "修改文章"
@handler updateArticle
post /updateArticle (UpdateArticleReq) returns (UpdateArticleResp)
}

至此api层已经定义好了,接下来使用goctl代码自动生成

和刚刚一样,右键main.api然后打开Terminal,输入代码

goctl api go -api main.api -dir ../ --style=goZero

会自动生成etc、internal文件夹以及article.go文件(我习惯把article.go文件改成main.go文件:如果我们后续有多个微服务,执行goctl命令的时候就不用频繁切换文件名称了)

在这里只需要在意几个配置文件(article.yaml, config.go, serviceContext.go)以及需要编写代码的logic目录即可, 暂时先不管, 将rpc层也生成好后一起配置。

4 | 编写rpc层

在rpc下新建pb文件夹, 在pb文件夹里新建article.proto文件

在编写proto文件的时候, 如果是第一次编写的话, 可以使用sql2pb工具自动生成, 一旦我们的proto文件有自定义的修改之后, 就不建议使用这个工具了, 使用方法如下

  1. 安装最新的sql2pb
go install github.com/Mikaelemmmm/sql2pb@latest
  1. 命令示例:
sql2pb -go_package ./pb -host localhost -package pb -password lps123456 -port 3306 -schema zero-demo -service_name article -user root > article.proto

这个命令可以直接将我的zero-demo数据库下所有的表内容都生成到article.proto文件中

这是自动生成的article.proto文件, ** 你也可以根据自己的需求往里面增加内容**

syntax = "proto3";

option go_package ="./pb";

package pb;

// ------------------------------------
// Messages
// ------------------------------------ //--------------------------------article--------------------------------
message Article {
int64 id = 1; //id
string title = 2; //title
string content = 3; //content
} message AddArticleReq {
string title = 1; //title
string content = 2; //content
} message AddArticleResp {
} message UpdateArticleReq {
int64 id = 1; //id
string title = 2; //title
string content = 3; //content
} message UpdateArticleResp {
} message DelArticleReq {
int64 id = 1; //id
} message DelArticleResp {
} message GetArticleByIdReq {
int64 id = 1; //id
} message GetArticleByIdResp {
Article article = 1; //article
} message SearchArticleReq {
int64 page = 1; //page
int64 limit = 2; //limit
int64 id = 3; //id
string title = 4; //title
string content = 5; //content
} message SearchArticleResp {
repeated Article article = 1; //article
} // ------------------------------------
// Rpc Func
// ------------------------------------ service article{ //-----------------------article-----------------------
rpc AddArticle(AddArticleReq) returns (AddArticleResp);
rpc UpdateArticle(UpdateArticleReq) returns (UpdateArticleResp);
rpc DelArticle(DelArticleReq) returns (DelArticleResp);
rpc GetArticleById(GetArticleByIdReq) returns (GetArticleByIdResp);
rpc SearchArticle(SearchArticleReq) returns (SearchArticleResp); }

下一步就是通过proto文件自动生成rpc层其他代码

和之前说的一样,右键article.proto然后打开Terminal,输入代码:

goctl rpc protoc article.proto --go_out=../ --go-grpc_out=../ --zrpc_out=../ --style=goZero

注意: 如果你是Windows电脑,运行后可能会出现一个invalid UTF-8 encoding的问题, 将左下角的文件格式改为UTF-8即可。(更建议你按照git bash,从根本上解决这个问题。)

运行成功后又会生成好几个文件

这里我同样将article.go改成了main.go

5 | 配置api层和rpc层

OK,现在没有能自动生成的代码了, 需要自己手动敲代码实现业务逻辑了。

配置api层

打开api/etc/article.yaml文件, 写入以下代码:

Name: article-api #服务名称
Host: 127.0.0.1 #监听地址
Port: 1001 #监听端口
Mode: dev #运行模式
# 配置MySQL Redis
DB:
DataSource: root:lps123456@tcp(127.0.0.1:3306)/zero-demo?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
Cache:
- Host: 127.0.0.1:6379
Pass:
# 配置rpc客户端, 后面需要调用rpc中的方法
ArticleRpcConf:
Endpoints:
- 127.0.0.1:2001
NonBlock: true

接下来是api/internal/config/config.go文件

package config

import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/zrpc"
)
type Config struct {
rest.RestConf
DB struct {
DataSource string
}
Cache cache.CacheConf
ArticleRpcConf zrpc.RpcClientConf
}

最后是api/internal/svc/serviceContext.go文件

package svc

import (
"GoZeroDemo/app/article/cmd/api/internal/config"
"GoZeroDemo/app/article/cmd/rpc/article"
"github.com/zeromicro/go-zero/zrpc"
) type ServiceContext struct {
Config config.Config
ArticleRpc article.ArticleZrpcClient
} func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
ArticleRpc: article.NewArticleZrpcClient(zrpc.MustNewClient(c.ArticleRpcConf)),
}
}

api层的服务就配置好了

配置rpc层

打开rpc/etc/article.yaml文件, 写入以下代码:

Name: article-rpc #服务名称
ListenOn: 127.0.0.1:2001 #监听地址
Mode: dev #运行模式
# 配置Redis
Redis:
Host: 127.0.0.1:6379
Type: node
Pass:
Key: article-rpc
# 配置MySQL
DB:
DataSource: root:lps123456@tcp(127.0.0.1:3306)/zero-demo?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
Cache:
- Host: 127.0.0.1:6379
Pass:

接下来是rpc/internal/config/config.go文件

package config

import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/zrpc"
) type Config struct {
zrpc.RpcServerConf
DB struct {
DataSource string
}
Cache cache.CacheConf
}

最后是rpc/internal/svc/serviceContext.go文件

package svc

import (
"GoZeroDemo/app/article/cmd/rpc/internal/config"
"GoZeroDemo/app/article/model"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
) type ServiceContext struct {
Config config.Config
RedisClient *redis.Redis
ArticleModel model.ArticleModel
} func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
ArticleModel: model.NewArticleModel(sqlx.NewMysql(c.DB.DataSource), c.Cache),
}
}

至此都配置好了, 接下来就是编写业务逻辑代码

6 | 编写api层和rpc层下logic代码

这里我就拿增加文章做示例

首先编写api下的logic中的createArticleLogic.go文件:

package article

import (
"GoZeroDemo/app/article/cmd/rpc/article"
"context" "GoZeroDemo/app/article/cmd/api/internal/svc"
"GoZeroDemo/app/article/cmd/api/internal/types" "github.com/zeromicro/go-zero/core/logx"
) type CreateArticleLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
} func NewCreateArticleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateArticleLogic {
return &CreateArticleLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
} func (l *CreateArticleLogic) CreateArticle(req *types.CreateArticleReq) (resp *types.CreateArticleResp, err error) {
// 这里就是调用rpc下的AddArticle方法
_, err = l.svcCtx.ArticleRpc.AddArticle(l.ctx, &article.AddArticleReq{
Title: req.Title,
Content: req.Content,
})
if err != nil {
return nil, err
}
return return
}

接下来完成rpc中的AddArticle方法, 编写addArticleLogic.go文件:

package logic

import (
"GoZeroDemo/app/article/cmd/rpc/internal/svc"
"GoZeroDemo/app/article/cmd/rpc/pb"
"GoZeroDemo/app/article/model"
"context" "github.com/zeromicro/go-zero/core/logx"
) type AddArticleLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
} func NewAddArticleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddArticleLogic {
return &AddArticleLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
} // -----------------------article-----------------------
func (l *AddArticleLogic) AddArticle(in *pb.AddArticleReq) (*pb.AddArticleResp, error) {
article := new(model.Article)
article.Title = in.Title
article.Content = in.Content
// 调用model层的方法
_, err := l.svcCtx.ArticleModel.Insert(l.ctx, article)
if err != nil {
return nil, err
}
return &pb.AddArticleResp{}, nil
}

接下来就可以进行测试了

7 | 自动生成接口文档并测试(使用Apifox)

  1. 使用swagg生成json文件

    下载goctl-swagger, 确认安装是否成功:
go get -u github.com/zeromicro/goctl-swagger
goctl-swagger -v

在main.api下打开Terminal, 输入以下代码:

goctl api plugin -plugin goctl-swagger="swagger -filename main.json" -api main.api -dir .

不出意外就会生成一个main.json文件

  1. 将json文件导入到Apifox中

    打开Apifox, 新建接口项目, 点击这里导入json文件

将json文件拖进去即可

完成之后-->点击这里-->进入选择开发环境-->进行一个端口的配置

这里的地址就是我对应的api服务的地址(yaml文件中配置)

3. 启动程序后, 进行测试

还记得刚刚我改名的main.go文件吗,一个在api层,一个在rpc层,现在分别运行它们

将它们同时在控制台Terminal打开,分别运行命令go run main.go

可以看到它们监听了两个端口,一个1001一个2001

接下来就可以在Apifox中进行测试了

从左至右分别点击这三个地方(数据可以自动生成也可以自己写)

然后发现返回null和200(因为我没有定义规范的返回给前端的字段,所以返回null代表正常)

4. 查询数据库,确保数据生成

最后查看数据库中是否出现了这条记录

可以看到记录新增成功, 圆满完成!

总结

这篇文章分享了如何使用gozero开发文章服务的增加功能,强烈建议你跟着我的步骤操练一遍,也可以尝试用相同的思路实现删除、查询功能。

我将继续更新Go-Zero系列文章,如果你对Go语言或者微服务感兴趣,欢迎关注我的公众号,也欢迎直接私信我。

Go-Zero从0到1实现微服务项目开发(二)的更多相关文章

  1. 微服务项目开发学成在线_day02 CMS前端开发

    1 Vue.js与Webpack研究 开发版的浏览器:https://www.google.cn/intl/zh-CN/chrome/dev/ 前端的开发框架:微服务项目开发学成在线_Vue.js与W ...

  2. 微服务项目开发学成在线_day01_CMS服务端开发

    05-CMS需求分析-什么是CMS 什么是CMS?CMS (Content Management System)即内容管理系统,不同的项目对CMS的定位不同.CMS有哪些类型? 每个公司对每个项目的C ...

  3. 微服务项目开发学成在线_day03 CMS页面管理开发

    springboot引入mangodb依赖坐标:在spring-boot集成条件下,使用mongodb的DAO层开发. swagger查看接口文档,请求地址:http://localhost:3100 ...

  4. 微服务项目开发学成在线_Vue.js与Webpack

    Vue.js 1.Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.自底向上逐层应用:作为渐进式框架要实现的目标就是方便项目增量开发. 渐进式框架:Progress ...

  5. springboot的maven多模块项目架构微服务搭建——依赖方式的多模块演化为微服务项目

    在上一篇依赖方式多模块的基础上对项目进行改造.主要改造user-service项目,service要配置mapper.mybatis及数据库相关的东西,后面的接口消费方user就不再需要了 注意:以下 ...

  6. (3)go-micro微服务项目搭建

    目录 一 微服务项目介绍 二 go-micro安装 1.拉取micro镜像 2.生成项目目录 三 项目搭建 使用DDD模式开发项目: 四 最后 一 微服务项目介绍 账户功能是每一个系统都绕不开的一部分 ...

  7. 【SFA官方翻译】使用 Kubernetes、Spring Boot 2.0 和 Docker 的微服务快速指南

    [SFA官方翻译]使用 Kubernetes.Spring Boot 2.0 和 Docker 的微服务快速指南 原创: Darren Luo SpringForAll社区 今天 原文链接:https ...

  8. 【spring colud】spring cloud微服务项目搭建【spring boot2.0】

    spring cloud微服务项目搭建 =================================== 示例版本: 1.spring boot 2.0版本 2.开发工具 IntellJ IDE ...

  9. 【版本号公布】Jeecg-P3 1.0 公布,J2EE微服务框架(插件开发)

    JEECG-P3 1.0 公布了! JEECG-P3 1.0是一个J2EE微服务框架(插件开发). 特点:业务组件以JAR方式提供,插件模式.松耦合.可插拔.支持独立部署,也能够无缝集成Jeecg平台 ...

  10. 「 从0到1学习微服务SpringCloud 」10 服务网关Zuul

    系列文章(更新ing): 「 从0到1学习微服务SpringCloud 」06 统一配置中心Spring Cloud Config 「 从0到1学习微服务SpringCloud 」07 RabbitM ...

随机推荐

  1. 绘制三元图、颜色空间图:R语言代码

      本文介绍基于R语言中的Ternary包,绘制三元图(Ternary Plot)的详细方法:其中,我们就以RGB三色分布图为例来具体介绍.   三元图可以从三个不同的角度反映数据的特征,因此在很多领 ...

  2. C#通过文件头判断flv文件

    代码如下: private void button1_Click(object sender, EventArgs e) { string path = Application.StartupPath ...

  3. 卷积神经网络学习笔记——ZFNet(Tensorflow实现)

    完整代码及其数据,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/DeepLearningNote 这个网络应该是CNN的鼻 ...

  4. markdown 常用表情符号 (github emoji)

    markdown 常用表情(emoji) 官网[非笔者维护,仅做引用] Face Smiling 咧嘴笑 grinning 汗颜笑 sweat_smile 爆笑 rofl 眨眼笑 wink innoc ...

  5. #线性基#CF1100F Ivan and Burgers

    题目传送门 分析 线段树上直接维护线性基是三个log的.(一定要合并) 考虑一种分治做法,在 \([l,mid]\) 和 \((mid,r]\) 的询问分治处理, 跨过 \([mid,mid+1]\) ...

  6. #平衡树,set#洛谷 2286 [HNOI2004]宠物收养场

    题目 分析 由于宠物被领养者领养和领养者领养宠物操作是一样的, 考虑建两棵平衡树维护操作,以领养者领养宠物为例 若当前没有宠物,就将领养者加入平衡树中, 否则选择最接近的特点值的宠物统计答案并删除该宠 ...

  7. JDK10的新特性:本地变量类型var

    目录 简介 为什么我们需要var var使用在什么地方 var不能用在什么地方 其他var的特点 总结 简介 java以面向对象的特性显著于世并得到了蓬勃的发展.在语言的发展过程中,为了让java语言 ...

  8. 你不知道的java对象序列化的秘密

    目录 简介 什么是序列化 重构序列化对象 序列化不是加密 使用真正的加密 使用代理 Serializable和Externalizable的区别 总结 简介 你知道序列化可以使用代理吗?你知道序列化的 ...

  9. 深入理解 Java 变量类型、声明及应用

    Java 变量 变量是用于存储数据值的容器.在 Java 中,有不同类型的变量,例如: String - 存储文本,例如 "你好".字符串值用双引号引起来. int - 存储整数( ...

  10. 为 Hugging Face 用户带来无服务器 GPU 推理服务

    今天,我们非常兴奋地宣布 部署到 Cloudflare Workers AI 功能正式上线,这是 Hugging Face Hub 平台上的一项新服务,它使得通过 Cloudflare 边缘数据中心部 ...