jjzjj

【go-zero】(1):尝试使用go-zero的工具goctl进行model,controller代码生成,配置数据库,实现FindAll方法,查询数据库全部数据

fly-iot 2024-01-21 原文

目录

前言


本文的原文连接是:
https://blog.csdn.net/freewebsys/article/details/128707849

未经博主允许不得转载。
博主CSDN地址是:https://blog.csdn.net/freewebsys
博主掘金地址是:https://juejin.cn/user/585379920479288
博主知乎地址是:https://www.zhihu.com/people/freewebsystem

1,关于go-zero框架


项目地址:
https://go-zero.dev/cn/
go-zero 是一个集成了各种工程实践的 web 和 rpc 框架

高性能
内建服务发现、负载均衡
内建限流
自适应熔断
自适应降载
自动触发,自动恢复
超时级联控制
自动缓存控制
链路跟踪、统计报警等
高并发支撑,稳定保障流量洪峰下的服务稳定

2,使用goctl 生成代码,安装工具


https://go-zero.dev/cn/docs/goctl/goctl

官方demo网站:

代码自动生成
go-zero 包含极简的 API 定义和生成工具 goctl,可以根据定义的 api 文件一键生成 Go, iOS, Android, Kotlin, Dart, TypeScript, JavaScript 代码,并可直接运行。

安装代码:

export GOPROXY=https://goproxy.cn/,direct 
go install github.com/zeromicro/go-zero/tools/goctl@latest

goctl -v
goctl version 1.4.3 darwin/amd64

先创建一个新项目:

goctl api new userDemo  -style goZero

cd userDemo

3,使用goctl 生成数据库model的crud代码


针对 userInfo 做CRUD,生成 model 代码:

比如一个用户表,放到 sql/user_info.sql 文件中:

CREATE TABLE IF NOT EXISTS  `user_info` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键Id',
  `name` varchar(200) NOT NULL COMMENT '用户名',
  `password` varchar(200) NOT NULL COMMENT '密码',
  `status` tinyint(1) NOT NULL COMMENT '状态',
  `type` tinyint(1) NOT NULL COMMENT '类型',
 
  PRIMARY KEY (`id`)
  
) ENGINE=InnoDB  AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT="用户信息表";

然后生成model 的 curd 代码:

注意 -c 参数表示是否带缓存:
生成不带缓存的代码:
goctl model mysql ddl -src="./sql/*.sql" -dir="./model"  -style goZero

生成代码缓存的代码:
goctl model mysql ddl -src="./sql/*.sql" -dir="./model" -c -style goZero

会有类似,不带缓存查询,直接硬编码了:

func (m *defaultUserInfoModel) FindOne(ctx context.Context, id int64) (*UserInfo, error) {
	query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userInfoRows, m.table)
	var resp UserInfo
	err := m.conn.QueryRowCtx(ctx, &resp, query, id)
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

带缓存查询:

func (m *defaultUserInfoModel) FindOne(ctx context.Context, id int64) (*UserInfo, error) {
	userInfoIdKey := fmt.Sprintf("%s%v", cacheUserInfoIdPrefix, id)
	var resp UserInfo
	err := m.QueryRowCtx(ctx, &resp, userInfoIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
		query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userInfoRows, m.table)
		return conn.QueryRowCtx(ctx, v, query, id)
	})
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

4,使用goctl 生成controller代码


最关键的就是这个 userDemo.api 的文件定义,和其他框架不同,这个配置定义的是接口的API。

  * 可以在 servicecontext.go 里面传递依赖给 logic,比如 mysql, redis 等
  * 在 api 定义的 get/post/put/delete 等请求对应的 logic 里增加业务处理逻辑

定义 userDemo.api 的配置,做个 crud 的 api 接口:

type UserInfo {
	Id       int    `form:"id,optional"`
	Name     string `form:"name"`
	Password string `form:"password"`
	Status   int    `form:"status,optional"`
	Type     int    `form:"type,optional"`
}

type UserInfoResponse {
	Id     int    `form:"id"`
	Name   string `form:"name"`
	Status int    `form:"status"`
	Type   int    `form:"type"`
}

type SearchRequest {
	Name string `form:"name,optional"`
}

type IdRequest {
	Id int `form:"id"`
}

type CommonResponse {
	Status  int    `json:"status"`
	Message string `json:"message"`
}

type ListResponse {
	Status  int        `json:"status"`
	Message string     `json:"message"`
	Data    []UserInfo `json:"data"`
}

