Skip to content

go-lazy-frame/go-lazy-frame

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoLazyFrame 懒人框架

偷懒,是程序员的基本守则

[TOC]

依赖包网络加速

# 永久生效
go env -w GOPROXY=https://goproxy.cn,direct
# 环境变量生效
export GOPROXY=https://goproxy.cn

环境配置

  • 配置项
配置项 说明
projectHome 项目根目录的绝对目录路径(或项目启动时的工作目录为项目的根目录),如果不配置,启动时无法自动更新接口文档,例如 /home/user/go-project/my-app
docsPath 需要自动更新接口文档定义的 go 文件源码位置,例如 {ProjectHome}/internal/router/docs.go,可使用 {ProjectHome} 代表上面配置的路径
RUN_ENV 有三个值:prod、dev、local,分别代表线上环境、开发环境、本地环境。本地环境代表本地开发时的环境,dev 和 prod 代表不同的运行环境(二进制运行)
ENV_Xxx 启动时,动态根据环境变量 ENV_XxxXxx 为对应的具体配置名),更新配置,如 ENV_EnableMon=true,则代表系统配置EnableMon在运行时应用为 true
  • 配置方式

    image-20211009204418186

特性

  • 【代码生成】代码一体化自动生成

  • 【接口文档】

    • 超有好的接口文档,免除和前端的接口对接工作,例如:
    • image-20211125133210425
    • 接口文档自动生成并更新,无需执行 swag init(开发时要配置 project.home 环境变量)
  • 【对运维更加友好的系统配置】

    • 启动时,只需要在环境变量中设置 ENV_xxx(xxx 为对应的具体配置名),即可改变对应的配置参数。
    • 系统可内置三个环境配置(proddevlocal),并可通过环境变量RUN_ENV指定启动时的环境配置。
  • 【日志】

    • 使用zap 日志框架,高性能,对日志文件进行自动分割和控制日志文件占用的存储空间。

性能比较

在相同硬件条件下的路由访问测试:

image-20211002180553425

  • x1:本框架的路由注册
  • x2:gin 原本的路由注册

可以看出,没有性能损耗

项目结构介绍

介于以下几点:

  • Golang 的包管理不完善,特别是企业的开发,依赖管理很不友好。不过 Golang 的包管理,对于开源项目,却是比较友好
  • 接口文档自动生成。目前业界都是用 swagger 进行文档接口文档的自动化管理。但是 Golang 的 swagger 支持,很不友好,虽然本框架进行了最大程序的自动化集成和改造,但是依然需要手动指定所有源码文件位置(当然,在项目规范下,该操作已自动化进行,无需开发人员介入)

所以不同的项目,以及框架,都统一在一个项目中。通过目录结构的区分,以及自动代码的生成系统,进行高效率的开发。这样,框架的维护和公共代码的及时同步更新,也能得到及时的应用。

项目结构,总体遵循 project-layout 目录规范,该规范是目前 Golang 开发者,最公认的目录规范,对于 Golang 语言开发,也是比较合理的目录规范,在此之上,根据项目和框架的实际情况,做一些相应的调整。

代码生成(重要)

介于 Golang 的语言特点,Golang 的框架,提高自动化的开发效率,都是通过代码生成的途径,毕竟,Golang 语言的反射机制…..(此处就不吐槽了)。代码自动生成使用:

# 1. cd 进入到应用项目的同级目录,比如应用目录为 $GOPATH/src/my-app,则 cd 到 $GOPATH/src
# 2. 拉取代码生成系统,若 github 速度慢,也可从 gitee 仓库拉取:
git clone https://github.com/go-lazy-frame/go-lazy-frame-generate.git
# git clone https://gitee.com/go-lazy-frame/go-lazy-frame-generate.git
cd go-lazy-frame-generate
# 3. 查看 README.md 说明

开发规范(重要)

