Go语言微服务框架 - 7.Gormer-自动生成代码的初体验

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 作为一名程序员,我们总是希望能有更简单的开发方式来解决重复性的工作问题。在这个小版本中,我将结合自己的工作,来给出一套自动生成代码的完整方案,供大家借鉴。

CRUD是贯穿整个程序员日常开发的基本工作,占据了我们绝大多数的coding时间。

作为一名程序员,我们总是希望能有更简单的开发方式来解决重复性的工作问题。在这个小版本中,我将结合自己的工作,来给出一套自动生成代码的完整方案,供大家借鉴。

v0.5.1:Gormer-自动生成代码的初体验

项目链接 https://github.com/Junedayday/micro_web_service/tree/v0.5.1

目标

自动生成一套可用的Dao层代码,兼容原始版本。

关键技术点

  1. Go Template技术概览
  2. gormer工具核心思路
  3. gormer的模板填充

目录构造

--- micro_web_service            项目目录
    |-- gen                            从idl文件夹中生成的文件,不可手动修改
       |-- idl                             对应idl文件夹
          |-- demo                             对应idl/demo服务
             |-- demo.pb.go                        demo.proto的基础结构
             |-- demo.pb.gw.go                     demo.proto的HTTP接口,对应gRPC-Gateway
             |-- demo_grpc.pb.go                   demo.proto的gRPC接口代码
            |-- order                            对应idl/order服务
             |-- order.pb.go                       order.proto的基础结构
             |-- order.pb.gw.go                    order.proto的HTTP接口,对应gRPC-Gateway
             |-- order_grpc.pb.go                  order.proto的gRPC接口代码
    |-- idl                            原始的idl定义
       |-- demo                            业务package定义
          |-- demo.proto                       protobuffer的原始定义
       |-- order                           业务order定义
          |-- order.proto                      protobuffer的原始定义
    |-- internal                       项目的内部代码,不对外暴露
       |-- config                          配置相关的文件夹
          |-- viper.go                         viper的相关加载逻辑
       |-- dao                             Data Access Object层
          |-- order.go                         Order对象,订单表,实现model层的OrderRepository
          |-- order_test.go                    Order的单元测试
       |-- gormer                          新增:从pkg/gormer中生成的相关代码,不允许更改
          |-- order.go                         新增:gormer从orders表中获取的真实Gorm结构体
       |-- model                           model层,定义对象的接口方法
          |-- order.go                         OrderRepository接口,具体实现在dao层
       |-- mysql                           MySQL连接
          |-- init.go                          初始化连接到MySQL的工作
       |-- server                          服务器的实现
          |-- demo.go                          server中对demo这个服务的接口实现
          |-- server.go                        server的定义,须实现对应服务的方法
       |-- service                         service层,作为领域实现的核心部分
          |-- order.go                         Order相关的服务,目前仅简单的CRUD
     |-- zlog                            封装日志的文件夹
        |-- zap.go                           zap封装的代码实现
  |-- pkg                            新增:开放给第三方的工具库
     |-- gormer                          新增:gormer工具,用于生成Gorm相关Dao层代码
    |-- buf.gen.yaml                   buf生成代码的定义,从v1beta升到v1
    |-- buf.yaml                       buf工具安装所需的工具,从v1beta升到v1
    |-- gen.sh                         更新:生成代码的脚本:buf+gormer
    |-- go.mod                         Go Module文件
    |-- main.go                        项目启动的main函数

1.Go Template技术概览

Go的标准库提供了Template功能,但网上的介绍很零散,我建议大家可以阅读以下两篇资料:

这里,为了方便大家阅读下面的内容,我简要概括下:

  1. 结构体中字段填充 { { .FieldName }}
  2. 条件语句 { {if .FieldName}} // action { { else }} // action 2 { { end }}
  3. 循环 { {range .Member}} ... { {end}}
  4. 流水线 { { with $x := <^>result-of-some-action<^> }} { { $x }} { { end }}

很多资料会很自然地将Go Template和HTML结合起来,但这只是模板的其中一个用法。

HTML的结构用模板化的方式可以减少大量重复性的代码,但这种思路是前后单不分离的,个人不太推荐。

2.gormer工具核心思路

