初学者友好:Go-Kratos 集成 go-crud,GORM ORM CRUD 无需重复编码,轻松上手

简介: 本文介绍如何在Go-Kratos微服务中集成go-curd与GORM,实现CRUD操作免重复编码。基于kratos-gorm-example项目,通过step-by-step教程,帮助初学者快速上手:从环境搭建、模型定义到API开发,全程简化数据操作,显著提升开发效率,适合Go新手快速构建微服务应用。

初学者友好:Go-Kratos 集成 go-crud,GORM ORM CRUD 无需重复编码,轻松上手

对于刚接触Go微服务开发的初学者来说,直接上手“框架+ORM”的组合常显复杂。而kratos-gorm-example项目已为我们搭建好了Go-Kratos与GORM的基础集成框架,本文将基于该项目,聚焦如何快速接入go-curd工具简化CRUD(增删改查)操作,全程以step-by-step的方式讲解,新手也能轻松跟随实操。

先明确核心工具关系:kratos-gorm-example是“基础骨架”(已整合Kratos与GORM),go-curd是“效率工具”(封装重复CRUD逻辑),我们的核心目标是“在现有骨架上装工具,让数据操作更简单”。

一、核心工具速览:3分钟理清分工

在动手前,先明确三个工具的分工,避免越做越乱:

  • Go-Kratos微服务框架核心,负责API定义、服务启动、请求分发,kratos-gorm-example已完成其基础配置;
  • GORM:ORM框架,实现Go结构体与数据库表的映射,kratos-gorm-example已完成数据库连接初始化;
  • go-crud:GORM的上层封装工具,把重复的CRUD逻辑(如创建、查询、更新、删除)做成现成方法,无需手动编写GORM原生语句。

二、环境准备:5分钟搞定前置依赖

先完成基础环境搭建和项目准备,确保后续步骤无报错:

  1. 安装基础工具:要求 Go 1.19+(Kratos 最低支持版本),安装后用go version验证;
  2. Git:用于克隆示例项目;
  3. 准备数据库:用 Postgresql(GORM 最常用的数据库),新建一个数据库(比如叫example),不用建表(后续 GORM 会自动建);
  4. 获取kratos-gorm-example项目:
    • 打开终端,执行以下命令克隆项目并进入目录:git clone https://github.com/tx7do/kratos-gorm-example.git
    • cd kratos-gorm-example
  5. 引入go-curd依赖: 在项目根目录执行命令,拉取go-curd的GORM适配模块:go get github.com/tx7do/go-curd/gorm
  6. 确认项目核心目录: 无需关注所有文件,重点记住3个核心目录(kratos-gorm-example已预设):
    • api:放 API 定义文件(.proto),用来定义 “创建用户”、“查询用户” 等接口;
    • app/user/service/internal/data/models:放数据库模型(和 MySQL 表对应);
    • app/user/service/internal/data:放业务逻辑,这里会调用 go-crud 做 CRUD。

三、核心步骤1:在kratos-gorm-example中集成go-curd

kratos-gorm-example已完成GORM的初始化配置,我们只需在现有基础上,将go-curd客户端集成进来,让业务层可以调用其简化方法。

1.1 修改数据层:集成go-curd客户端

打开app/user/service/internal/data/user.go修改代码以集成go-curd

package data

import (
  gormCurd "github.com/tx7do/go-crud/gorm"
)

type UserRepo struct {
   
    data *Data
    log  *log.Helper

    mapper     *mapper.CopierMapper[userV1.User, models.User]
    repository *gormCurd.Repository[userV1.User, models.User]
}

func NewUserRepo(data *Data, logger log.Logger) *UserRepo {
   
    l := log.NewHelper(log.With(logger, "module", "user/repo/user-service"))
    repo := &UserRepo{
   
        data:   data,
        log:    l,
        mapper: mapper.NewCopierMapper[userV1.User, models.User](),
    }

    repo.repository = gormCurd.NewRepository[userV1.User, models.User](
        repo.mapper,
    )

    repo.init()

    return repo
}

核心改动说明:新增repository字段存储go-curd客户端,通过gormCurd.NewRepository()初始化,提供方法供业务层调用。

