GO项目实战

174 阅读2分钟

使用go语言搭建一个后端的项目

这个项目是一个练手的项目,记录一下项目从无到有的一个过程

Viper的使用

安装

# 安装
go get github.com/spf13/viper

使用

# config.go
func InitConfig() {
   workDir, _ := os.Getwd()                 // 项目目录
   viper.SetConfigName("application")       // 配置文件名
   viper.SetConfigType("yml")               // 文件类型
   viper.AddConfigPath(workDir + "/config") // 配置文件夹 可以看下图我的目录结构

   err := viper.ReadInConfig()
   if err != nil {
      panic(any(err))
   }
}

# main.go
func main(){
    config.InitConfig() // 初始化配置文件
    port := viper.GetString("server.port") // 获取配置文件
}

# application.yaml
server:
  port: 8080
datasource:
  driverName: mysql
  host: 127.0.0.1
  port: 3306
  database: OceanLearn
  username: root
  password: 123456
  charset: utf8

image.png

初始化化数据库

安装

# 连接数据库
go get -u gorm.io/gorm
# mysql 驱动
go get -u gorm.io/driver/mysql

使用

func InitDatabase() *gorm.DB {

   host := viper.GetString("datasource.host")
   port := viper.GetString("datasource.port")
   database := viper.GetString("datasource.database")
   username := viper.GetString("datasource.username")
   password := viper.GetString("datasource.password")
   charset := viper.GetString("datasource.charset")

   dns := username + ":" +
      password + "@tcp(" + host + ":" + port + ")/" +
      database + "?charset=" + charset +
      "&parseTime=True&loc=Local"

   db, err := gorm.Open(mysql.Open(dns), &gorm.Config{})
   if err != nil {
      panic(any("数据库连接失败,请重试……"))
   }

   err = db.AutoMigrate(&models.Admin{})
   if err != nil {
      return nil
   }

   // 赋值给DB
   DB = db

   return db
}

中间件

写中间件的时候要注意的点:

  1. 注意放行 ctx.Next()
  2. 中间件方法返回的是gin.HandlerFunc类型的函数,所以要使用 return func(ctx *gin.Context){}
  3. 将数据写入上下文
    ctx.Set("user", user)
    
  4. 在控制器中使用上下文数据
    data, _ := ctx.Get("user")
    

权限中间件

func AuthMiddleware() gin.HandlerFunc {
   return func(ctx *gin.Context) {
      tokenString := ctx.GetHeader("Authorization") // 获取变token

      if tokenString == "" || !strings.HasPrefix(tokenString, "Bearer ") {
         ctx.JSON(http.StatusUnauthorized, gin.H{
            "code": 401,
            "msg":  "请登录!",
         })
         ctx.Abort()
         return
      }

      tokenString = tokenString[7:] // 截取 token 有效的部分

      token, claims, err := common.ParseToken(tokenString)
      if err != nil || !token.Valid {
         ctx.JSON(http.StatusUnauthorized, gin.H{
            "code": 401,
            "msg":  "请重新登录",
         })
         ctx.Abort()
         return
      }

      var DB = common.GetDB()

      var user = models.User{} // 初始化 User
      if err := DB.Debug().First(&user, claims.UserId).Error; err != nil {
         panic(any(err))
      }

      // 用户存在 将user的信息写入上下文
      ctx.Set("user", user)
      ctx.Next()
   }
}

跨域中间件

return func(context *gin.Context) {
   context.Writer.Header().Set("Access-Control-Allow-Origin", "http://localhost:8081")
   context.Writer.Header().Set("Access-Control-Max-Age", "86400")
   context.Writer.Header().Set("Access-Control-Allow-Methods", "*")
   context.Writer.Header().Set("Access-Control-Allow-Headers", "*")
   context.Writer.Header().Set("Access-Control-Allow-Credentials", "true")

   if context.Request.Method == http.MethodOptions {
      context.AbortWithStatus(200)
   } else {
      context.Next()
   }
}

异常中间件

return func(ctx *gin.Context) {
   defer func() {
      if err := recover(); err != any(nil) {
         response.Fail(ctx, fmt.Sprint(err), nil)
      }
   }()

   ctx.Next()
}

时间格式相关

GO中的事件格式 不是想PHP中使用 “Y-m-d H:i:s”, 而是使用 "2006-01-02 15:04:05 " 速记方法就是 2006-1月2日3时4分5秒

loc, _ := time.LoadLocation("Local")
birthday, _ := time.ParseInLocation("2006-01-02 15:04:05", json2.Birthday, loc)