在pkg/gormer目录下提供了一个gormer工具,用于自动生成代码,我对主流程进行简单地讲解:

  1. 解析各种关键性的参数
  2. 连接测试数据库,获取表信息
  3. 逐个处理每个表
    1. 读取数据库中的表结构
    2. 根据表结构生成对应的Go语言结构体,放在internal/gormer下
    3. 生成相关的Dao层代码,放在internal/dao下
  4. 执行go fmt格式化代码

其中最关键的是3-b与3-c,它们是生成代码的最关键步骤。我们来看一个关键性的结构体:

// 结构体名称,对应MySQL表级别的信息
type StructLevel struct {
   
    TableName      string
    Name           string
    SmallCamelName string
    Columns        []FieldLevel
}

// Field字段名称,对应MySQL表里Column
type FieldLevel struct {
   
    FieldName string
    FieldType string
    GormName  string
}

3.gormer的模板填充

结合1、2,我们可以开始生成模板的部分,具体的Template代码如下,它会将StructLevel这个结构体中的字段填充到下面内容中,生成go文件。

var gormerTmpl = `
// Table Level Info
const {
   {.Name}}TableName = "{
   {.TableName}}"

// Field Level Info
type {
   {.Name}}Field string
const (
{
   {range $item := .Columns}}
    {
   {$.Name}}Field{
   {$item.FieldName}} {
   {$.Name}}Field = "{
   {$item.GormName}}" {
   {end}}
)

var {
   {$.Name}}FieldAll = []{
   {$.Name}}Field{ {
   {range $k,$item := .Columns}}"{
   {$item.GormName}}", {
   {end}}}

// Kernel struct for table for one row
type {
   {.Name}} struct { {
   {range $item := .Columns}}
    {
   {$item.FieldName}}    {
   {$item.FieldType}}    ` + "`" + `gorm:"column:{
   {$item.GormName}}"` + "`" + ` {
   {end}}
}

// Kernel struct for table operation
type {
   {.Name}}Options struct {
    {
   {.Name}} *{
   {.Name}}
    Fields []string
}

// Match: case insensitive
var {
   {$.Name}}FieldMap = map[string]string{
{
   {range $item := .Columns}}"{
   {$item.FieldName}}":"{
   {$item.GormName}}","{
   {$item.GormName}}":"{
   {$item.GormName}}",
{
   {end}}
}

func New{
   {.Name}}Options(target *{
   {.Name}}, fields ...{
   {$.Name}}Field) *{
   {.Name}}Options{
    options := &{
   {.Name}}Options{
        {
   {.Name}}: target,
        Fields: make([]string, len(fields)),
    }
    for index, field := range fields {
        options.Fields[index] = string(field)
    }
    return options
}

func New{
   {.Name}}OptionsAll(target *{
   {.Name}}) *{
   {.Name}}Options{
    return New{
   {.Name}}Options(target, {
   {$.Name}}FieldAll...)
}

func New{
   {.Name}}OptionsRawString(target *{
   {.Name}}, fields ...string) *{
   {.Name}}Options{
    options := &{
   {.Name}}Options{
        {
   {.Name}}: target,
    }
    for _, field := range fields {
        if f,ok := {
   {$.Name}}FieldMap[field];ok {
             options.Fields = append(options.Fields, f)
        }
    }
    return options
}
`

生成的代码如下:

// Code generated by gormer. DO NOT EDIT.
package gormer

import "time"

// Table Level Info
const OrderTableName = "orders"

// Field Level Info
type OrderField string

const (
    OrderFieldId         OrderField = "id"
    OrderFieldName       OrderField = "name"
    OrderFieldPrice      OrderField = "price"
    OrderFieldCreateTime OrderField = "create_time"
)

var OrderFieldAll = []OrderField{
   "id", "name", "price", "create_time"}

// Kernel struct for table for one row
type Order struct {
   
    Id         int64     `gorm:"column:id"`
    Name       string    `gorm:"column:name"`
    Price      float64   `gorm:"column:price"`
    CreateTime time.Time `gorm:"column:create_time"`
}

// Kernel struct for table operation
type OrderOptions struct {
   
    Order  *Order
    Fields []string
}

// Match: case insensitive
var OrderFieldMap = map[string]string{
   
    "Id": "id", "id": "id",
    "Name": "name", "name": "name",
    "Price": "price", "price": "price",
    "CreateTime": "create_time", "create_time": "create_time",
}

func NewOrderOptions(target *Order, fields ...OrderField) *OrderOptions {
   
    options := &OrderOptions{
   
        Order:  target,
        Fields: make([]string, len(fields)),
    }
    for index, field := range fields {
   
        options.Fields[index] = string(field)
    }
    return options
}