1.2 确认数据库配置(无需修改,仅验证)

kratos-gorm-example已在configs/data.yaml中配置好数据库连接,打开文件验证:

data:
  database:
    driver: "postgres"
    source: "host=localhost port=5432 user=postgres password=*Abcd123456 dbname=example sslmode=disable"
    migrate: true

注意:将source中的user=postgres password=*Abcd123456改为自己的PostgreSQL用户名和密码,确保能连接到之前新建的example数据库。

四、核心步骤2:用go-curd实现CRUD业务逻辑

我们将以“用户模块”为例,基于项目现有的目录结构,用go-curd实现用户的增、删、改、查。kratos-gorm-example已预设部分基础代码,我们只需补充和修改。

2.1 定义用户模型(Model)

打开app/user/service/internal/data/models/user.go,定义User结构体(对应数据库中的的users表):

package models

import "gorm.io/gorm"

// User 用户信息表
type User struct {
   
    gorm.Model

    UserName string `gorm:"column:username;comment:'账号名'"`
    NickName string `gorm:"column:nickname;comment:'昵称'"`
    Password string `gorm:"column:password;comment:'登录密码'"`
}

func (u User) TableName() string {
   
    return "users"
}

说明:GORM会根据该结构体自动创建数据库表,后续我们会通过go-curd操作该模型。

2.2 编写Data层:用go-curd实现CRUD

打开app/user/service/internal/data/user.go,编写业务逻辑方法。核心优势:用go-curd的现成方法替代原生GORM代码,减少重复工作。

package data

func (r *UserRepo) List(ctx context.Context, req *pagination.PagingRequest) (*userV1.ListUserResponse, error) {
   
    if req == nil {
   
        return nil, errors.New("request is nil")
    }

    ret, err := r.repository.ListWithPaging(ctx, r.data.db, req)
    if err != nil {
   
        return nil, err
    }
    if ret == nil {
   
        return &userV1.ListUserResponse{
   Total: 0, Items: nil}, nil
    }

    return &userV1.ListUserResponse{
   
        Total: ret.Total,
        Items: ret.Items,
    }, nil
}

func (r *UserRepo) Get(ctx context.Context, req *userV1.GetUserRequest) (*userV1.User, error) {
   
    if req == nil {
   
        return nil, errors.New("request is nil")
    }

    var whereCond *gorm.DB
    switch req.QueryBy.(type) {
   
    case *userV1.GetUserRequest_Id:
        whereCond = r.data.db.Where("id = ?", req.GetId())
    case *userV1.GetUserRequest_UserName:
        whereCond = r.data.db.Where("user_name = ?", req.GetUserName())
    default:
        whereCond = r.data.db.Where("id = ?", req.GetId())
    }

    dto, err := r.repository.Get(ctx, whereCond, req.GetViewMask())
    if err != nil {
   
        return nil, err
    }

    return dto, err
}

func (r *UserRepo) Create(ctx context.Context, req *userV1.CreateUserRequest) (*userV1.User, error) {
   
    if req == nil || req.Data == nil {
   
        return nil, errors.New("request is nil")
    }

    if req.Data.Password != nil && req.Data.GetPassword() != "" {
   
        cryptoPassword, err := crypto.HashPassword(req.Data.GetPassword())
        if err != nil {
   
            return nil, err
        }
        req.Data.Password = &cryptoPassword
    }

    result, err := r.repository.Create(ctx, r.data.db, req.Data, nil)

    return result, err
}

func (r *UserRepo) Update(ctx context.Context, req *userV1.UpdateUserRequest) (*userV1.User, error) {
   
    if req == nil || req.Data == nil {
   
        return nil, errors.New("request is nil")
    }

    if req.Data.Password != nil && req.Data.GetPassword() != "" {
   
        cryptoPassword, err := crypto.HashPassword(req.Data.GetPassword())
        if err != nil {
   
            return nil, err
        }
        req.Data.Password = &cryptoPassword
    }

    result, err := r.repository.Update(ctx, r.data.db, req.Data, req.GetUpdateMask())

    return result, err
}

