我们通过一个系列文章跟大家详细展示一个 go-zero
微服务实例,整个系列分十三篇文章,目录结构如下:
- go-zero 实战 - 服务划分与项目创建
- go-zero 实战 - User API Gateway
- go-zero 实战 - User Login
- go-zero 实战 - User Register
- go-zero 实战 - User Userinfo
- go-zero 实战 - Food API Gateway
- go-zero 实战 - Food Search
- go-zero 实战 - Food AddFood
- go-zero 实战 - Food DeleteFood
- go-zero 实战 - Food Foodlist
- go-zero 实战进阶 - rpc 服务
- go-zero 实战进阶 - 用户管理 rpc 服务
- go-zero 实战进阶 - 食材管理 rpc 服务
期望通过本系列文章带你在本地利用 go-zero
快速开发一个《食谱指南》系统,让你快速上手微服务。
我们在 上一篇 中介绍了如何搭建食材搜索接口,本篇我们采用相同的方式搭建添加食材的接口。你将在本篇了解到以下内容:
- 创建数据库表
user_food
,并定义数据库表结构,以便建立用户
和食材
两者之间的关联; - 利用 goctl model 命令生成对应的
mysql CRUD
代码; - 完善添加食材接口的逻辑。
创建数据库表 user_food
,并定义数据库表结构
在本机 mysql
中的 foodguides
数据库中,执行如下 SQL
语句新建 user_food
表:
CREATE TABLE `user_food` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
`userid` bigint COMMENT '用户Id',
`foodid` bigint COMMENT '食物Id',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `userid_index` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
执行 goctl model
命令生成 mysql CRUD
代码
编辑 foodmanage/model/food.sql
文件,追加上述创建 user_food
表的 SQL
语句。
cd
到 foodmanage/model
目录下,执行 goctl model 命令生成 mysql CRUD
代码:
➜ service:
$ cd foodmanage/model
$ goctl model mysql ddl -src food.sql -dir .
foodmodel.go already exists, ignored.
Done.
注册服务上下文的依赖
$ vim foodmanage/api/internal/svc/serviceContext.go
package svc
import (
"FoodGuides/service/foodmanage/api/internal/config"
"FoodGuides/service/foodmanage/model"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type ServiceContext struct {
Config config.Config
FoodModel model.FoodModel
UserFoodModel model.UserFoodModel
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
FoodModel: model.NewFoodModel(sqlx.NewMysql(c.Mysql.DataSource)),
UserFoodModel: model.NewUserFoodModel(sqlx.NewMysql(c.Mysql.DataSource)),
}
}
完善添加食材接口的逻辑
$ vim foodmanage/api/internal/logic/addfoodlogic.go
package logic
import (
"FoodGuides/service/foodmanage/model"
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"strconv"
"FoodGuides/service/foodmanage/api/internal/svc"
"FoodGuides/service/foodmanage/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddFoodLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddFoodLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddFoodLogic {
return &AddFoodLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AddFoodLogic) AddFood(req *types.AddFoodRequest) (*types.AddFoodResponse, error) {
// 获取 jwt 载体中 `uid` 信息,
uid, _ := l.ctx.Value("uid").(json.Number).Int64()
foodId, _ := strconv.ParseInt(req.FoodId, 10, 64)
_, err := l.svcCtx.FoodModel.FindOne(l.ctx, foodId)
if err != nil {
if err == model.ErrNotFound {
return nil, errors.New(fmt.Sprintf("不存在 ID 为 %d 的食材", foodId))
}
return nil, err
}
data := model.UserFood{
Userid: sql.NullInt64{
Int64: uid,
Valid: true,
},
Foodid: sql.NullInt64{
Int64: foodId,
Valid: true,
},
}
_, err = l.svcCtx.UserFoodModel.Insert(l.ctx, &data)
if err != nil {
return nil, err
}
return &types.AddFoodResponse{}, nil
}
修改 Response
返回格式
$ vim foodmanage/api/internal/handler/addfoodhandler.go
package handler
import (
"FoodGuides/common/responsex"
"net/http"
"FoodGuides/service/foodmanage/api/internal/logic"
"FoodGuides/service/foodmanage/api/internal/svc"
"FoodGuides/service/foodmanage/api/internal/types"
"github.com/zeromicro/go-zero/rest/httpx"
)
func AddFoodHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AddFoodRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.OkJson(w, responsex.FailureResponse(nil, err.Error(), 1000))
return
}
l := logic.NewAddFoodLogic(r.Context(), svcCtx)
resp, err := l.AddFood(&req)
if err != nil {
httpx.OkJson(w, responsex.FailureResponse(nil, err.Error(), 1000))
} else {
httpx.OkJson(w, responsex.SuccessResponse(resp, "新增成功"))
}
}
}
启动服务
启动 food api
服务, 运行成功后,food api
则运行在本机的 8889
端口
➜ service:
$ go run foodmanage/api/food.go -f foodmanage/api/etc/food-api.yaml
Starting server at 0.0.0.0:8889...
我们用 Postman
尝试请求 /food/addfood
接口:
- 在
Postman
的Authorization
选项中选择Bearer Token
,填写登录成功后Api
返回的accessToken
字段值。 - 在
Postman
的Body
选项中选择raw
,并设置内容为{"foodId": "1"}
。
点击发送请求按钮,有如下截图的响应说明接口运行正常。
我们去查看本地数据库表 user_food
表,将会看到有一条新记录已被插入到表中。
这样 Food AddFood
接口就开发完成了。下一篇我们将介绍如何搭建删除食材接口。