go-zero微服务实战——基本环境搭建

news2024/9/27 15:31:31

简介

项目架构来源于go-zero实战:让微服务Go起来。此对该项目有所删减,相对简单适合初学者。

省去了项目中每个服务占用独立docker的过程,省略了docker-compose的构建过程。每个服务是一个独立的程序不依赖与容器。

环境搭建

  1. 安装goctl
go install github.com/zeromicro/go-zero/tools/goctl@latest
  1. 安装protoc
goctl env check --install --verbose --force
  1. 安装go-zero
go get -u github.com/zeromicro/go-zero@latest
  1. 生成api标准api服务
goctl api new apiservice
  1. 生成rpc服务
goctl rpc new rpcservice

生成代码后go mod tidy下载所需依赖。

apiservice目录下的apiservicelogic.go27行后修改为如下图所示代码:

在这里插入图片描述

删除apiservice目录下etc下的配置文件,在主程序中做如何修改如下修改,直接配置方便一些:

func main() {

	var c config.Config
	c.Host = "0.0.0.0"
	c.Port = 8000

	server := rest.MustNewServer(c.RestConf)
	defer server.Stop()

	ctx := svc.NewServiceContext(c)
	handler.RegisterHandlers(server, ctx)

	fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
	server.Start()
}

api服务统一为8000系列的端口。

rpcservice目录下的yaml配置文件端口修改为9000系。主函数做如下修改:

func main() {
	var c config.Config
	c.ListenOn = "0.0.0.0:9000"
	c.Mode = "dev"
	ctx := svc.NewServiceContext(c)

	s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
		rpcservice.RegisterRpcserviceServer(grpcServer, server.NewRpcserviceServer(ctx))

		if c.Mode == service.DevMode || c.Mode == service.TestMode {
			reflection.Register(grpcServer)
		}
	})
	defer s.Stop()

	fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
	s.Start()
}

启动程序

在这里插入图片描述

在这里插入图片描述

浏览器访问

在这里插入图片描述

rpc客户端访问

新项目复制两个pb文件,编写客户端主程序。

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"rpcclient/rpcservice"
)

func main() {
	//配置连连接参数(无加密)
	dial, _ := grpc.Dial("localhost:9000", grpc.WithTransportCredentials(insecure.NewCredentials()))
	defer dial.Close()
	//创建客户端连接
	client := rpcservice.NewRpcserviceClient(dial)
	//通过客户端调用方法
	res, _ := client.Ping(context.Background(), &rpcservice.Request{Ping: "xiaoxu"})
	fmt.Println(res.Pong)

}

在这里插入图片描述

go-zero api服务构建

整合mysql数据库

构建如项目上的4个服务。4个服务都是上一节构建基本项目为基础的gitee地址

整合数据库就不再过多赘述了,整合xorm框架,返回数据库引擎即可,如下:

xorm实战——结构体映射到实现数据库操作

import (
	"fmt"

	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"
)

var Engine *xorm.Engine

func init() {
	var err error
	e, err := xorm.NewEngine("mysql", "root:root@/zerotest?charset=utf8")
	if err != nil {
		fmt.Println("数据库连接失败!")
	}
	// err的错误处理
	Engine = e
}

构建mysql数据库后在其他包下通过库名.Engine即可使用数据库引擎。

创建数据库

CREATE TABLE `order` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `order_id` varchar(100) NOT NULL COMMENT '订单编号',
  `type` tinyint DEFAULT NULL COMMENT '订单类型',
  `customer_id` int DEFAULT NULL COMMENT '用户编号',
  `amount` int DEFAULT NULL COMMENT '数量',
  `payment` tinyint DEFAULT NULL COMMENT '支付方式',
  `status` tinyint DEFAULT NULL COMMENT '状态',
  `create_time` varchar(100) DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单表';

控制器逻辑实现

新建logic目录

在这里插入图片描述

创建订单逻辑类

type orderLogic struct{}

var OrderLogic orderLogic

// 创建订单
func (this orderLogic) Create(param models.Order) error {
	param.Id = 0
	_, err := db.Engine.Insert(param)
	if err != nil {
		fmt.Printf("logic module create err:%v", err)
		return err
	}
	return nil
}

//db是构建服务器引擎的包

控制器调用逻辑代码

