go-zero 实战 - Food Search

203 阅读3分钟

我们通过一个系列文章跟大家详细展示一个 go-zero 微服务实例,整个系列分十三篇文章,目录结构如下:

  1. go-zero 实战 - 服务划分与项目创建
  2. go-zero 实战 - User API Gateway
  3. go-zero 实战 - User Login
  4. go-zero 实战 - User Register
  5. go-zero 实战 - User Userinfo
  6. go-zero 实战 - Food API Gateway
  7. go-zero 实战 - Food Search
  8. go-zero 实战 - Food AddFood
  9. go-zero 实战 - Food DeleteFood
  10. go-zero 实战 - Food Foodlist
  11. go-zero 实战进阶 - rpc 服务
  12. go-zero 实战进阶 - 用户管理 rpc 服务
  13. go-zero 实战进阶 - 食材管理 rpc 服务

期望通过本系列文章带你在本地利用 go-zero 快速开发一个《食谱指南》系统,让你快速上手微服务。

本篇我们将讲解如何创建 食材搜索 接口。同样的,你将在本篇学习到以下内容:

  1. 创建 food 表,并定义数据库表结构,以便保存食材信息;
  2. 利用 goctl model 命令,生成 mysql CRUD 代码;
  3. 完善搜索接口逻辑内容。

创建 food 表,并定义数据库表结构

在本机 mysql 中的 foodguides 数据库中,执行如下 SQL 语句新建 food 表:

CREATE TABLE `food` (
                        `id` bigint NOT NULL AUTO_INCREMENT COMMENT '食物Id',
                        `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物名称',
                        `protein` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物蛋白质含量',
                        `fat` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物脂肪含量',
                        `carbohydrate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物碳水化合物含量',
                        `calorie` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物卡路里',
                        `minerals` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物矿物质含量',
                        `calcium` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物钙含量',
                        `phosphorus` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物磷含量',
                        `iron` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物铁含量',
                        `purine` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '食物嘌呤含量',
                        `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
                        `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                        PRIMARY KEY (`id`),
                        UNIQUE KEY `name_index` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

接下来,我们执行以下 SQL 语句,新增一条食材数据,为搜索结果做准备:

INSERT INTO `foodguides`.`food`(`id`, `name`, `protein`, `fat`, `carbohydrate`, `calorie`, `minerals`, `calcium`, `phosphorus`, `iron`, `purine`, `create_time`, `update_time`) VALUES (1, '鱿鱼', '60.0', '4.6', '7.8', '1323', '100', '87', '392', '4.1', '100', '2021-01-26 23:30:43', '2021-01-26 23:33:38');

执行 goctl model 命令,生成 mysql CRUD 代码

foodmanage/model 目录下新建 food.sql 文件,并将上述创建 food 数据库表的 SQL 语句复制到该文件中。

cdfoodmanage/model 目录下,执行 goctl model 命令生成 mysql CRUD 代码:

$ goctl model mysql ddl -src food.sql -dir .
Done.

查看 model 目录结构

➜  model: 
$ tree
.
├── food.sql
├── foodmodel.go
├── foodmodel_gen.go
└── vars.go

修改 food.yaml 配置文件

$ vim foodmanage/api/food/etc/food.yaml

Name: food-api
Host: 0.0.0.0
Port: 8889

Mysql:
  DataSource: root:123456@tcp(127.0.0.1:9528)/foodguides?charset=utf8mb4&parseTime=True&loc=Local

Auth:
  AccessSecret: ad879037-d3fd-tghj-112d-6bfc35d54b7d
  AccessExpire: 86400

添加服务配置

$ vim foodmanage/api/internal/config/config.go

package config

import "github.com/zeromicro/go-zero/rest"

type Config struct {
    rest.RestConf
    Mysql struct {
       DataSource string
    }
    Auth struct {
       AccessSecret string
       AccessExpire int64
    }
}

注册服务上下文的依赖

$ 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
}

func NewServiceContext(c config.Config) *ServiceContext {
    return &ServiceContext{
       Config: c,
       FoodModel: model.NewFoodModel(sqlx.NewMysql(c.Mysql.DataSource)),
    }
}

添加搜索接口逻辑

$ vim foodmanage/api/internal/logic/searchlogic.go

package logic

import (
    "context"
    "strconv"

    "FoodGuides/service/foodmanage/api/internal/svc"
    "FoodGuides/service/foodmanage/api/internal/types"

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

type SearchLogic struct {
    logx.Logger
    ctx    context.Context
    svcCtx *svc.ServiceContext
}

func NewSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SearchLogic {
    return &SearchLogic{
       Logger: logx.WithContext(ctx),
       ctx:    ctx,
       svcCtx: svcCtx,
    }
}

func (l *SearchLogic) Search(req *types.SearchRequest) (*types.SearchResponse, error) {
    searchKey := req.Key
    food, err := l.svcCtx.FoodModel.FindOneByName(l.ctx, searchKey)

    if err != nil {
       return nil, err
    }

    foodReply := types.FoodReply{
       Id:           strconv.FormatInt(food.Id, 10),
       Name:         food.Name,
       Protein:      food.Protein,
       Fat:          food.Fat,
       Carbohydrate: food.Carbohydrate,
       Calorie:      food.Calorie,
       Minerals:     food.Minerals,
       Calcium:      food.Calcium,
       Phosphorus:   food.Phosphorus,
       Iron:         food.Iron,
       Purine:       food.Purine,
    }
    return &types.SearchResponse{FoodReply: foodReply}, nil
}

修改 Response 返回格式

$ vim foodmanage/api/internal/handler/searchhandler.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 SearchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
       var req types.SearchRequest
       if err := httpx.Parse(r, &req); err != nil {
          httpx.OkJson(w, responsex.FailureResponse(nil, err.Error(), 1000))
          return
       }

       l := logic.NewSearchLogic(r.Context(), svcCtx)
       resp, err := l.Search(&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 尝试请求搜索接口,有如下截图的响应说明搜索服务运行正常。

image.png

至此,Food Search Api 就开发完了。下一篇将介绍如何搭建添加食材的接口。

上一篇《go-zero 实战 - Food API Gateway》

下一篇《go-zero 实战 - Food AddFood》