写在前面(文末送书!点赞或是评论本博客即可参与送书活动!)

最近在做毕设,前台做完了,现在要开始搭建后台系统了,而后台系统,又大多数是固定的模版。
所以为了方便摸鱼,顺便写一个可以 自动生成模版 的代码工具

开源地址:https://github.com/CocaineCong/fgen

1. 项目生成

1.1 项目结构

目前只支持生成单体式的项目结构目录,后续会更新微服务分布式的目录生成

效果如下

那么首先,我现阶段所了解的项目目录结构是一下结构:

demo/├── api // 暴露出api接口,承接router转发的请求道service层├── cmd // 项目启动├── config // 配置文件存放├── consts // 定义常量├── loading // 加载配置├── middleware // 中间件├── repository //持久层│  ├── db // 数据库│  │  ├── dao // dao层│  │  └── model // 一些定义的 struct 模型│  └── redis // 缓存或是redis├── test // test测试文件├── pkg // 存放一些配置│  ├── e 
│  └── util
├── router // 路由 ├── types // 类型转换├── serializer // 一些序列化,将数据传送给前端└── service // 服务层

1.2 生成目录

传入 project 的 path 以及 path 的 name ,用一个数组将这些目录存起来,因为对于一些特殊的目录,还要生成二级目录,或者是一些必备的文件,比如说 config 目录下的 .yaml 文件。

func GenProject(projectPath, projectName string) error {if projectPath == "" {
		projectPath = "./"}if projectName == "" {// 外层能保证不为空
		projectName = "demo/"}

	genApiPath := projectPath + projectName + "api/"
	genCmdPath := projectPath + projectName + "cmd/"
	genConfigPath := projectPath + projectName + "config/"
	genConstsPath := projectPath + projectName + "consts/"
	genLoadingPath := projectPath + projectName + "loading/"
	genMiddlewarePath := projectPath + projectName + "middleware/"
	genPkgPath := projectPath + projectName + "pkg/"
	genRepositoryPath := projectPath + projectName + "repository/"
	genRouterPath := projectPath + projectName + "router/"
	genSerializerPath := projectPath + projectName + "serializer/"
	genServicePath := projectPath + projectName + "service/"
	genTestPath := projectPath + projectName + "test/"
	genTypesPath := projectPath + projectName + "types/"
	genModsPath := projectPath + projectName + "go.mod"
	genPaths := []string{genApiPath, genCmdPath, genConfigPath, genConstsPath, genLoadingPath, genMiddlewarePath, genPkgPath, genRepositoryPath, genRouterPath, genSerializerPath, genServicePath, genTestPath, genTypesPath, genModsPath}}

1.3 config 配置文件生成

我们逐个遍历上面的数组列表,会针对一些特定特殊的 path 进行操作。比如这个config,我们会生成对应的config.yaml 配置文件

case genConfigPath:if err := gfile.Mkdir(genConfigPath); err != nil {
		glog.Fatal("mkdir for generating path:%s failed: %v", genPath, err)}if err := gfile.Mkdir(genConfigPath + "local/"); err != nil {
		glog.Fatal("mkdir for generating path:%s failed: %v", genPath, err)}
	yamlPath := genConfigPath + "local/config.yaml"
	entityContent := gstr.ReplaceByMap(configYamlTemplate, g.MapStrStr{"{domain}": projectName[:len(projectName)-1],})if err := writeFile(yamlPath, entityContent); err != nil {return err	}

	entityContent = strings.Replace(configGolangTemplate, "'", "`", -1)
	configGo := genConfigPath + "config.go"if err := writeFile(configGo, entityContent); err != nil {return err	}

以下就是yaml文件的生成代码文件模版,如果需要什么再往上面加就好了。

const configYamlTemplate = `
system:
  domain: {domain}
  version: 1.0
  appEnv: "test"
  HttpPort: ":4000"
  Host: "localhost"

mysql:
  default:
    dialect: "mysql"
    host: "127.0.0.1"
    port: "3306"
    dbName: "hello_story"
    user: "root"
    password: "root"
    charset: "utf8mb4"

redis:
  name: 1
  address: 127.0.0.1:6379
  password: 
`
{domain}

可以使用以下方法,对模版内容进行填充。

entityContent := gstr.ReplaceByMap(configYamlTemplate, g.MapStrStr{"{domain}": projectName[:len(projectName)-1],})

1.4 生成go mod文件

由于go mod 文件的特殊性,我们要先获取系统的go版本。

func getGolangVersion() (string, error) {
	ver := runtime.Version()if ver != "" {return ver[2:6], nil}return "", errors.New("golang 环境不存在")}
go mod tidy

1.5 脚本执行

由于引入了第三方包,所以我们最终还是要 go mod tidy 一下。

先测试网络环境

pingCmd := exec.Command("ping", "-c 5 baidu.com")_, err := pingCmd.CombinedOutput()if err != nil {
	fmt.Println("err", err)return err}
start.sh
cd {path}go env -w GOPROXY=,direct
go mod tidy
go mod tidy

下一步的话呢,打算把 model 也放进来,打通一下 model 层面的自动生成,curd的代码。