// create
func OrderCreateController() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		//获取请求参数
		var req models.Order
		err := httpx.ParseJsonBody(r, &req)
		if err != nil {
			//fmt.Printf("ordercontoller err:%v", err)
			httpx.WriteJson(w, 500, fmt.Sprintf("ordercontoller err:%v", err))
			return
		}
		//******************//
		err = orderlogic.OrderLogic.Create(req)
		//******************//
		if err != nil {
			//fmt.Printf("order create err:%v", err)
			httpx.WriteJson(w, 500, fmt.Sprintf("order create err:%v", err))
			return
		}
		httpx.OkJson(w, map[string]string{"code": "200", "message": "插入成功!"})

	}
}

Create方法不使用结构体模拟类,直接是一个函数也是可以的,但是函数就不能重名了,在微服务中可以为单个函数,在单纯的web服务中还是用类实现比较好。

部分代码:

// create
func OrderCreateController() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		//获取请求参数
		var req models.Order
		err := httpx.ParseJsonBody(r, &req)
		if err != nil {
			//fmt.Printf("ordercontoller err:%v", err)
			httpx.WriteJson(w, 500, fmt.Sprintf("ordercontoller err:%v", err))
			return
		}
		err = orderlogic.OrderLogic.Create(req)
		if err != nil {
			//fmt.Printf("order create err:%v", err)
			httpx.WriteJson(w, 500, fmt.Sprintf("order create err:%v", err))
			return
		}
		httpx.OkJson(w, map[string]string{"code": "200", "message": "插入成功!"})

	}
}

// update
func OrderUpdateController() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req models.Order
		err := httpx.ParseJsonBody(r, &req)
		if err != nil {
			httpx.WriteJson(w, 500, fmt.Sprintf("update err:%v", err))
			return
		}
		err = orderlogic.OrderLogic.Update(req)
		if err != nil {
			//...
			return
		}
		httpx.OkJson(w, map[string]string{"code": "200", "message": "更新成功!"})

	}
}

//Remove

func OrderRemove() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req models.Order
		err := httpx.ParseJsonBody(r, &req)
		if err != nil {
			httpx.WriteJson(w, 500, fmt.Sprintf("remove err%v", err))
			return
		}
		err = orderlogic.OrderLogic.Remove(req)
		if err != nil {
			//...
			return
		}
		httpx.OkJson(w, map[string]string{"code": "200", "message": "删除成功!"})
	}
}

//List

func OrderList() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		res, err := orderlogic.OrderLogic.List()
		if err != nil {
			//...
			return
		}
		httpx.OkJson(w, res)
	}
}

逻辑层直接省略了,就是xorm对mysql的CURD操作。

注册路由

func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
	server.AddRoutes(
		[]rest.Route{
			{
				Method:  http.MethodGet,
				Path:    "/from/:name",
				Handler: ApiserviceHandler(serverCtx),
			},
			//自定义路由
			{
				Method: http.MethodPost,
				Path: "/create",
				Handler: OrderCreateController(),
			},
			{
				Method: http.MethodPost,
				Path: "/update",
				Handler: OrderUpdateController(),
			},
			{
				Method: http.MethodPost,
				Path: "/remove",
				Handler: OrderRemove(),
			},
			{
				Method: http.MethodPost,
				Path: "/list",
				Handler: OrderList(),
			},
		},
	)
}

在这里插入图片描述
综上所属,已经成功的构建了一个web服务,包括对订单order的基本操作。

如果不想手写这莫多代码,可以看看zero的api语法,直接使用api文件一键生成更加方便。

go-zero rpc服务构建

在rpc远程调用中主要用于rpc服务器注册本地的方法,实现服务器之间的内部调用。在上述服务中,都是沿用了插件生成的目录,仅修改了部分配置文件。可以参考如下连接的目录结构层次清晰。

go-zero实战

删除旧的rpc服务的所有目录,保留proto文件,添加如下内容:

syntax = "proto3";

package rpcservice;
option go_package="./rpcservice";

message Request {
  string ping = 1;
}

message Response {
  string pong = 1;
}

service Rpcservice {
  rpc Ping(Request) returns(Response);
  // 自定义方法区
  rpc Create (Request) returns (Response);
  rpc Update (Request) returns (Response);
  rpc Remove (Request) returns (Response);
  rpc Detail (Request) returns (Response);
  rpc List (Request) returns (Response);
}

注意这里不再是goctl rpc new [name]了,该命令是一键生成rpc标准服务命令,而需要自定义rpc服务即根据编写的.proto文件生成服务需要使用protobuf插件命令。