service userDemo-api {
	@handler userInfoListHandler
	get /userInfo/list(SearchRequest) returns (ListResponse)
	
	@handler viewUserInfoHandler
	get /userInfo/view(IdRequest) returns (UserInfoResponse)
	
	@handler saveUserInfoHandler
	post /userInfo/save(UserInfo) returns (CommonResponse)
	
	@handler deleteUserInfoHandler
	post /userInfo/delete(IdRequest) returns (CommonResponse)
}

重新生成代码:

# 需要把之前的 controller 和 logic 代码删除再生成。
goctl api go -api userDemo.api -dir . -style goZero

go mod init 
go mod tidy 

#然后再启动服务:
go run userdemo.go -f etc/userDemo-Api.yaml 

6,增加数据库,日志配置


然后修改 config 的配置和 yaml 配置:

Name: userDemo-api
Host: 0.0.0.0
Port: 8888

Redis:
  Host: localhost:6379
  Type: node
  Pass: 
DB:
  DataSource: go-demo:go-demo123@tcp(127.0.0.0:3306)/go_demo?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
Cache:
  - Host: localhost:6379
    Pass: 

Log:
  ServiceName: userDemo-api
  Level: severe
  Mode: file

修改 config 类:

package config

import (
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest"
)

type Config struct {
	rest.RestConf
	logx.LogConf

	DB struct {
		DataSource string
	}

}

启动类里面增加日志:

	var c config.Config
	conf.MustLoad(*configFile, &c)

	// logx 根据配置初始化
	// https://go-zero.dev/cn/docs/blog/tool/logx/
	logx.MustSetup(c.LogConf)
	// grace close log
	proc.AddShutdownListener(func() {
		logx.Close()
	})

......

然后增加 findAll 方法:

func (m *defaultUserInfoModel) FindAll(ctx context.Context) ([]*UserInfo, error) {
	query := fmt.Sprintf("select %s from %s ", userInfoRows, m.table)

	var resp []*UserInfo
	err := m.conn.QueryRowsCtx(ctx, &resp, query)
	switch err {
	case nil:
		return resp, nil
	default:
		return nil, err
	}
}

controller 里面代码使用 copy 进行转换,因为 model 的类和 logic 包对应的类包不一样:

func (l *UserInfoListLogic) UserInfoList(req *types.SearchRequest) (resp *types.ListResponse, err error) {
	// todo: add your logic here and delete this line
	logx.WithContext(l.ctx).Info("######## query UserInfoList ########")

	userInfoList, err := l.svcCtx.UserInfoModel.FindAll(l.ctx)

	if err != nil {
		return nil, err
	}

	var userInfoListTmp []types.UserInfo //
	_ = copier.Copy(&userInfoListTmp, userInfoList)

	return &types.ListResponse{
		Status:  200,
		Message: "success",
		Data:    userInfoListTmp,
	}, nil
}

然后启动之后 controller 里面就可以获得数据了,终于调试好了。

然后访问:
http://localhost:8888/userInfo/list

{"status":200,"message":"success","data":[{"Id":1,"Name":"11","Password":"22","Status":1,"Type":1},{"Id":2,"Name":"33","Password":"44","Status":5,"Type":2},{"Id":3,"Name":"11","Password":"22","Status":1,"Type":1},{"Id":4,"Name":"33","Password":"44","Status":5,"Type":2},{"Id":5,"Name":"11","Password":"22","Status":1,"Type":1},{"Id":6,"Name":"33","Password":"44","Status":5,"Type":2}]}

7,总结


总体上感觉 go-zero 还是比较好上手的,使用起来也是非常的方便,但是 curd 的 model 里面的查询略少。
而且没有分页查询的数据,需要自己组装。把分页其他的啥的模板都修改下。
相比kratos 这个算是简单的了,因为kratos采用了ddd的设计方式,更优雅。
但是代码分布的略复杂,需要学习下,

本文的原文连接是:
https://blog.csdn.net/freewebsys/article/details/128707849

有关【go-zero】(1):尝试使用go-zero的工具goctl进行model,controller代码生成,配置数据库,实现FindAll方法,查询数据库全部数据的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  3. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  6. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  7. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  8. ruby-on-rails - 独立 ruby​​ 脚本的配置文件 - 2

    我有一个在Linux服务器上运行的ruby​​脚本。它不使用rails或任何东西。它基本上是一个命令行ruby​​脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg

  9. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  10. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

随机推荐