字節(jié)跳動(dòng) Golang 微服務(wù)框架 Hertz 集成 Gorm 實(shí)戰(zhàn)
hello,大家好,我是千羽。
圖片
上一篇,講了《字節(jié)跳動(dòng) Golang 微服務(wù) HTTP 框架 Hertz》入門(mén),今天我們就通過(guò)一個(gè)實(shí)戰(zhàn)項(xiàng)目,來(lái)體驗(yàn) Hertz 和 Gorm 的集成。
在 Golang 開(kāi)發(fā)中,許多框架和功能不像 Java 那么成熟,需要開(kāi)發(fā)者自己實(shí)現(xiàn)。而字節(jié)跳動(dòng)開(kāi)源的 Hertz 框架,則提供了豐富的功能,堪稱 Golang 版的 Spring Boot。
Step 1:Fork Hertz 官方 Demo
首先,將官方的 Hertz 示例倉(cāng)庫(kù) fork 到自己的 GitHub 倉(cāng)庫(kù),方便后續(xù)操作:
圖片
然后,將項(xiàng)目 clone 到本地,按照官方文檔操作。
圖片
具體倉(cāng)庫(kù)地址:https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_gorm
Step 2:配置與啟動(dòng)項(xiàng)目
官方 Readme 提供了啟動(dòng)指導(dǎo),根據(jù)文檔說(shuō)明進(jìn)行以下步驟:
- 使用 Docker 啟動(dòng) MySQL 容器:
cd bizdemo/hertz_gorm && docker-compose up- 連接 MySQL 確保數(shù)據(jù)庫(kù)正常運(yùn)行:
圖片
- 編譯并啟動(dòng)項(xiàng)目:
cd bizdemo/hertz_gorm
go build -o hertz_gorm && ./hertz_gorm若啟動(dòng)成功,你將看到以下日志輸出:
HERTZ: HTTP server listening on address=[::]:8888Step 3:接口調(diào)試
在項(xiàng)目啟動(dòng)后,我們可以逐一測(cè)試接口。Hertz 項(xiàng)目包含了一些基本的 CRUD 接口,方便我們進(jìn)行數(shù)據(jù)的操作和驗(yàn)證。
根據(jù)啟動(dòng)的日志,我們進(jìn)行各個(gè)接口驗(yàn)證
absolutePath=/v1/user/create/
absolutePath=/v1/user/delete/:user_id
absolutePath=/v1/user/query/
absolutePath=/v1/user/update/:user_id
absolutePath=/ping1. /ping 接口測(cè)試
請(qǐng)求 URL: http://localhost:8888/ping
響應(yīng)示例:
{
"message": "pong"
}
圖片
2. 創(chuàng)建用戶接口 /v1/user/create/
請(qǐng)求 URL: http://localhost:8888/v1/user/create/
請(qǐng)求參數(shù):
{
"name": "千羽",
"gender": 1,
"age": 18,
"introduce": "程序員"
}響應(yīng)示例:
{
"code": 1,
"msg": ""
}
圖片
MySQL 查詢效果:
圖片
3. 查詢用戶接口 /v1/user/query/
請(qǐng)求 URL: http://localhost:8888/v1/user/query/
圖片
請(qǐng)求 URL: http://localhost:8888/v1/user/query/
請(qǐng)求參數(shù):
{
"page": 1,
"page_size":10,
"keyword":"千羽"
}響應(yīng)示例:
{
"code": 1,
"msg": "",
"users": [
{
"user_id": 1,
"name": "千羽",
"gender": 1,
"age": 18,
"introduce": "程序員"
}
],
"total": 1
}
圖片
3. 刪除用戶接口 /v1/user/delete/1
刪除,軟刪除,不會(huì)真正的刪除
圖片
Step 4:代碼解析
Service 層:
// CreateUser .
// @router /v1/user/create/ [POST]
func CreateUser(ctx context.Context, c *app.RequestContext) {
var err error
var req user_gorm.CreateUserRequest
err = c.BindAndValidate(&req)
if err != nil {
c.JSON(consts.StatusBadRequest, &user_gorm.CreateUserResponse{Code: user_gorm.Code_ParamInvalid, Msg: err.Error()})
return
}
if err = mysql.CreateUser([]*model.User{
{
Name: req.Name,
Gender: int64(req.Gender),
Age: req.Age,
Introduce: req.Introduce,
},
}); err != nil {
c.JSON(consts.StatusInternalServerError, &user_gorm.CreateUserResponse{Code: user_gorm.Code_DBErr, Msg: err.Error()})
return
}
resp := new(user_gorm.CreateUserResponse)
resp.Code = user_gorm.Code_Success
c.JSON(consts.StatusOK, resp)
}MySQL 層:
func CreateUser(users []*model.User) error {
return DB.Create(users).Error
}查詢用戶的邏輯 /v1/user/query/
Service 層:
// QueryUser .
// @router /v1/user/query/ [POST]
func QueryUser(ctx context.Context, c *app.RequestContext) {
var err error
var req user_gorm.QueryUserRequest
err = c.BindAndValidate(&req)
if err != nil {
c.JSON(consts.StatusBadRequest, &user_gorm.QueryUserResponse{Code: user_gorm.Code_ParamInvalid, Msg: err.Error()})
return
}
users, total, err := mysql.QueryUser(req.Keyword, req.Page, req.PageSize)
if err != nil {
c.JSON(consts.StatusInternalServerError, &user_gorm.QueryUserResponse{Code: user_gorm.Code_DBErr, Msg: err.Error()})
return
}
c.JSON(consts.StatusOK, &user_gorm.QueryUserResponse{Code: user_gorm.Code_Success, Users: pack.Users(users), Totoal: total})
}MySQL 層:
func QueryUser(keyword *string, page, pageSize int64) ([]*model.User, int64, error) {
db := DB.Model(model.User{})
if keyword != nil && len(*keyword) != 0 {
db = db.Where(DB.Or("name like ?", "%"+*keyword+"%").
Or("introduce like ?", "%"+*keyword+"%"))
}
var total int64
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
var res []*model.User
if err := db.Limit(int(pageSize)).Offset(int(pageSize * (page - 1))).Find(&res).Error; err != nil {
return nil, 0, err
}
return res, total, nil
}更新用戶的邏輯 /v1/user/update/1
圖片
Service 層:
// UpdateUser .
// @router /v1/user/update/:user_id [POST]
func UpdateUser(ctx context.Context, c *app.RequestContext) {
var err error
var req user_gorm.UpdateUserRequest
err = c.BindAndValidate(&req)
if err != nil {
c.JSON(consts.StatusBadRequest, &user_gorm.UpdateUserResponse{Code: user_gorm.Code_ParamInvalid, Msg: err.Error()})
return
}
u := &model.User{}
u.ID = uint(req.UserID)
u.Name = req.Name
u.Gender = int64(req.Gender)
u.Age = req.Age
u.Introduce = req.Introduce
if err = mysql.UpdateUser(u); err != nil {
c.JSON(consts.StatusInternalServerError, &user_gorm.UpdateUserResponse{Code: user_gorm.Code_DBErr, Msg: err.Error()})
return
}
c.JSON(consts.StatusOK, &user_gorm.UpdateUserResponse{Code: user_gorm.Code_Success})
}mysql 層:
func UpdateUser(user *model.User) error {
return DB.Updates(user).Error
}刪除 /v1/user/delete/:user_id
刪除,軟刪除,不會(huì)真正的刪除
Service 層:
// DeleteUser .
// @router /v1/user/delete/:user_id [POST]
func DeleteUser(ctx context.Context, c *app.RequestContext) {
var err error
var req user_gorm.DeleteUserRequest
err = c.BindAndValidate(&req)
if err != nil {
c.JSON(consts.StatusBadRequest, &user_gorm.DeleteUserResponse{Code: user_gorm.Code_ParamInvalid, Msg: err.Error()})
return
}
if err = mysql.DeleteUser(req.UserID); err != nil {
c.JSON(consts.StatusInternalServerError, &user_gorm.DeleteUserResponse{Code: user_gorm.Code_DBErr, Msg: err.Error()})
return
}
c.JSON(consts.StatusOK, &user_gorm.DeleteUserResponse{Code: user_gorm.Code_Success})
}mysql 層:
func DeleteUser(userId int64) error {
return DB.Where("id = ?", userId).Delete(&model.User{}).Error
}
圖片
總結(jié)
通過(guò)這個(gè)項(xiàng)目,我們體驗(yàn)了 Hertz 集成 Gorm 的基本操作,涵蓋了用戶的創(chuàng)建、查詢、更新和刪除接口。在 Golang 生態(tài)中,雖然框架沒(méi)有 Java 完善,但 Hertz 帶來(lái)了簡(jiǎn)便的解決方案,有助于開(kāi)發(fā)者快速上手。
參考文章:https://www.cloudwego.io/zh/docs/hertz/
