protoc-gen-go,protoc-gen-go-grpc

这两个插件在grpc服务中一般是需要独立安装的,但是在go-zero中goctl集成了这两个插件。

protoc --go_out=. *.proto
protoc --go-grpc_out=. *.proto

以下是自定义rpc服务部分,goctl生成直接跳过

运行完指令后在proto文件指定的目录生成了grpc服务源码,如下

在这里插入图片描述

在这里插入图片描述

注意如果之前已经使用了goctl rpc命令,那么目录下不止有这两个文件,建议删除goctl生成的文件自定义构建,因为许多用不着到。goctl生成的代码主要是结合了zrpc.RpcServerConf的配置,即config目录下的对象,如下:

在这里插入图片描述
在goctl生成的代码中也是支持flag库的,如下,这里后续将会改成静态的省去配置文件。
在这里插入图片描述

goctl生成部分

通过两个命令生成rpc服务文件,如下:

在这里插入图片描述

在生成的代码中已经具备了逻辑层的方法,如下:

在这里插入图片描述

修改主程序注释调用flag参数获取功能,原因是api服务和rpc服务中都有独立的yaml文件这是不合理的,两个flag参数获取存在冲突,所以将两个都注册掉改为静态配置,后续可以改为一个配置文件。

//注释掉flag获取参数的部分
func main() {
	flag.Parse()

	var c config.Config
	// conf.MustLoad(*configFile, &c)
	c.ListenOn = "0.0.0.0:9000"
	c.Name = "order.rpc"
	ctx := svc.NewServiceContext(c)
	s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
		rpcservice.RegisterRpcserviceServer(grpcServer, server.NewRpcserviceServer(ctx))

		if c.Mode == service.DevMode || c.Mode == service.TestMode {
			reflection.Register(grpcServer)
		}
	})
	defer s.Stop()

	fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
	s.Start()
}

修改rpc服务的逻辑如下所示:

在这里插入图片描述
编写客户端访问rpc服务