func NewOrderOptionsAll(target *Order) *OrderOptions {
   
    return NewOrderOptions(target, OrderFieldAll...)
}

func NewOrderOptionsRawString(target *Order, fields ...string) *OrderOptions {
   
    options := &OrderOptions{
   
        Order: target,
    }
    for _, field := range fields {
   
        if f, ok := OrderFieldMap[field]; ok {
   
            options.Fields = append(options.Fields, f)
        }
    }
    return options
}

dao层的代码逻辑类似,我就不重复填写了。

这里,我将代码拆分成了gormer与dao两层,主要是:

  • internal/gormer整个目录是不可变的、只能自动生成,对应基础的数据库表结构
  • internal/dao层会添加其余的文件,如定制化的sql。

至此,再将引用的相关代码简单修改,就实现了这一整块功能.

总结

本章重点介绍了Go Template在高度重复的代码模块中的应用,结合数据库实现了一个高度自动化的工具gormer。

gormer目前实现的功能比较单一,但只要有了初步自动化的思路,我们可以在后续迭代中慢慢优化,让它适应更多的场景。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
JavaScript Java Go
探索Go语言在微服务架构中的优势
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出。本文将深入探讨Go语言在构建微服务时的性能优势,包括其在内存管理、网络编程、并发模型以及工具链支持方面的特点。通过对比其他流行语言,我们将揭示Go语言如何成为微服务架构中的一股清流。
151 53
|
2月前
|
开发框架 Go 计算机视觉
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C++ 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。此外,在许多情况下,在各种平台上安装 OpenCV 是很麻烦的。使用纯Go开发的插件不仅在开发时方便,在项目部署和项目维护也能省很多时间精力。
|
3月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
183 4
|
3月前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
190 1
|
3月前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
3月前
|
Go 数据处理 API
Go语言在微服务架构中的应用与优势
本文摘要采用问答形式,以期提供更直接的信息获取方式。 Q1: 为什么选择Go语言进行微服务开发? A1: Go语言的并发模型、简洁的语法和高效的编译速度使其成为微服务架构的理想选择。 Q2: Go语言在微服务架构中有哪些优势? A2: 主要优势包括高性能、高并发处理能力、简洁的代码和强大的标准库。 Q3: 文章将如何展示Go语言在微服务中的应用? A3: 通过对比其他语言和展示Go语言在实际项目中的应用案例,来说明其在微服务架构中的优势。
|
3月前
|
安全 Go 开发者
代码之美:Go语言并发编程的优雅实现与案例分析
【10月更文挑战第28天】Go语言自2009年发布以来,凭借简洁的语法、高效的性能和原生的并发支持,赢得了众多开发者的青睐。本文通过两个案例,分别展示了如何使用goroutine和channel实现并发下载网页和构建并发Web服务器,深入探讨了Go语言并发编程的优雅实现。
48 2
|
4月前
|
Cloud Native Go API
Go语言在微服务架构中的创新应用与实践
本文深入探讨了Go语言在构建高效、可扩展的微服务架构中的应用。Go语言以其轻量级协程(goroutine)和强大的并发处理能力,成为微服务开发的首选语言之一。通过实际案例分析,本文展示了如何利用Go语言的特性优化微服务的设计与实现,提高系统的响应速度和稳定性。文章还讨论了Go语言在微服务生态中的角色,以及面临的挑战和未来发展趋势。
|
3月前
|
SQL 监控 算法
为Go应用无侵入地添加任意代码
这篇文章旨在提供技术深度和实践指南,帮助开发者理解并应用这项创新技术来提高Golang应用的监控与服务治理能力。在接下来的部分,我们将通过一些实际案例,进一步展示如何在不同场景中应用这项技术,提供更多实践启示。
|
4月前
|
运维 Go 开发者
Go语言在微服务架构中的应用与优势
本文深入探讨了Go语言在构建微服务架构中的独特优势和实际应用。通过分析Go语言的核心特性,如简洁的语法、高效的并发处理能力以及强大的标准库支持,我们揭示了为何Go成为开发高性能微服务的首选语言。文章还详细介绍了Go语言在微服务架构中的几个关键应用场景,包括服务间通信、容器化部署和自动化运维等,旨在为读者提供实用的技术指导和启发。