这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天。 本篇笔记记录我入门使用GORM的一些过程。
本篇文章接续上次的创作。Hertz入门 | 青训营笔记 - 掘金 (juejin.cn)
更复杂的接口
上次我们只有一个/echo接口,它的使用也不包含持久性的数据,本篇文章中我们添加两个新的接口,/note/add和/note/list,分别用来向数据库中添加一条文本信息,以及列出全部的文本信息。
// idl/note/note.proto
syntax = "proto3";
package note;
option go_package = "note";
import "api.proto";
enum Code {
NoCode = 0;
Success = 1;
ParamInvalid = 2;
DBErr = 3;
}
message Note {
int64 id = 1;
string content = 2;
}
message NoteAddReq {
string content = 1 [(api.body) = "content", (api.form) = "content", (api.vd) = "(len($) > 0 && len($) < 100)"];
}
message NoteAddResp {
Code statusCode = 1 [(api.body) = "status_code"];
}
service NoteAddService {
rpc NoteAdd(NoteAddReq) returns(NoteAddResp) {
option (api.post) = "/note/add";
}
}
message NoteListReq {
int64 maxNum = 1 [(api.query) = "max", (api.vd) = "$ > 0 && $ < 20)"];
}
message NoteListResp {
Code statusCode = 1 [(api.body) = "status_code"];
repeated Note notes = 2;
}
service NoteListService {
rpc NoteList(NoteListReq) returns(NoteListResp) {
option (api.get) = "/note/list";
}
}
使用以下命令更新生成的代码
hz update -I idl -idl idl/note/note.proto
编写ORM代码生成脚本
创建cmd目录,并在该目录下创建generate.go文件,编写以下内容。
package main
import (
"gorm.io/driver/sqlite"
"gorm.io/gen"
"gorm.io/gorm"
"hertz-echo/biz/model/note"
)
func main() {
g := gen.NewGenerator(gen.Config{
OutPath: "../biz/query",
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode
})
// gormdb, _ := gorm.Open(mysql.Open("root:@(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local"))
gormdb, _ := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})
g.UseDB(gormdb) // reuse your gorm db
// Generate basic type-safe DAO API for struct `model.User` following conventions
g.ApplyBasic(note.Note{})
// Generate the code
g.Execute()
}
运行生成脚本,生成相关的基础文件。
cd cmd & go run generate.go
可以看到新生成的文件
编写业务逻辑
// NoteAdd .
// @router /note/add [POST]
func NoteAdd(ctx context.Context, c *app.RequestContext) {
var err error
var req note.NoteAddReq
resp := new(note.NoteAddResp)
err = c.BindAndValidate(&req)
if err != nil {
resp.StatusCode = note.Code_ParamInvalid
return
}
err = query.Note.Create(&ormNote.Note{Content: req.Content})
if err != nil {
resp.StatusCode = note.Code_DBErr
return
}
resp.StatusCode = note.Code_Success
c.JSON(consts.StatusOK, resp)
}
// NoteList .
// @router /note/list [GET]
func NoteList(ctx context.Context, c *app.RequestContext) {
var err error
var req note.NoteListReq
resp := new(note.NoteListResp)
err = c.BindAndValidate(&req)
if err != nil {
resp.StatusCode = note.Code_ParamInvalid
return
}
modelNotes, err := query.Note.Order(query.Note.ID).Limit(int(req.MaxNum)).Find()
if err != nil {
resp.StatusCode = note.Code_DBErr
return
}
notes := make([]*note.Note, 0, len(modelNotes))
for _, m := range modelNotes {
notes = append(notes, ¬e.Note{Id: m.ID, Content: m.Content})
}
resp.StatusCode = note.Code_Success
resp.Notes = notes
c.JSON(consts.StatusOK, resp)
}
有了自动生成的框架和orm代码,业务逻辑的编写就非常简单了。
注意,还需要在主程序中插入数据库初始化的代码
运行与测试
重新编译并运行程序
使用ApiPost工具来测试我们的接口
add接口测试
list接口测试