func (r *UserRepo) Upsert(ctx context.Context, req *userV1.UpdateUserRequest) (*userV1.User, error) {
   
    if req == nil || req.Data == nil {
   
        return nil, errors.New("request is nil")
    }

    var err error

    if req.Data.Password != nil && req.Data.GetPassword() != "" {
   
        cryptoPassword, err := crypto.HashPassword(req.Data.GetPassword())
        if err != nil {
   
            return nil, err
        }
        req.Data.Password = &cryptoPassword
    }

    result, err := r.repository.Upsert(ctx, r.data.db, req.Data, req.GetUpdateMask())

    return result, err
}

func (r *UserRepo) Delete(ctx context.Context, req *userV1.DeleteUserRequest) (bool, error) {
   
    if req == nil {
   
        return false, errors.New("request is nil")
    }

    result, err := r.repository.Delete(ctx, r.data.db.Where("id = ?", req.GetId()))

    return result > 0, err
}

核心简化点:对比原生GORM,go-curd的ListGetCreateUpdateUpsertDelete方法无需编写查询条件,直接传入上下文、模型实例和ID即可,代码更简洁。

2.3 定义API接口(Proto)并生成代码

kratos-gorm-example已在api/protos/user/service/v1/user.proto中预设了用户API定义,我们只需确认内容(无需修改),然后生成Go代码:

syntax = "proto3";

package user.service.v1;

import "gnostic/openapi/v3/annotations.proto";

import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/field_mask.proto";

import "google/api/annotations.proto";

import "pagination/v1/pagination.proto";

// 用户服务
service UserService {
  // 查询用户列表
  rpc ListUser (pagination.PagingRequest) returns (ListUserResponse) {
    option (google.api.http) = {
      get: "/users"
      additional_bindings {
        post: "/users/list"
        body: "*"
      }
    };
  }

  // 查询用户详情
  rpc GetUser (GetUserRequest) returns (User) {
    option (google.api.http) = {
      get: "/users/{id}"
      additional_bindings {
        get: "/users/username/{user_name}"
      }
    };
  }

  // 创建用户
  rpc CreateUser (CreateUserRequest) returns (User) {
    option (google.api.http) = {
      post: "/users"
      body: "*"
    };
  }

  // 更新用户
  rpc UpdateUser (UpdateUserRequest) returns (User) {
    option (google.api.http) = {
      put: "/users/{data.id}"
      body: "*"
    };
  }

  // 删除用户
  rpc DeleteUser (DeleteUserRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/users/{id}"
    };
  }
}

// 用户
message User {
  uint32 id = 1;

  optional string user_name = 2 [json_name = "userName", (gnostic.openapi.v3.property) = {description: "账户名"}];// 账户名
  optional string nick_name = 3 [json_name = "nickName", (gnostic.openapi.v3.property) = {description: "昵称"}];// 昵称
  optional string password = 4 [json_name = "password", (gnostic.openapi.v3.property) = {description: "密码"}];// 密码

  optional google.protobuf.Timestamp created_at = 200 [json_name = "createdAt", (gnostic.openapi.v3.property) = {description: "创建时间"}];// 创建时间
  optional google.protobuf.Timestamp updated_at = 201 [json_name = "updatedAt", (gnostic.openapi.v3.property) = {description: "更新时间"}];// 更新时间
  optional google.protobuf.Timestamp deleted_at = 202 [json_name = "deletedAt", (gnostic.openapi.v3.property) = {description: "删除时间"}];// 删除时间
}

// 获取用户列表 - 答复
message ListUserResponse {
  repeated User items = 1;
  uint64 total = 2;
}

// 获取用户数据 - 请求
message GetUserRequest {
  oneof query_by {
    uint32 id = 1 [
      (gnostic.openapi.v3.property) = {description: "用户ID", read_only: true},
      json_name = "id"
    ]; // 用户ID

    string user_name = 2 [
      (gnostic.openapi.v3.property) = {description: "用户登录名", read_only: true},
      json_name = "userName"
    ]; // 用户登录名
  }

  optional google.protobuf.FieldMask view_mask = 100 [
    json_name = "viewMask",
    (gnostic.openapi.v3.property) = {
      description: "视图字段过滤器,用于控制返回的字段"
    }
  ]; // 视图字段过滤器,用于控制返回的字段
}

