使用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
初始化化数据库
安装
# 连接数据库
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
}
中间件
写中间件的时候要注意的点:
- 注意放行 ctx.Next()
- 中间件方法返回的是gin.HandlerFunc类型的函数,所以要使用 return func(ctx *gin.Context){}
- 将数据写入上下文
ctx.Set("user", user)
- 在控制器中使用上下文数据
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)