import (
	"context"
	"fmt"
	"rpcclient/rpcservice"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {
	//配置连连接参数(无加密)
	dial, _ := grpc.Dial("localhost:9000", grpc.WithTransportCredentials(insecure.NewCredentials()))
	defer dial.Close()
	//创建客户端连接
	client := rpcservice.NewRpcserviceClient(dial)
	//通过客户端调用方法
	res, err := client.Ping(context.Background(), &rpcservice.Request{ReqJson: "xiaoxu"})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(res)

}

在这里插入图片描述
成功访问,ping的案例是goctl已经实现了的,虽然早proto中编写了自定义的方法,如下

在这里插入图片描述
但是却仍然无法调用,回报未继承的错误,在客户端加入如下代码:

//order list
r, err := client.List(context.Background(), &rpcservice.Request{})
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(r.ResJson)

在这里插入图片描述

List not implemented该错误的原因时虽然存在该方法名,但方法没有方法体,也就说函数没有将处理逻。

在这里插入图片描述
在服务端通过反射获取到Rpcservice_Ping_FullMethodName的Ping方法,也就是/rpcservice.Rpcservice/Ping的Ping方法。如下图

在这里插入图片描述

该方法就是生成文件的server目录下包的方法,如下:

在这里插入图片描述
在这里插入图片描述

官方提供的方法ping调用了生成的logic的ping方法,其实就是实现了逻辑的解耦,将逻辑功能分隔开来。如下所示,logic层部分只写逻辑处理,在serve下调用逻辑处理部分函数。

在这里插入图片描述
在这里插入图片描述

当然不论如何解耦,核心还是server目录的文件,必须在此处注册逻辑函数,才可以在rpc武器生成函数实例,客户端才可以成功调用。

该方法实际上也是proto中定义的方法的一个重写过程,是接口的是实现。

注册自定义函数

//list 继承
func (s *RpcserviceServer) List(ctx context.Context,in *rpcservice.Request) (*rpcservice.Response, error) {
	//r, err := logic.List(in)
	o, err := orderlogic.OrderLogic.List()
	if err != nil {
		fmt.Printf("rpc err:%v", err)
		return &rpcservice.Response{}, err
	}
	//o 赚json字符串
	josnstr, _ := json.Marshal(o)
	return &rpcservice.Response{ResJson: string(josnstr)}, nil
}

上面代码逻辑部分一起写在rpc方法注册的函数中,当逻辑代码多是就会十分冗余,最好将逻辑部分提取出来封装在新函数中,在注册是调用新方法即可,想官方提供的模板一样。

服务端注册成功后,服务端调用,代码如下:

package main

import (
	"context"
	"fmt"
	"rpcclient/rpcservice"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {
	//配置连连接参数(无加密)
	dial, _ := grpc.Dial("localhost:9000", grpc.WithTransportCredentials(insecure.NewCredentials()))
	defer dial.Close()
	//创建客户端连接
	client := rpcservice.NewRpcserviceClient(dial)
	//通过客户端调用方法
	res, err := client.Ping(context.Background(), &rpcservice.Request{ReqJson: "xiaoxu"})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(res)

	//order list
	r, err := client.List(context.Background(), &rpcservice.Request{})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(r.ResJson)

}

在这里插入图片描述

别忘了克隆_grpc.pbpb文件。

到此服务order已经可以同时提供api服务和rpc服务了。

gitee地址:https://gitee.com/fireapproval/xiaoxu/tree/xiaoxu/go/go-zero-test

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/731137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c++ -- STL

【C/C】STL详解_cstl_沉晓的博客-CSDN博客 Learning Record have done assignment class template An excellent programmer only needs to know how to use containers to improve program encapsulation and reduce coupling, without understanding the underlying pri…

面向对象之创建对象模式和继承模式

目录 工厂函数模式 优点: 缺点: 构造函数模式 优点: 缺点: 原型对象模式 优点: 缺点: 组合模式 instanceof 继承 继承分为三类,分别是:原型链继承、借用构造函数继承、组合继承(原型链继承借用构造函数继承) 组合继承 从…

开发工具VSCODE的使用记录

vscode简介 Visual Studio Code(简称“VS Code” [1] )是Microsoft在2015年4月30日Build开发者大会上正式宣布一个运行于 Mac OS X、Windows和 Linux 之上的,针对于编写现代Web和云应用的跨平台源代码编辑器, [2] 可在桌面上运行…

ADB 命令结合 monkey 的简单使用,超详细

一:ADB简介 1,什么是adb: ADB 全称为 Android Debug Bridge,起到调试桥的作用,是一个客户端-服务器端程序。其中客户端是用来操作的电脑,服务端是 Android 设备。ADB 也是 Android SDK 中的一个工具&#…

openssl CVE-2016-2107 漏洞检测---OpenSSL Padding Oracle 攻击

openssl CVE-2016-2107 漏洞检测—OpenSSL Padding Oracle 攻击 文章目录 CVE-2016-2107.exe执行1执行2 OpenSSL Padding Oracle 攻击漏洞描述检测方法修复 CVE-2016-2107.exe 执行1 下载CVE-2016-2107.exe https://github.com/FiloSottile/CVE-2016-2107 https://github.com…

2023 7.3~7.9 周报 (论文初读)

上周回顾: (上周还没开始) 本周计划: 本周阅读论文《Deep-Learning Full-Waveform Inversion Using Seismic Migration Images》. 这篇论文是发表于2022的一篇较新的关于DL-FWI的论文, 作者在论文中提出了一些比较新颖的观点和质疑. 这篇论文主基调很符合近几年DL-FWI的味道…

对 MinIO API 进行封装并上传到第三方库 Pyzjr

目录 本文介绍 上一节补充 使用官方的游乐场进行测试和开发 熟悉MinIO的API 创建客户端 操作桶 1、检查桶是否存在,如果不存在就创建一个桶 2、列出所有的存储桶名 3、删除储存桶 4、用于查看存储桶的对象 操作对象 1、删除对象 2、删除zip文件 3、下…

C#基础学习_构造方法

C#基础学习_构造方法 在构造方法中添加初始化内容; 通过使用构造方法,可以简化对象初始化代码。 无参数的构造方法: public Student(){StudentID = 12345;StudentName = "djichsdi";}带参数的构造方法(构造方法同样可以重载&

Python——基础语法

输出语句 #字符串拼接 print("hello word""北岭山脚鼠鼠") #字符转义 print("He said \"Let\s go!\"") #换行 print("hello!\nHi!") #三引号 print(""""北岭山脚鼠鼠 北岭山脚鼠鼠 北岭山脚鼠鼠 北岭山…

ESP32(掌控板) 陀螺仪显示与RGB灯

ESP32(掌控板) 陀螺仪显示与RGB灯 本程序图形化显示陀螺仪位置(注意要换算),根据陀螺仪位置控制RGB灯颜色并有3种颜色组合和关灯可选,通过触摸按键调节亮度。 图形化程序如下 Arduino代码如下 /*!* MindP…

字符集,编码方式和Java程序乱码问题

目录 1,字符编码 2,三大字符集及编码方式 2.1,ASCII字符集及编码方式 2.2,GBK字符集及编码方式 2.3,Unicode字符集及编码方式 3.程序乱码问题 1,字符编码 数字计算机中的存储器唯一可以存储的是比特&a…

绿虫生产效率提升工具怎么安装配置?

一、添加员工 打开绿虫生产效率提升工具后台,输入账号密码登录,登录成功之后,需要先进行员工添加,点击员工管理,导入员工信息,也可使用企微同步。 二、绑定员工 点击终端部署,复制网址或下载安…

多模态系列论文----最详细的多模态论文总结(BLIP、BEIT、CoCa等)

1 多模态概述 多模态指的是多种模态的信息数据,包括:文本、图像、视频、音频等。多模态任务是指需要同时处理两种或多种不同类型的数据的任务。近年来,随着深度学习技术的发展,多模态任务取得了显著的进步。特别是VIT&#xff08…

【WebSocket】SpringBoot整合WebSocket实现聊天室(一)

目录 一、准备 1、引入依赖 2、创建配置类 二、相关注解 一、准备 1、引入依赖 首先我们需要在项目中引入依赖&#xff0c;有两种方式。第一种我们可以在创建Spring Boot项目时搜索WebSocket然后勾选依赖 第二种是我们可以直接在项目的pom.xml文件中插入以下依赖 <dep…

基于TF-IDF+Tensorflow+PyQt+孪生神经网络的智能聊天机器人(深度学习)含全部Python工程源码及模型+训练数据集

目录 前言总体设计系统整体结构图系统流程图孪生神经网络结构图 运行环境Python 环境TensorFlow 环境 模块实现1. 数据预处理2. 创建模型并编译3. 模型训练及保存4. 模型应用 系统测试1. 训练准确率2. 测试效果3. 模型生成 工程源代码下载其它资料下载 前言 本项目利用TF-IDF&…

[VUE学习】从头搭建权限管理系统前端-初始化

1.安装Node 2.安装Vue Cli vue的一个脚手架 npm install -g vue/cli 3.vue ui搭建vue项目 cmd 运行 vue ui 然后创建新项目 选择npm 选择配置 Babel 是编译的 Router 是路由 vuex 是状态保存的 Linter/fomatter 代码检测和格式化 创建完成 这个时候 代码在我们本地…

Spring Boot 中的 Criteria 是什么,如何使用?

Spring Boot 中的 Criteria 是什么&#xff0c;如何使用&#xff1f; 介绍 Spring Boot 是一个流行的 Java Web 开发框架&#xff0c;它提供了一些强大的工具和库&#xff0c;使得开发 Web 应用程序变得更加容易。其中之一是 Criteria API&#xff0c;它提供了一种类型安全的…

电脑免费简单又好用的记事本app软件推荐

很多职场人士在办公时都需要用到电脑&#xff0c;在电脑上有很多好用的工具软件可以用来辅助工作的展开&#xff0c;其中记事本类的App就有不少优质软件存在。那电脑免费简单又好用的记事本app软件推荐哪些呢&#xff1f;这里小编就以自己的Windows10电脑为例&#xff0c;为大家…

山西电力市场日前价格预测【2023-07-09】

日前价格预测 预测明日&#xff08;2023-07-09&#xff09;山西电力市场全天平均日前电价为386.09元/MWh。其中&#xff0c;最高日前价格为505.65元/MWh&#xff0c;预计出现在21: 30。最低日前电价为286.38元/MWh&#xff0c;预计出现在13: 30。 以上预测仅供学习参考&#x…

ModaHub魔搭社区:向量数据库Zilliz Cloud向量搜索和查询教程(一)

目录 概述 开始前 单向量搜索 本文介绍如何在 Zilliz Cloud 中执行近似最近邻&#xff08;Approximate Nearest Neighbour&#xff0c;ANN&#xff09;搜索和查询。搜索是指在 Collection 中查找与指定查询向量最接近的向量&#xff0c;查询是基于指定条件筛选出满足条件的数…