// 创建用户 - 请求
message CreateUserRequest {
  User data = 1;

  uint32 operator_id = 2 [json_name = "operatorId", (gnostic.openapi.v3.property) = {description: "操作者用户ID"}];// 操作者用户ID
}

// 更新用户 - 请求
message UpdateUserRequest {
  User data = 1;

  google.protobuf.FieldMask update_mask = 2 [
    json_name = "updateMask",
    (gnostic.openapi.v3.property) = {
      description: "要更新的字段列表",
      example: {yaml : "id,realname,username"}
    }
  ]; // 要更新的字段列表

  optional bool allow_missing = 3 [
    json_name = "allowMissing",
    (gnostic.openapi.v3.property) = {description: "如果设置为true的时候,资源不存在则会新增(插入),并且在这种情况下`updateMask`字段将会被忽略。"}
  ]; // 如果设置为true的时候,资源不存在则会新增(插入),并且在这种情况下`updateMask`字段将会被忽略。
}

// 删除用户 - 请求
message DeleteUserRequest {
  uint32 id = 1;

  uint32 operator_id = 2 [json_name = "operatorId", (gnostic.openapi.v3.property) = {description: "操作者用户ID"}];// 操作者用户ID
}

执行以下命令生成Go代码(项目已预设make api命令):

make api

生成的代码会放在api/gen/go/user/service/v1目录下,供Data层Service层调用。

2.4 Server 层绑定接口与 Service

kratos-gorm-example 通过NewRESTServer方法完成 HTTP Server 的创建,并将 UserService 注册到 KratosHTTP 服务中,实现 API 接口与 Service 层的绑定。核心代码如下(文件路径:app/user/service/internal/server/rest.go):

// NewRESTServer new an HTTP server.
func NewRESTServer(
    cfg *conf.Bootstrap, logger log.Logger,
    userService *service.UserService,
) *http.Server {
   
    if cfg == nil || cfg.Server == nil || cfg.Server.Rest == nil {
   
        return nil
    }

    srv := bootstrap.CreateRestServer(cfg, logging.Server(logger))

    userV1.RegisterUserServiceHTTPServer(srv, userService)

    if cfg.GetServer().GetRest().GetEnableSwagger() {
   
        swaggerUI.RegisterSwaggerUIServerWithOption(
            srv,
            swaggerUI.WithTitle("Kratos GORM Example User Service API"),
            swaggerUI.WithMemoryData(assets.OpenApiData, "yaml"),
        )
    }

    return srv
}

代码说明:

  1. bootstrap.CreateRestServer:基于配置创建 Kratos 的 HTTP Server 实例,包含端口、中间件等基础配置;
  2. userV1.RegisterUserServiceHTTPServer:将实现了UserService接口的userService实例注册到 HTTP Server 中,完成 API 接口(如/users)与 Service 层方法的绑定;
  3. Swagger 相关配置:可选开启 Swagger UI,方便调试 API 接口。

此步骤无需手动修改代码(项目已实现),只需验证该文件存在且代码完整即可 —— 启动服务后,Kratos 会自动将 HTTP 请求转发到对应的 Service 层方法。

五、核心步骤3:运行项目并测试CRUD接口

所有代码修改完成后,启动项目并测试接口,验证go-curd是否正常工作。

3.1 自动创建数据库表(GORM自动迁移)

kratos-gorm-example已在app/user/service/internal/data/gorm_client.go中实现了GORM自动迁移逻辑,启动项目时会自动根据User模型创建users表

// 关键迁移代码(项目已实现)
if err := data.DB().AutoMigrate(
  &model.User{
   }, // 自动迁移User模型到数据库表
); err != nil {
   
  log.Error("迁移数据库表失败:", err)
  return err
}

3.2 启动项目

在项目的服务目录app/user/service下执行以下命令启动服务:

make run

看到终端输出下面的文本或类似日志,说明项目启动成功:

DEBUG msg=config loaded: client.yaml format: yaml
DEBUG msg=config loaded: data.yaml format: yaml
DEBUG msg=config loaded: logger.yaml format: yaml
DEBUG msg=config loaded: server.yaml format: yaml
DEBUG msg=config loaded: tracer.yaml format: yaml

