重构整体的结构

按照功能进行分块

init 函数会自动

是的,init 函数会自动执行。在 Go 中,init 函数是一种特殊的函数,它会在包初始化时自动运行。在每个包中都可以定义一个或多个 init 函数,这些函数将在包的全局变量准备好之后执行,并且在程序的 main 函数执行之前运行。因此,你不必显式地调用 init 函数,它会在程序启动时自动执行。

在 Golang 中,init 函数的行为具有特定的规则和用途。以下是详细说明以及相关文档:

init 函数的特性

  1. 自动执行

    • init 函数在包被加载时自动执行,无需手动调用。
    • 它确保在程序的 main 函数执行之前,对全局变量进行初始化或完成其他设置。
  2. 每个包一个或多个

    • 每个包可以包含一个或多个 init 函数。
    • Go 语言会按照源码中的定义顺序逐个执行这些 init 函数。
  3. 执行顺序

    • init 函数的执行顺序与包的导入依赖顺序一致。即,在某个包中,所有依赖项的 init 函数都会按照依赖顺序先执行,随后才会执行该包本身的 init 函数。
  4. 用途

    • 常用于初始化需要特别处理的信息,如数据库连接、加载配置文件、初始化日志设置等。

示例

下面是一个 init 函数的示例,用于加载配置文件并初始化一些基本设置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func init() {
    var err error
    path := "./conf/app.ini"
    Cfg, err = ini.Load(path)
    if err != nil {
        log.Fatalf("Fail to parse 'conf/app.ini': %v", err)
    }

    LoadBase()
    LoadServer()
    LoadApp()
    LoadTencentCloudCos()
}

文档

Go 的官方文档没有专门为 init 提供独立页面,但在 Go语言规范 中有关于包初始化(包括 init 函数)的描述部分。另外,许多 Go 编程书籍和在线教程也会详细解释 init 函数的工作原理及使用案例。

关于 golang 的导包

不同文件夹之间的文件属于同一个包时,其他文件导入使用的话是需要换名字的不然会起冲突

测试文件时同属于一个 package 的时候可以直接使用函数

是的,这里的“同一个包”指的是在 Go 语言中定义的 package。每个 Go 文件都声明一个包名(如 package user),所有属于同一个包的文件可以共享相同的函数和变量。

关键点

  • 包的定义:在 Go 中,使用 package 关键字定义包。所有在同一目录下的文件,若使用相同的包名,则属于同一包。

  • 函数调用:如果在同一个包中,可以直接调用其他文件中定义的函数,而无需使用包名作为前缀。例如,在 user_repository.go 中定义的 GerRole 函数可以直接在 user_repository_test.go 中使用 GerRole() 来调用。

  • 导入其他包:如果需要调用其他包的函数,则需要导入相应的包,并使用包名作为前缀。例如,user.GerRole() 是调用 user 包中的 GerRole 函数。

示例

假设有以下两个文件:

user_repository. go

1
2
3
4
5
package user

func GerRole(username string) string {
	// 函数实现
}

user_repository_test. go

1
2
3
4
5
6
package user // 仍然是同一个包

func TestGerRole(t *testing.T) {
	role := GerRole("testuser") // 直接调用,不用加 user.
	// 测试逻辑
}

Gorm

在使用 GORM 时,默认情况下,结构体名会被转换为小写并加上复数形式作为表名。例如,Userinfo 结构体会对应 userinfos 表。如果你想自定义表名,可以在结构体定义中使用 TableName 方法来指定表名。

gin. context

在 Go 的 Gin 框架中,c.Next() 是一个非常重要的函数,用于控制中间件的执行流。以下是关于 c.Next() 的详细解释:

c.Next() 的作用

  1. 继续处理请求

    • 当您在中间件中调用 c.Next() 时,它会告诉 Gin 继续处理当前请求的后续中间件和最终的处理函数(即路由处理器)。
  2. 中间件的执行顺序

    • 在 Gin 中,中间件是按照注册的顺序执行的。如果一个中间件调用 c.Next(),则会继续执行后面的中间件和处理函数;如果不调用 c.Next(),则后面的中间件和处理函数将不会执行。
  3. 条件控制

    • 在您的例子中,如果用户角色不是 “admin”,中间件会通过 c.AbortWithStatusJSON(...) 提前终止请求处理,并返回一个 401 Unauthorized 响应。在这种情况下,c.Next() 不会被调用,因为请求已经被终止。

代码示例分析

以下是您的 JWT_admin 函数中 c.Next() 的上下文:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func JWT_admin() gin.HandlerFunc {
	return func(c *gin.Context) {
		var code int
		code = e.SUCCESS

		// 从请求头中获取 token
		token := c.Request.Header.Get("X-Token")
		// 解析 token
		data, err := util.ParseToken(token)
		if err != nil {
			log.Println("parse token error:", err)
		}

		role := data.Role
		if role != "admin" {
			code = e.ERROR_AUTH_CHECK_ROLE_FAIL
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"code": code, "msg": e.GetMsg(code)})
			return // 终止处理,返回响应
		}

		c.Set("username", data.Username)
		c.Set("role", role)

		// gin继续处理请求
		c.Next() // 继续执行后续中间件和处理函数
	}
}

总结

  • c.Next() 用于继续处理请求的流。
  • 如果在中间件中遇到错误或条件不满足,可以通过 c.Abort()c.AbortWithStatusJSON() 终止请求处理,而不是继续执行后续的处理。
  • 这使得中间件可以在请求处理链中灵活控制执行流。

如果您还有其他问题或需要进一步的解释,请告诉我!