# GoControlBackend **Repository Path**: chi-meng/go-control-backend ## Basic Information - **Project Name**: GoControlBackend - **Description**: 使用Go语言开发的一个简单的后台管理系统 - **Primary Language**: Go - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-03-06 - **Last Updated**: 2025-11-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # GoControalBackend # 【一】初始化项目 ## 【1】创建项目 ### (1)项目结构 ```text ../GoControlBackend ├── LICENSE ├── README.en.md ├── README.md ├── api ├── config.yaml ├── common ├── go.mod ├── main.go ├── middleware ├── pkg └── router ``` ### (2)项目初始化 - 先安装项目依赖包go.mod ```shell # 初始化 Go mod go mod init GoControlBackend # 初始化 tidy go mod tidy ``` ## 【2】安装第三方依赖 - 在终端命令Terminal中安装依赖 ```shell # 安装gin命令: go get github.com/gin-gonic/gin@v1.8.1 # 安装gorm命令: go get gorm.io/gorm # 安装mysql命令: go get gorm.io/driver/mysql # 安装log命令: go get github.com/sirupsen/logrus go get github.com/lestrrat-go/file-rotatelogs go get github.com/rifflock/lfshook # 安装go-redis命令: go get github.com/go-redis/redis/v8@v8.11.5 # 安装base64Captcha命令: go get github.com/mojocn/base64Captcha@v1.3.1 # 安装jwt-go命令: go get github.com/dgrijalva/jwt-go # 安装yaml命令: go get gopkg.in/yaml.v3 # 安装获取客户端OS和browser命令: go get -u github.com/wenlng/go-user-agent # 安装ip地址命令: go get github.com/gogf/gf # 安装swagger命令: go get github.com/swaggo/files go get github.com/swaggo/gin-swagger ``` - 如果下载依赖报红,在file中选择settings->Go->Go Modules中配置 `GOPROXY=https://goproxy.io` ## 【3】项目配置项参数 - `common/config/config.go` ```go package config import ( "gopkg.in/yaml.v2" "io/ioutil" ) // 全局参数配置项 type config struct { Server server `yaml:"server"` Db db `yaml:"db"` Redis redis `yaml:"redis"` ImageSettings imageSettings `yaml:"imageSettings"` Log log `yaml:"log"` } // 启动参数配置模块 type server struct { Address string `yaml:"address"` Model string `yaml:"model"` } // MySQL数据库参数配置模块 type db struct { Dialects string `yaml:"dialects"` Host string `yaml:"host"` Port int `yaml:"port"` Db string `yaml:"db"` Username string `yaml:"username"` Password string `yaml:"password"` Charset string `yaml:"charset"` MaxIdle int `yaml:"maxIdle"` MaxOpen int `yaml:"maxOpen"` } // Redis数据库配置 type redis struct { Address string `yaml:"address"` Password string `yaml:"password"` } // 文件上传接口配置 type imageSettings struct { UploadDir string `yaml:"uploadDir"` ImageHost string `yaml:"imageHost"` } // 日志参数配置 type log struct { Path string `yaml:"path"` Name string `yaml:"name"` Model string `yaml:"model"` } var Config *config // 配置初始化 func init() { yamlFile, err := ioutil.ReadFile("./config.yaml") // 如果有错误 宕机 if err != nil { panic(err) } // 绑定值 err = yaml.Unmarshal(yamlFile, &Config) if err != nil { panic(err) } } ``` - `config.yaml` ```yaml # 项目启动参数 server: address: 2025 # DEBUG 模式 model: debug # release 模式 # model : release # MySQL 数据库配置 db: dialects: mysql host: 127.0.0.1 port: 13306 db: go_control_backend username: root password: 1314521 charset: utf8mb4 # 最大空闲数 maxIdle: 50 # 最大链接数 maxOpen: 150 # Redis 配置 redis: address: 1270.0.1:6321 password: 123456 # 图片上传位置 imageSettings: # 本地磁盘存储位置 uploadDir: /GoControlBackend/upload/ # 本地项目IP地址 imageHost: http://localhost:2025 # 日志参数配置 log: path: ./log name: sys # 输出模式为输出到控制台 model: console # 输出模式为输出到文件 # model : file ``` ## 【3】初始化MySQL - `pkg/db/db.go` ```go package db import ( "GoControalBackend/common/config" "fmt" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" ) var Db *gorm.DB // SetupDBLink 初始化数据库 func SetupDBLink() error { // 定义错误变量 var err error // 从配置中获取数据库配置 var dbConfig = config.Config.Db // 格式化数据库连接URL url := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=True&loc=Local", dbConfig.Username, dbConfig.Password, dbConfig.Host, dbConfig.Port, dbConfig.Db, dbConfig.Charset) // 使用gorm库打开数据库连接 Db, err := gorm.Open(mysql.Open(url), &gorm.Config{ Logger: logger.Default.LogMode(logger.Info), DisableForeignKeyConstraintWhenMigrating: true, }) // 如果打开数据库连接时发生错误,触发panic if err != nil { panic(err) } // 如果数据库连接对象中存在错误,触发panic if Db.Error != nil { panic(Db.Error) } // 获取底层的sql.DB对象 sqlDB, err := Db.DB() // 设置最大空闲连接数 sqlDB.SetMaxIdleConns(dbConfig.MaxIdle) // 设置最大打开连接数 sqlDB.SetMaxOpenConns(dbConfig.MaxOpen) // 返回nil表示成功 return nil } ``` ## 【4】初始化Redis - `pkg/redis/redis.go` ```go package redis import ( "GoControalBackend/common/config" "context" "github.com/go-redis/redis/v8" ) // RedisDb Redis 配置初始化 var RedisDb *redis.Client // SetupRedisDb 初始化Redis容器 func SetupRedisDb() error { var ctx = context.Background() RedisDb = redis.NewClient( &redis.Options{ Addr: config.Config.Redis.Address, Password: config.Config.Redis.Address, DB: 9, }) _, err := RedisDb.Ping(ctx).Result() if err != nil { return err } return nil } ``` ## 【5】跨域中间件初始化 - `middleware/cors.go` ```go package middleware import ( "github.com/gin-gonic/gin" "net/http" ) // 跨域中间件配置 // Cors 定义一个 CORS 中间件函数 func Cors() gin.HandlerFunc { // 返回一个处理函数 return func(context *gin.Context) { // 获取请求方法 method := context.Request.Method // 设置响应头,允许所有来源 context.Header("Access-Control-Allow-Origin", "*") // 设置允许的请求头 context.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token,Authorization,Token") // 设置允许的请求方法 context.Header("Access-Control-Allow-Methods", "POST,GET,OPTIONS") // 设置暴露的响应头 context.Header("Access-Control-Expose-Headers", "Content-Length,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Content-Type") // 设置是否允许发送 cookies context.Header("Access-Control-Allow-Credentials", "true") // 放行所有 OPTIONS 方法 if method == "OPTIONS" { // 中断请求并返回 204 状态码 context.AbortWithStatus(http.StatusNoContent) } // 处理请求 context.Next() } } ``` ## 【6】统一返回结构 - 状态码:`common/result/code.go` ```go package result // Codes 状态码 type Codes struct { SUCCESS uint FAILED uint Message map[uint]string } // ApiCode 状态码 var ApiCode = &Codes{ SUCCESS: 200, FAILED: 501, } // 状态信息 func init() { // 初始化ApiCode.Message字典,将状态码映射到对应的中文消息 ApiCode.Message = map[uint]string{ // 状态码SUCCESS映射到中文消息"成功" ApiCode.SUCCESS: "成功", // 状态码FAILED映射到中文消息"失败" ApiCode.FAILED: "失败", } } // 供外部调用 func (c *Codes) GetMessage(code uint) string { // 从c.Message映射中获取对应code的消息 message, ok := c.Message[code] // 如果code不存在于映射中,返回空字符串 if !ok { return "" } // 如果code存在于映射中,返回对应的消息 return message } ``` - 成功和失败响应 `common/result/result.go` ```go package result import ( "github.com/gin-gonic/gin" "net/http" ) // Result 定义返回结构 type Result struct { Code int `json:"code"` // 状态码 Message string `json:"message"` // 提示信息 Data interface{} `json:"data"` // 返回数据 } // Success 返回成功结构体 func Success(c *gin.Context, data interface{}) { // 检查data是否为nil,如果是则初始化为一个空的gin.H if data == nil { data = gin.H{} } // 初始化一个Result结构体 response := Result{} // 设置响应码为成功码 response.Code = int(ApiCode.SUCCESS) // 获取成功码对应的消息 response.Message = ApiCode.GetMessage(ApiCode.SUCCESS) // 设置响应数据 response.Data = data // 以JSONP格式返回成功响应 c.JSONP(http.StatusOK, response) } // Failure 返回失败结构体 func Failure(c *gin.Context, code int, message string) { // 定义一个响应结构体 response := Result{} // 设置响应的状态码 response.Code = code // 设置响应的消息 response.Message = message // 设置响应的数据为空的gin.H对象 response.Data = gin.H{} // 将响应以JSON格式返回给客户端 c.JSON(http.StatusOK, response) } ``` ## 【7】日志处理 - 日志配置 `pkg/log/logger.go` ```go package log import ( "GoControalBackend/common/config" rotatelogs "github.com/lestrrat-go/file-rotatelogs" "github.com/rifflock/lfshook" "github.com/sirupsen/logrus" "os" "path/filepath" "time" ) // 日志组件 var log *logrus.Logger var logToFile *logrus.Logger // 日志文件名 var loggerFile string // 设置日志文件的路径 // 参数: file: 日志文件的路径 func setLogFile(file string) { // 将日志文件路径赋值给全局变量loggerFile loggerFile = file } // 初始化 func init() { // 设置日志文件路径,使用配置中的日志路径和文件名 setLogFile(filepath.Join(config.Config.Log.Path, config.Config.Log.Name)) } // Log 日志方法调用 func Log() *logrus.Logger { // 如果配置中的日志模式为文件 if config.Config.Log.Model == "file" { // 返回文件日志记录器 return logFile() } else { // 如果日志记录器尚未初始化 if log == nil { // 创建一个新的日志记录器 log = logrus.New() // 设置日志输出为标准输出 log.Out = os.Stdout // 设置日志格式为JSON格式,并指定时间戳格式 log.Formatter = &logrus.JSONFormatter{TimestampFormat: "2008-01-01 15:04:05"} // 设置日志级别为调试级别 log.SetLevel(logrus.DebugLevel) } } // 返回日志记录器 return log } // 日志文件方法 func logFile() *logrus.Logger { // 检查 logToFile 是否为空 if logToFile == nil { // 如果为空,创建一个新的 logrus.Logger 实例 logToFile = logrus.New() // 设置日志级别为 Debug logToFile.SetLevel(logrus.DebugLevel) // 创建日志文件轮转写入器 logWriter, _ := rotatelogs.New( // 分割后的文件名称 loggerFile+"%Y%m%d.log", // 设置最大保存时间 rotatelogs.WithMaxAge(30*24*time.Hour), // 设置日志切割时间间隔(1天) rotatelogs.WithRotationTime(24*time.Hour), ) // 定义日志级别到写入器的映射 writeMap := lfshook.WriterMap{ logrus.InfoLevel: logWriter, logrus.FatalLevel: logWriter, logrus.DebugLevel: logWriter, logrus.WarnLevel: logWriter, logrus.ErrorLevel: logWriter, logrus.PanicLevel: logWriter, } // 设置时间格式 lfHook := lfshook.NewHook(writeMap, &logrus.JSONFormatter{ TimestampFormat: "2006-01-02 15:04:05", }) // 新增 Hook logToFile.AddHook(lfHook) } // 返回日志实例 return logToFile } ``` - 日志中间件 `middleware/logger.go` ```go package middleware import ( "GoControalBackend/pkg/log" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "io/ioutil" "time" ) // Logger 日志中间件 func Logger() gin.HandlerFunc { // 获取日志记录器 logger := log.Log() return func(context *gin.Context) { // 开始时间 startTime := time.Now() // 处理请求 context.Next() // 结束时间 endTime := time.Now() // 执行时间 latencyTime := endTime.Sub(startTime) / time.Millisecond // 请求方式 requestMethod := context.Request.Method // 请求路由 requestUrl := context.Request.RequestURI // 请求头 header := context.Request.Header // 协议版本 proto := context.Request.Proto // 状态码 statusCode := context.Writer.Status() // 请求API clientIP := context.ClientIP() // 获取请求处理中的错误 err := context.Err() // 读取请求体 body, _ := ioutil.ReadAll(context.Request.Body) // 记录日志 logger.WithFields(logrus.Fields{ "status_code": statusCode, "latency_time": latencyTime, "client_ip": clientIP, "request_method": requestMethod, "request_url": requestUrl, "header": header, "proto": proto, "err": err, "body": body, }).Info() } } ``` ## 【8】路由定义 ```go package router import ( "GoControalBackend/common/config" "GoControalBackend/middleware" "github.com/gin-gonic/gin" "net/http" ) // InitRouter 路由 定义 func InitRouter() *gin.Engine { // 创建一个新的gin路由器 router := gin.New() // 宕机恢复 router.Use(gin.Recovery()) // 跨域中间件 router.Use(middleware.Cors()) // 图片访问路径静态文件夹可直接访问 router.StaticFS(config.Config.ImageSettings.UploadDir, http.Dir(config.Config.ImageSettings.UploadDir)) // 日志中间件 router.Use(middleware.Logger()) // 注册路由 register(router) // 返回初始化的路由器 return router } // register 接口 func register(router *gin.Engine) { // todo :>> 后续接口URL } ``` ## 【9】启动入口 ```go package main import ( "GoControalBackend/common/config" "GoControalBackend/pkg/db" "GoControalBackend/pkg/log" "GoControalBackend/pkg/redis" "GoControalBackend/router" "context" "github.com/gin-gonic/gin" "net/http" "os" "os/signal" "time" ) // 启动入口程序 // man 函数主要为四个步骤:设置启动模式,初始化路由,启动服务,监听消息 func main() { // 加载日志 log log := log.Log() // 设置启动模式 gin.SetMode(config.Config.Server.Model) // 初始化路由 router := router.InitRouter() // 创建HTTP服务器 srv := &http.Server{ Addr: config.Config.Server.Address, Handler: router, } // 启动服务 go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Info("listen err ::>> %s \n", err) } log.Info("listen ::>> %s \n", config.Config.Server.Address) }() // 创建一个用于接收系统信号的通道 quit := make(chan os.Signal) // 监听消息 signal.Notify(quit, os.Interrupt) // 等待接收到系统中断信号 <-quit // 打印日志,表示服务器正在关闭 log.Info("Shutdown Server ... ") // 创建一个带有超时时间的上下文 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // 关闭服务器 if err := srv.Shutdown(ctx); err != nil { log.Info("Server Shutdown ::>> ", err) } // 打印日志,表示服务器正在退出 log.Info("Server exiting ... ") } // 初始化链接 func init() { // MySQL db.SetupDBLink() // Redis redis.SetupRedisDb() } ``` # 【其他】 #### 介绍 使用Go语言开发的一个简单的后台管理系统 #### 软件架构 软件架构说明 #### 安装教程 1. xxxx 2. xxxx 3. xxxx #### 使用说明 1. xxxx 2. xxxx 3. xxxx #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)