3.3 测试接口(用curl或Postman)

以下用curl命令测试4个CRUD接口,确保功能正常:

1. 创建用户:

curl -X 'POST' \
  'http://localhost:7788/users' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "data": {
    "id": 0,
    "userName": "zhangsan",
    "nickName": "张三",
    "password": "123456"
  }
}'

成功响应:

{
   
  "id": 1, //(ID为自动生成的主键)。
  "userName": "zhangsan",
  "nickName": "张三",
  "password": "$2a$10$Jd34ATGgTJ2sV7xvPruMLONArXk9KYQ2O6XDY42UxVO37p5DO8CVu",
  "createdAt": "1970-01-01T00:00:00Z",
  "updatedAt": "1970-01-01T00:00:00Z"
}

2. 查询用户(使用上面返回的ID=1):

curl -X 'GET' \
  'http://localhost:7788/users/1' \
  -H 'accept: application/json'

成功响应:

{
   
  "id": 1,
  "userName": "zhangsan",
  "nickName": "张三",
  "password": "$2a$10$Jd34ATGgTJ2sV7xvPruMLONArXk9KYQ2O6XDY42UxVO37p5DO8CVu",
  "createdAt": "1970-01-01T00:00:00Z",
  "updatedAt": "1970-01-01T00:00:00Z"
}

3. 更新用户:

curl -X 'PUT' \
  'http://localhost:7788/users/1' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "data": {
    "id": 1,
    "userName": "zhangsan",
    "nickName": "张三三"
  }
}'

成功响应:

{
   
  "id": 1,
  "userName": "zhangsan",
  "nickName": "张三三",
  "password": "$2a$10$Jd34ATGgTJ2sV7xvPruMLONArXk9KYQ2O6XDY42UxVO37p5DO8CVu",
  "createdAt": "1970-01-01T00:00:00Z",
  "updatedAt": "1970-01-01T00:00:00Z"
}

4. 删除用户:

curl -X 'DELETE' \
  'http://localhost:7788/users/1' \
  -H 'accept: */*'

成功响应:

{
   }

六、新手避坑注意事项

  1. 依赖版本兼容:go-curd仅支持GORM v2版本,kratos-gorm-example已使用GORM v2,无需额外调整;若手动升级依赖,避免安装GORM v1。
  2. 数据库配置错误:务必修改configs/data.yaml中的source字段,确保MySQL用户名、密码、数据库名正确,否则会出现连接失败错误。

  3. 模型字段与Proto类型匹配:Proto中的ageint32类型,Model中的Age需对应int32(而非int),否则会出现类型转换错误。

  4. go-curd方法调用规范:调用GetDelete时,第二个参数必须是模型实例的指针(如&user),不能直接传结构体。

  5. 自动迁移仅用于开发环境:GORM的AutoMigrate仅适合开发阶段快速创建表,生产环境建议使用数据库迁移工具(如gorm-migrate)管理表结构。

七、总结

基于kratos-gorm-example项目集成go-curd的核心逻辑非常简单:在现有GORM连接基础上初始化go-curd客户端,然后用其封装的现成方法替代原生GORM CRUD代码。相比直接编写GORM代码,go-curd帮我们节省了大量重复工作,让业务逻辑更简洁。

如果需要扩展其他模块(如订单、商品),只需复制用户模块的逻辑:定义模型→在Service层用go-curd实现CRUD→绑定API接口即可。若遇到问题,可参考两个项目的官方GitHub文档(go-curd、kratos-gorm-example)获取更多细节。