通用规范

  1. DTO 和 VO 的定义:

    1. DTO:接口请求的参数封装;
    2. VO:接口响应的参数封装
  2. 公共服务方法,例如 util 等,使用结构体方法进行定义,并且结构体私有,同时使用公开的变量供外部访问,例如:

    var (
      // 供外部调用
      MyUtil = new(myUtil)
    )
    type myUtil struct {}
    func (me *myUtil) MyFun() {}
  3. 每个表设计时,必须有以下几个字段和定义:

    create table xxx_xxx
    (
        id         bigint unsigned auto_increment primary key,
        created_at datetime(3) null,
        updated_at datetime(3) null,
        deleted_at datetime(3) null,
        index `index_deleted_at` (`deleted_at`)
    ) ENGINE = InnoDB
      DEFAULT CHARSET = utf8mb4
      COLLATE = utf8mb4_0900_ai_ci COMMENT ='';
  4. 表字段规范:

    1. 如果是关联其他表 ID 的字段,列名必须用 _id结尾,若不遵守该规则,在代码自动生成时,会影响字段的类型定义。
    2. 主键列一律使用 bigint 类型
  5. 不建议修改编辑 gen_ 开头的代码文件(若有特殊的业务情况要修改,修改操作也是生效的,不过要防止被再次生成覆盖,以及表结构变更时注意手动维护代码):

    1. 该代码文件内有 Code generated by LazyFrame Gen tool. DO NOT EDIT.的提示注释,并且如果编辑,开发工具也会有提示:

image-20211009193046118

  1. 数据库表(实体)结构变更:
    1. 修改对应的表结构,然后通过代码生成工具进行自动代码生成,变更代码实体以及相关的基础代码,请勿直接修改实体
  2. 创建表时,必须要有表注释,简短就行,不宜过长,否则自动生成的接口文档不友好

Controller 规范

代码生成工具,会自动给每一个实体(表)自动生成一个 controller,并同时注册到路由中。具体代码,可参考自动生成的代码。

  1. 一个 controller 即为定义一个struct,每个接口都是一个 struct

  2. controller struct 要注册在 router.go 的路由中

  3. 每一个struct接口方法,都要对应一个 WebXxx 的字段定义(其中的 Xxx 为对应的 struct 方法,既访问的接口方法),用于描述该接口的定义,如:

    1. type SandCar struct {
      	...
      	WebCreate interface{} `url:"/sand_car/create" method:"post"`
        ...
      }
      
      func (me SandCar) Create(c *gin.Context) {
      }
  4. 接口方法,需要用注释进行接口文档定义,项目启动时,会自动更新接口文档,如(注意@id@Router这两个的对应调整):

    1. // Create
      // 注意:以下的 id 必须设置,且必须全局唯一,否则接口文档页面无法正常显示
      // @id SandCarCreateUsingPOST
      // @Tags 车辆
      // @Summary 车辆创建
      // @Description 车辆创建
      // @Accept json
      // @Produce  json
      // @Param token header string true "登陆成功后的授权 Token,后续的所有接口header,都要带上 token"
      // @Param request body dto.SandCarDto{} true "创建"
      // 		参数名 参数类型 参数对象类型 是否必传 描述
      // @Success 200 {object} web.ResponseResult{}
      // @Failure 500 {object} web.ResponseResult{}
      // @Router /sand_car/create [post]
      func (me SandCar) Create(c *gin.Context) {
      	d := dto.SandCarDto{}
      	if err := c.ShouldBind(&d); err != nil {
      		me.Failed(c, err.Error())
      		return
      	}
      	err := service.SandCarService.CreateSandCar(d)
      	if err != nil {
      		me.Failed(c, err.Error())
      		return
      	}
      	me.Success(c, "OK")
      }
  5. 除 GET 方法外,统一使用POST body 体传 JSON 的方式,进行参数传递,并且结构体的对象数据获取,统一使用结构体方法:me.BindBodyJson(c, &d),如:

    ...	
    d := RbacLogUpdateDto{}
    if err := me.BindBodyJson(c, &d); err != nil {
      me.Failed(c, err.Error())
      return
    }
    ...