该功能特性从v2.1版本开始提供。

基本介绍

设计背景

在业务项目实践中,业务逻辑封装往往是最复杂的部分,同时,业务模块之间的依赖十分复杂、边界模糊,无法采用Golang包管理的形式。如何有效管理项目中的业务逻辑封装部分,对于每个采用Golang开发的项目都是必定会遇到的难题。

设计目标

  1. 增加logic分类目录,将所有业务逻辑代码迁移到logic分类目录下,采用包管理形式来管理业务模块。
  2. 业务模块之间的依赖通过接口化解耦,将原有的service分类调整为接口目录。这样每个业务模块将会各自维护、更加灵活。
  3. 可以按照一定的项目规范,从logic业务逻辑代码生成service接口定义代码。同时,也允许人工维护这部分service接口。

命令使用

该命令通过分析给定的logic业务逻辑模块目录下的代码,自动生成service目录接口代码。

需要注意:

  1. 由于该命令是根据业务模块生成service接口,因此只会解析二级目录下的go代码文件,并不会无限递归分析代码文件。以logic目录为例,该命令只会解析logic/xxx/*.go文件。因此,需要logic层代码结构满足一定规范。
  2. 不同业务模块中定义的结构体名称在生成的service接口名称时可能会重复覆盖,因此需要在设计业务模块时保证名称不能冲突。

手动模式

如果是手动执行命令行,直接在项目根目录下执行 gf gen service 即可。

$ gf gen service -h
USAGE
    gf gen service [OPTION]

OPTION
    -s, --srcFolder      source folder path to be parsed. default: internal/logic
    -d, --dstFolder      destination folder path storing automatically generated go files. default: internal/service
    -w, --watchFile      used in file watcher, it generates service go files only if given file is under srcFolder
    -a, --stPattern      regular expression matching struct name for generating service. default: s([A-Z]\w+)
    -p, --packages       produce go files only for given source packages, multiple packages joined with char ','
    -i, --importPrefix   custom import prefix to calculate import path for generated importing go file of logic
    -o, --overwrite      overwrite service go files that already exist in generating folder. default: true
    -h, --help           more information about this command

参数说明:

名称必须默认值含义
srcFolderinternal/logic指向logic代码目录地址
dstFolderinternal/service指向生成的接口文件存放目录
stPatterns([A-A]\w+)

使用正则指定业务模块结构体定义格式,便于解析业务接口定义名称。在默认的正则下,所有小写s开头,大写字母随后的结构体都将被当做业务模块接口名称。例如:

logic结构体名称service接口名称
sUserUser
sMetaDataMetaData
watchFile

用在代码文件监听中,代表当前改变的代码文件路径

packages

仅生成指定包名的接口文件,给定字符串数组,通过命令行传参则给定JSON字符串,命令行组件自动转换数据类型
importPrefix

指定生成业务引用文件中的引用包名前缀
overwrite
true生成代码文件时是否覆盖已有文件

自动模式

如果您是使用的GolandIDE,那么可以使用我们提供的配置文件:watchers.xml  自动监听代码文件修改时自动生成接口文件。使用方式,如下图:

具体使用手摸手

Step1:引入我们提供的配置

我们建议您在使用Goland IDE时,使用我们提供的配置文件:watchers.xml 

Step2:编写您的业务逻辑代码

Step3:生成接口及服务注册文件

如果您已经按照Step1做好了配置,那么这一步可以忽略。因为在您编写代码的时候,service便同时生成了接口定义文件。

否则,每一次在您开发/更新完成logic业务模块后,您需要手动执行一下 gf gen service 命令。

Step4:注意服务的实现注入部分(仅一次)

只有在生成完成接口文件后,您才能在每个业务模块中加上接口的具体实现注入。该方法每个业务模块加一次即可。

Step5:在启动文件中引用接口实现注册(仅一次)

可以发现,该命令除了生成接口文件之外,还生成了一个接口实现注册文件。该文件用于在程序启动时,将接口的具体实现在启动时执行注册。

该文件的引入需要在main包的最顶部引入,需要注意import的顺序,放到最顶部,后面加一个空行。如果同时存在packed包的引入,那么放到packed包后面。像这样:

Step6:Start&Enjoy

启动main.go即可。

常见问题FAQ

快速定位接口的具体实现

项目业务模块采用接口化解耦后体验非常棒!但是我在开发和调试过程中,想要快速找到指定接口的具体实现有点困难,能给点指导思路吗?

> 这里我推荐使用Goland IDE,有个很棒的接口实现定位功能,具体如图。找到接口定义后,点击左边的小图标可快速定位具体的实现。如果Goland不显示小图标,可以尝试升级使用最新版本的Goland哈。






Content Menu

  • No labels

20 Comments

  1. // ==========================================================================
    // Code generated by GoFrame CLI tool. DO NOT EDIT.
    // ==========================================================================

    package service

    import (
    "context"
    "pms/internal/consts"
    "pms/internal/dao"
    "pms/internal/model"
    "pms/internal/model/do"
    "pms/internal/model/entity"
    "pms/utility"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/grpool"
    )

    生成的service 文件的import 部分不正确是什么原因呢?
    1. GF Version:  v2.1.2 已经解决.

  2. 生成service的文件名全是小写,是不是应该与service保持一致.

    1. 针对这个问题有给强哥提了PR,希望能被合并~
      https://github.com/gogf/gf/pull/1953

      1. 我看了代码,好像是刻意转成小写的呢.另外请教您一下.我测试时生成的service会一些用不到的包,这个您了解是什么问题吗?

        1. 强哥说是bug,目前可以通过 goimports 工具自动清理多出包。

    2. GF Version:  v2.1.2 已经解决.

  3. 生成service时,没有判断逻辑代码是否注释.即使注释的方法也会生成;

  4.  这里我推荐使用GolandIDE,有个很棒的接口实现定位功能,具体如图。找到接口定义后,点击左边的小图标可快速定位具体的实现。

    Code generated by GoFrame CLI tool. DO NOT EDIT.

    老大,这个要把生成的头部修改一下,小图标才能出现.有上边这个就没有小图标.

  5. 自定义目录,会提示:

    source folder path "internal/logic" does not exist

  6. 郭强 强仔  郭老板 您的GolandIDE 什么版本的,我这没有你说的那个小图标呀?

  7. 强仔  把文件的

    Code generated by GoFrame CLI tool. DO NOT EDIT.  删除了就有小图标了!
  8. 请问我用gf gen service 为什么生成不了service文件,都需要哪些步骤 

    logic 文件已经写好了

    ll internal/logic/
    drwxr-xr-x  3 root root 4096 Sep 16 17:18 ./
    drwxr-xr-x 11 root root 4096 Sep 14 15:51 ../
    drwxr-xr-x  2 root root 4096 Sep 16 17:18 camera_type/


    gf gen service
    done!

    只是返回了done 然后就没了

    servcice还是空的


  9. 你的那个是手动执行,自动不香么。。。
    但我的也是,怀疑是作者偷懒。你需要自己先写一下注入和接口名称,将接口和实现函数关联(就是类似java中的构造方法,我总是搞混,魔怔了),然后你改动logic中实现方法,就会自动自动创建service中接口,不需要每次都改。

    1. 谢谢回复,不用自动是因为电脑用goland占用内存太大,然后我这这边排查了下,发现问题有个logic的返回值少了一个空格,这可太难受了

  10. 想问一个先有蛋,还是先有鸡的问题:

    要生成 service ,就要写 logic,但是 logic 里又有 service相关的引用和代码

    那是不是意味着要先写 logic ,生成 service, 再把相关的servicer的代码再补上,这样操作是不是有点繁琐了

    能否考虑以下方法:

    使用 gf gen service -s srcDir -d dstDir 命令,直接生成 logic和service,然后在丰富logic的过程中,自动gen service ,这样是不是只需要专注 logic ,而增加了 service的自动化

    另外一直使用 vscode,不知道vscode有没有自动化脚本。


    1. 对于goland service这层是不需要手动维护的 说白点也就是只管写logic保存下就自动更新service了

      1. func init() {

        service.RegisterUser(New())

        }

        func New() service.IUser {
        return &sUser{}
        }

        service自动更新我理解,想问一下logic里这二段代码怎么解耦。我有疑问的地方也是这里

        我现在的步骤是先写 logic,但是不写 init 和 new 。生成 service后,再回来写 init 和 new 

        这样感觉怪怪的,如果是 gf gen service -s srcDir -d dstDir 命令,直接生成 logic和service 一步直接生成这二个文件的简体,后面只需要给logic加内容,再自动gen service是不是更合理一些。

        1. 可以简化下

          func init() {

          service.RegisterUser(&sUser{})

          }

          因为service是interface也就是可以多实现,在有多实现的时候必定要手动声明注册哪个实现.只是说你是单一实现看着有点多余罢了,简化后实质也只需写一个init表明用该接口实现

          1. 明白了,感谢回复