目录
相关文章
|
1月前
|
前端开发 JavaScript Go
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:为什么选 Golang+Vue3 这套组合?
go-wind-admin 采用 Golang + Vue3 技术栈,融合高性能后端与高效前端生态。后端基于 go-kratos、ent/gorm 灵活适配复杂业务,前端结合 Vue3、TypeScript 与 Vben Admin,提升开发效率与可维护性,兼顾性能、扩展性与企业级需求,是中后台系统的理想选择。(239字)
231 7
|
前端开发 安全 API
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:自动化解放双手,初学者快速搭建系统并自动生成前端接口
GoWind Admin 是基于 Go-Kratos 与 Vue3 的企业级中后台框架,开箱即用,集成用户、权限、租户等核心模块。搭配 protoc-gen-typescript-http,可从 Protobuf 自动生成类型安全的前端接口,大幅降低联调成本,提升开发效率,助力初学者快速搭建系统,实现前后端高效协作。
252 0
|
1月前
|
运维 Cloud Native 应用服务中间件
阿里云微服务引擎 MSE 及 API 网关 2025 年 11 月产品动态
阿里云微服务引擎 MSE 面向业界主流开源微服务项目, 提供注册配置中心和分布式协调(原生支持 Nacos/ZooKeeper/Eureka )、云原生网关(原生支持Higress/Nginx/Envoy,遵循Ingress标准)、微服务治理(原生支持 Spring Cloud/Dubbo/Sentinel,遵循 OpenSergo 服务治理规范)能力。API 网关 (API Gateway),提供 APl 托管服务,覆盖设计、开发、测试、发布、售卖、运维监测、安全管控、下线等 API 生命周期阶段。帮助您快速构建以 API 为核心的系统架构.满足新技术引入、系统集成、业务中台等诸多场景需要。
阿里云微服务引擎 MSE 及 API 网关 2025 年 11 月产品动态
|
1月前
|
消息中间件 安全 中间件
微服务技术选型:从生态架构视角看go-kratos的不可替代性
本文从生态架构视角解析go-kratos在Go微服务中的不可替代性,剖析其“核心-扩展-应用”三层协同体系,展现其在统一架构、降低集成成本、全场景适配与长期迭代中的综合优势,为技术选型提供深层决策依据。
134 3
|
1月前
|
人工智能 运维 Serverless
AgentScope 拥抱函数计算 FC,为 Agent 应用提供 Serverless 运行底座
AgentScope推出Serverless运行时,直面AI Agent部署成本高、运维复杂、资源利用率低三大痛点。通过“按需启动、毫秒弹性、零运维”架构,实现低成本、高弹性、强隔离的智能体部署,助力多智能体应用从实验迈向规模化落地。
|
2月前
|
人工智能 Java API
Java 正式进入 Agentic AI 时代:Spring AI Alibaba 1.1 发布背后的技术演进
Spring AI Alibaba 1.1 正式发布,提供极简方式构建企业级AI智能体。基于ReactAgent核心,支持多智能体协作、上下文工程与生产级管控,助力开发者快速打造可靠、可扩展的智能应用。
2409 43
|
2月前
|
存储 安全 API
微服务安全之 OAuth2 协议深度解析:从原理到实战落地
本文深入解析OAuth2协议在微服务安全中的应用,涵盖核心概念、四种授权模式(授权码、简化、密码、客户端凭证)、令牌机制(JWT结构、存储管理)、资源服务器实现及安全最佳实践,结合Spring Security实战代码,助力开发者构建安全可靠的系统。
452 4
|
1月前
|
人工智能 BI 开发工具
适合个人开发者的5款开发工具,开发者必须知道
2025年,个人开发者迎来工具黄金时代。本文精选5款高效开发利器:GitHub Copilot(AI智能编程)、Trae(中文友好)、Cursor(项目级理解)、VS Code(开源全能)和Zoho Creator(低代码平台),覆盖从代码生成到应用搭建,助你提升效率,快速实现创意。
585 3
|
7月前
|
JSON API Go
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:集成 Swagger UI 打造交互式 API 文档
GoWind Admin(风行)是基于 Kratos 的企业级中后台框架,集成 Swagger UI 实现交互式 API 文档。通过 Protobuf 自动生成 OpenAPI v3 规范文档,利用 `//go:embed` 嵌入服务,一键部署可视化调试界面,提升前后端协作效率,开箱即用。
433 1
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:集成 Swagger UI 打造交互式 API 文档
|
1月前
|
人工智能 运维 监控
开源项目分享 : Gitee热榜项目 2025-12-13 日榜
本文整理Gitee当日热门开源项目,涵盖AI智能体、低代码开发、数字人、容器化部署等前沿技术。聚焦智能化、降本增效与垂直场景应用,展现AI工程化、全栈融合与技术普惠趋势,助力开发者把握开源脉搏。
229 15