本文最后更新于 2024-08-19,文章内容距离上一次更新已经过去了很久啦,可能已经过时了,请谨慎参考喵。

前情提要

注:这个项目烂尾了,请谨慎观看!

开发环境:
Windows Server 2022+GoLand2024.1+MySQL8.3(Winx64)
Go 代理: go env -w GOPROXY=https://goproxy.cn
(由于用的是远程桌面连接虚拟机,故截图比较糊,主要看代码)

项目创建

创建如下的目录结构:

GOBLOG-ADMIN
├── go.mod    # go mod文件
├── main.go    # 程序入口
├── config.yaml    # 配置文件
├── api/    # api
├── config/    # 配置项
├── core/    # 核心库
├── result/    # 接口访问集
├── global/    # 全局配置文件
├── middleware/    # 中间件
├── model/    # 模型
├── router/    # 路由
├── utils/    # 工具类
└── constant/    # 系统常量

测试一下环境:
go.mod :

model goblog-admin

go 1.22

main.go :

// 启动程序
// @author DaBaiLuoBo

package main

import "fmt"

func main() {
    fmt.Println("The GoBlog-Admin has been started...")
}

输出:

3046761367.png

系统配置

首先引入一下 yaml 支持的包,项目根目录执行:

go get gopkg.in/yaml.v2

2762805260.png

查看 go.mod 文件已加载其依赖:

3017101771.png

配置 config.yaml 文件:

# 系统配置
system:
  # 运行地址:本地
  host: "0.0.0.0"
  # 端口
  port: 5001
  # 启动环境:debug/release
  env: debug

创建 /config/config.go 文件:

// 读取配置文件
// @author DaBaiLuoBo

package config

import (
    "gopkg.in/yaml.v2"
    "io/ioutil"
)

// config 总配置文件
type config struct {
    System system `yaml:"system"`
}

// 系统配置
type system struct {
    Host string `yaml:"host"`
    Port int    `yaml:"port"`
    Env  string `yaml:"env"`
}

var Config *config

// init 初始化配置
func init() {
    yamlFile, err := ioutil.ReadFile("./config.yaml") // 注意这里的路径,是和根目录同级
    // 如果为空,直接返回错误内容
    if err != nil {
        return
    }
    // 接收配置文件,存入 Config 中
    yaml.Unmarshal(yamlFile, &Config)
}

回到 main.go 文件中,打印一下配置文件测试是否读取到:

// 启动程序
// @author DaBaiLuoBo

package main

import (
    "fmt"
    "goblog-admin/config"
)

func main() {
    fmt.Println("The GoBlog-Admin has been started...")
    fmt.Println("系统配置文件:", config.Config.System)
}

输出:

3743568431.png

日志配置

首先添加日志依赖:(项目根目录执行)

go get github.com/sirupsen/logrus

881228593.png

回到 config.yaml 文件中,继续写日志配置文件:

# 系统配置
system:
  # 运行地址:本地
  host: "0.0.0.0"
  # 端口
  port: 5001
  # 启动环境:debug/release
  env: debug

# logger 日志配置
logger:
  # 日志等级
  level: info
  # 日志前缀
  prefix: '[goblog-admin]'
  # 日志文件路径
  director: logger
  # 显示行号
  show_line: true
  # 是否打印在控制台
  log_in_console: true

/config/config.go 结构体中增加:

// 读取配置文件
// @author DaBaiLuoBo

package config

import (
    "gopkg.in/yaml.v2"
    "io/ioutil"
)

// config 总配置文件
type config struct {
    System system `yaml:"system"`
    Logger logger `yaml:"logger"`
}

// 系统配置
type system struct {
    Host string `yaml:"host"`
    Port int    `yaml:"port"`
    Env  string `yaml:"env"`
}

// logger 日志配置
type logger struct {
    Level        string `yaml:"level"`
    Prefix       string `yaml:"prefix"`
    Director     string `yaml:"director"`
    ShowLine     bool   `yaml:"show_line"`
    LogInConsole bool   `yaml:"log_in_console"`
}

var Config *config

// init 初始化配置
func init() {
    yamlFile, err := ioutil.ReadFile("./config.yaml") // 注意这里的路径,是和根目录同级
    // 如果为空,直接返回错误内容
    if err != nil {
        return
    }
    // 接收配置文件,存入 Config 中
    yaml.Unmarshal(yamlFile, &Config)
}

main.go 文件中打印一下测试是否读取到:

fmt.Println("日志配置文件:", config.Config.Logger)

输出:

3067808448.png

没有问题哈,接下来在核心组件目录中创建处理日志的包 /core/logrus.go

// 日志处理
// @author DaBaiLuoBo

package core

import (
    "bytes"
    "fmt"
    "github.com/sirupsen/logrus"
    "goblog-admin/config"
    "os"
    "path"
)

// 颜色
const (
    red    = 31
    yellow = 33
    blue   = 36
    gray   = 37
)

type LogFormatter struct{}

// Format 实现 Formatter (entry *logrus.Entry) ([]byte, error) 接口
func (t *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
    // 根据不同的 level 展示不同的颜色
    var levelColor int
    switch entry.Level {
    case logrus.DebugLevel, logrus.TraceLevel:
        levelColor = gray
    case logrus.WarnLevel:
        levelColor = yellow
    case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
        levelColor = red
    default:
        levelColor = blue
    }

    //
    var b *bytes.Buffer
    if entry.Buffer != nil {
        b = entry.Buffer
    } else {
        b = &bytes.Buffer{}
    }
    log := config.Config.Logger

    // 自定义日期格式
    timestamp := entry.Time.Format("2006-01-02 15:04:05")
    if entry.HasCaller() {
        // 自定义文件路径
        funcVal := entry.Caller.Function
        fileVal := fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line)
        // 自定义输出格式
        fmt.Fprintf(b, "%s[%s] \x1b[%dm[%s]\x1b[0m %s %s: %s\n", log.Prefix, timestamp, levelColor, entry.Level, fileVal, funcVal, entry.Message)
    } else {
        fmt.Fprintf(b, "%s[%s] \x1b[%dm[%s]\x1b[0m: %s\n", log.Prefix, timestamp, levelColor, entry.Level, entry.Message)
    }
    return b.Bytes(), nil
}

// InitLogger 初始化
func InitLogger() *logrus.Logger {
    mlog := logrus.New()                                // 新建一个实例
    mlog.SetOutput(os.Stdout)                           // 设置输出类型
    mlog.SetReportCaller(config.Config.Logger.ShowLine) // 开启返回函数名和行号
    mlog.SetFormatter(&LogFormatter{})                  // 设置自己定义的 Formatter
    level, err := logrus.ParseLevel(config.Config.Logger.Level)
    if err != nil {
        level = logrus.InfoLevel
    }
    mlog.SetLevel(level) // 设置最低的 level
    InitDefaultLogger()  // 不注释的话即启用全局 log
    return mlog
}

// InitDefaultLogger 全局 log
func InitDefaultLogger() {
    logrus.SetOutput(os.Stdout)                           // 设置输出类型
    logrus.SetReportCaller(config.Config.Logger.ShowLine) // 开启返回函数名和行号
    logrus.SetFormatter(&LogFormatter{})                  // 设置自己定义的 Formatter
    level, err := logrus.ParseLevel(config.Config.Logger.Level)
    if err != nil {
        level = logrus.InfoLevel
    }
    logrus.SetLevel(level) // 设置最低的 level
}

创建全局共享配置, global/global.go

// 全局共享配置
// @author DaBaiLuoBo

package global

import "github.com/sirupsen/logrus"

var (
    Log *logrus.Logger
)

返回 main.go 文件,设置初始化和输出日志:

// 启动程序
// @author DaBaiLuoBo

package main

import (
    "goblog-admin/core"
    "goblog-admin/global"
)

func main() {
    //fmt.Println("The GoBlog-Admin has been started...")
    //fmt.Println("系统配置文件:", config.Config.System)
    //fmt.Println("日志配置文件:", config.Config.Logger)

    // 初始化 logger
    global.Log = core.InitLogger()
    // 输出日志
    global.Log.Warnln("GoBlog 日志")
    global.Log.Error("GoBlog 日志")
    global.Log.Infof("GoBlog 日志")
}

输出:

3266743683.png

MySQL配置

首先配置MySQL的驱动和依赖以及gorm:(项目根目录执行)

go get gorm.io/driver/mysql
go get gorm.io/gorm

1623037242.png

config.yaml 文件中添加MySQL配置:

# 系统配置
system:
  # 运行地址:本地
  host: "0.0.0.0"
  # 端口
  port: 5001
  # 启动环境:debug/release
  env: debug

# logger 日志配置
logger:
  # 日志等级
  level: info
  # 日志前缀
  prefix: '[goblog-admin]'
  # 日志文件路径
  director: logger
  # 显示行号
  show_line: true
  # 是否打印在控制台
  log_in_console: true

# MySQL 配置
mysql:
  # 监听地址
  host: 127.0.0.1
  # 端口
  port: 3306
  # 数据库名称
  db_name: goblogtest
  # 链接数据库用户名
  username: goblog
  # 链接数据库密码
  password: goblog
  # 日志等级
  log_level: dev
  # 字符集设置
  charset: utf8mb4
  # 最大连接数
  maxIdle: 50
  # 最大连接时间
  maxOpen: 150

然后在 /config/config.go 文件中配置一下结构体:

// 读取配置文件
// @author DaBaiLuoBo

package config

import (
    "gopkg.in/yaml.v2"
    "io/ioutil"
)

// config 总配置文件
type config struct {
    System system `yaml:"system"`
    Logger logger `yaml:"logger"`
    Mysql  mysql  `yaml:"mysql"`
}

// 系统配置
type system struct {
    Host string `yaml:"host"`
    Port int    `yaml:"port"`
    Env  string `yaml:"env"`
}

// logger 日志配置
type logger struct {
    Level        string `yaml:"level"`
    Prefix       string `yaml:"prefix"`
    Director     string `yaml:"director"`
    ShowLine     bool   `yaml:"show_line"`
    LogInConsole bool   `yaml:"log_in_console"`
}

// MySQL 配置
type mysql struct {
    Host     string `yaml:"host"`
    Port     int    `yaml:"port"`
    DbName   string `yaml:"db_name"`
    Username string `yaml:"username"`
    Password string `yaml:"password"`
    LogLevel string `yaml:"log_level"`
    Charset  string `yaml:"charset"`
    MaxIdle  int    `yaml:"maxIdle"`
    MaxOpen  int    `yaml:"maxOpen"`
}

var Config *config

// init 初始化配置
func init() {
    yamlFile, err := ioutil.ReadFile("./config.yaml") // 注意这里的路径,是和根目录同级
    // 如果为空,直接返回错误内容
    if err != nil {
        return
    }
    // 接收配置文件,存入 Config 中
    yaml.Unmarshal(yamlFile, &Config)
}

写好之后在 main.go 文件中尝试打印一下,看看是否读取到了配置信息:

// 启动程序
// @author DaBaiLuoBo

package main

import (
    "goblog-admin/config"
    "goblog-admin/core"
    "goblog-admin/global"
)

func main() {
    //fmt.Println("The GoBlog-Admin has been started...")
    //fmt.Println("系统配置文件:", config.Config.System)
    //fmt.Println("日志配置文件:", config.Config.Logger)

    // 初始化 logger
    global.Log = core.InitLogger()
    // 输出日志
    //global.Log.Warnln("GoBlog 日志")
    //global.Log.Error("GoBlog 日志")
    //global.Log.Infof("GoBlog 日志")
    // 测试一下输出MySQL配置信息
    global.Log.Infof("MySQL配置:%s", config.Config.Mysql)
}

输出:

134243784.png

配置信息虽然输出了,但是有数据没有正常显示,这是因为全部用的 %s 字符串输出,先不用管,继续配置MySQL的连接
创建 /core/mysql.go 文件,作为MySQL的启动和连接组件:

// MySQL 启动和连接组件(初始化配置)
// @author DaBaiLuoBo

package core

import (
    "fmt"
    "goblog-admin/config"
    "goblog-admin/global"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
)

// 创建一个数据库,指针指向 gorm 组件
var Db *gorm.DB

// 数据库初始化
func MysqlInit() error {
    var err error
    // 拿到 MySQL 配置信息
    var dbConfig = config.Config.Mysql
    // 格式化 url 字符串,含 MySQL 的配置参数
    url := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=True&loc=Local",
        dbConfig.Username,
        dbConfig.Password,
        dbConfig.Host,
        dbConfig.Port,
        dbConfig.DbName,
        dbConfig.Charset)
    Db, err = gorm.Open(mysql.Open(url), &gorm.Config{
        Logger:                                   logger.Default.LogMode(logger.Info),
        DisableForeignKeyConstraintWhenMigrating: true,
    })
    if err != nil {
        return err
    }
    if Db.Error != nil {
        return Db.Error
    }

    // 数据库的设置
    sqlDb, err := Db.DB()
    sqlDb.SetMaxIdleConns(dbConfig.MaxIdle)
    sqlDb.SetMaxOpenConns(dbConfig.MaxOpen)

    // 打印数据库操作成功
    global.Log.Infof("[MySQL] 数据库连接成功")

    // 保证函数完整性,返回空
    return nil
}

然后在 main.go 中增加数据库初始化语句:

// 主启动程序
// @author DaBaiLuoBo

package main

import (
    "goblog-admin/core"
    "goblog-admin/global"
)

func main() {
    // 初始化 logger
    global.Log = core.InitLogger()

    // 初始化 MySQL
    core.MysqlInit()

    //fmt.Println("The GoBlog-Admin has been started...")
    //fmt.Println("系统配置文件:", config.Config.System)
    //fmt.Println("日志配置文件:", config.Config.Logger)

    // 测试输出日志
    //global.Log.Warnln("GoBlog 日志")
    //global.Log.Error("GoBlog 日志")
    //global.Log.Infof("GoBlog 日志")

    // 测试一下输出MySQL配置信息
    //global.Log.Infof("MySQL配置:%s", config.Config.Mysql)
}

然后创建一个数据库,用户名和密码与配置文件中的信息保持一致,运行主程序测试是否连接成功:

313680306.png

Redis配置

添加一下redis的依赖:(项目根目录执行)

go get github.com/go-redis/redis/v8

config.yaml 文件中增加redis的配置信息:

# 系统配置
system:
  # 运行地址:本地
  host: "0.0.0.0"
  # 端口
  port: 5001
  # 启动环境:debug/release
  env: debug

# logger 日志配置
logger:
  # 日志等级
  level: info
  # 日志前缀
  prefix: '[goblog-admin]'
  # 日志文件路径
  director: logger
  # 显示行号
  show_line: true
  # 是否打印在控制台
  log_in_console: true

# MySQL 配置
mysql:
  # 监听地址
  host: 127.0.0.1
  # 端口
  port: 3306
  # 数据库名称
  db_name: goblogtest
  # 链接数据库用户名
  username: goblogtest
  # 链接数据库密码
  password: goblogtest
  # 日志等级
  log_level: dev
  # 字符集设置
  charset: utf8mb4
  # 最大连接数
  maxIdle: 50
  # 最大连接时间
  maxOpen: 150

# Redis 配置
redis:
  # redis 访问地址
  address: 127.0.0.1:6379
  # redis 连接密码
  password: 
  # 数据库(默认为0,第一个)
  db: 0

继续在 /config/config.go 文件中创建redis配置信息的结构体:

// 读取配置文件
// @author DaBaiLuoBo

package config

import (
    "gopkg.in/yaml.v2"
    "io/ioutil"
)

// config 总配置文件
type config struct {
    System system `yaml:"system"`
    Logger logger `yaml:"logger"`
    Mysql  mysql  `yaml:"mysql"`
    Redis  redis  `yaml:"redis"`
}

// 系统配置
type system struct {
    Host string `yaml:"host"`
    Port int    `yaml:"port"`
    Env  string `yaml:"env"`
}

// logger 日志配置
type logger struct {
    Level        string `yaml:"level"`
    Prefix       string `yaml:"prefix"`
    Director     string `yaml:"director"`
    ShowLine     bool   `yaml:"show_line"`
    LogInConsole bool   `yaml:"log_in_console"`
}

// MySQL 配置
type mysql struct {
    Host     string `yaml:"host"`
    Port     int    `yaml:"port"`
    DbName   string `yaml:"db_name"`
    Username string `yaml:"username"`
    Password string `yaml:"password"`
    LogLevel string `yaml:"log_level"`
    Charset  string `yaml:"charset"`
    MaxIdle  int    `yaml:"maxIdle"`
    MaxOpen  int    `yaml:"maxOpen"`
}

// Redis 配置
type redis struct {
    Address  string `yaml:"address"`
    Password string `yaml:"password"`
    Db       int    `yaml:"db"`
}

var Config *config

// init 初始化配置
func init() {
    yamlFile, err := ioutil.ReadFile("./config.yaml") // 注意这里的路径,是和根目录同级
    // 如果为空,直接返回错误内容
    if err != nil {
        return
    }
    // 接收配置文件,存入 Config 中
    yaml.Unmarshal(yamlFile, &Config)
}

然后在 main.go 中打印配置信息测试一下:

// 主启动程序
// @author DaBaiLuoBo

package main

import (
    "goblog-admin/config"
    "goblog-admin/core"
    "goblog-admin/global"
)

func main() {
    // 初始化 logger
    global.Log = core.InitLogger()

    // 初始化 MySQL
    core.MysqlInit()

    //fmt.Println("The GoBlog-Admin has been started...")
    //fmt.Println("系统配置文件:", config.Config.System)
    //fmt.Println("日志配置文件:", config.Config.Logger)

    // 测试输出日志
    //global.Log.Warnln("GoBlog 日志")
    //global.Log.Error("GoBlog 日志")
    //global.Log.Infof("GoBlog 日志")

    // 测试一下输出MySQL配置信息
    //global.Log.Infof("MySQL配置:%s", config.Config.Mysql)
    // 测试一下输出Redis配置信息
    global.Log.Infof("Redis配置:", config.Config.Redis)
}

输出:

/global/global.go 文件里拿到redis的上下文:

// 全局共享配置
// @author DaBaiLuoBo

package global

import (
    "context"
    "github.com/sirupsen/logrus"
)

var (
    Log *logrus.Logger
    Ctx = context.Background()
)

注册一个 /core/redis.go 组件文件,完成redis初始化:

// Redis 启动和连接组件(初始化配置)
// @author DaBaiLuoBo

package core

import (
    "github.com/go-redis/redis/v8"
    "goblog-admin/config"
    "goblog-admin/global"
)

// 和 MySQL 一样,先拿到 Redis 客户端
var (
    RedisDb *redis.Client
)

// 初始化 Redis 连接
func RedisInit() error {
    RedisDb = redis.NewClient(&redis.Options{
        Addr:     config.Config.Redis.Address,
        Password: config.Config.Redis.Password,
        DB:       config.Config.Redis.Db})
    // 接收 redis 连接的上下文
    _, err := RedisDb.Ping(global.Ctx).Result()
    if err != nil {
        return err
    }
    global.Log.Infof("[Redis] Redis 连接成功")
    // 保证函数完整性,返回空
    return nil
}

main.go 中初始化redis:

// 主启动程序
// @author DaBaiLuoBo

package main

import (
    "goblog-admin/core"
    "goblog-admin/global"
)

func main() {
    // 初始化 logger
    global.Log = core.InitLogger()
    // 初始化 MySQL
    core.MysqlInit()
    // 初始化 Redis
    core.RedisInit()
}

运行一下,输出:

初始化路由

首先添加 gin 框架支持:(项目根目录下执行)

go get github.com/gin-gonic/gin

创建路由配置文件 /router/router.go

// 路由初始化以及注册
// @author DaBaiLuoBo

package router

import (
    "github.com/gin-gonic/gin"
    "goblog-admin/config"
)

// 先拿到Gin框架
func RouterInit() *gin.Engine {
    // 设置启动模式
    gin.SetMode(config.Config.System.Env)
    // 新建路由
    router := gin.New()
    // 设置跌机时恢复
    router.Use(gin.Recovery())
    return router
}

// Register 路由接口
func register(router *gin.Engine) {
    // todo 后续的所有接口 url 将在此配置

}

然后在 main.go 中启动路由:

// 主启动程序
// @author DaBaiLuoBo

package main

import (
    "fmt"
    "goblog-admin/config"
    "goblog-admin/core"
    "goblog-admin/global"
    "goblog-admin/router"
)

func main() {
    // 初始化 logger
    global.Log = core.InitLogger()
    // 初始化 MySQL
    core.MysqlInit()
    // 初始化 Redis
    core.RedisInit()
    // 初始化路由
    router := router.RouterInit()
    // 拿到路由地址
    address := fmt.Sprintf("%s:%d", config.Config.System.Host, config.Config.System.Port)
    global.Log.Infof("系统启动成功,运行在: %s", address)
    // 让系统运行在指定的路由上
    router.Run(address)
}

运行测试一下,输出:
540262915.png

通用返回结构

所谓的返回结构就是指请求返回的数据结构,一般来说由三部分组成,code、data以及message组成
code就是状态码,data就是数据,message就是提示信息
创建 /result/code.go 文件,先实现状态码:

// 状态码/状态信息
//@author DaiBaiLuoBo

package result

// Codes 定义状态
type Codes struct {
    Message map[uint]string
    Success uint
    Failed  uint
}

// ApiCode 状态码
var ApiCode = &Codes{
    Success: 200,
    Failed:  501,
}

// 状态信息初始化
func init() {
    ApiCode.Message = map[uint]string{
        ApiCode.Success: "成功",
        ApiCode.Failed:  "失败",
    }
}

// GetMessage 供给外部调用状态信息
func (c *Codes) GetMessage(code uint) string {
    message, ok := c.Message[code]
    // 如果不 ok,返回空,ok 则返回 message
    if !ok {
        return ""
    }
    return message
}

再创建一个 /result/result.go 文件,用来定义通用返回结构的结构体:

// 结构数据定义
// @author DaiBaiLuoBo

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{}) {
    if data == nil {
        data = gin.H{}
    }
    // 接收 Result
    res := Result{}
    res.Code = int(ApiCode.Success)
    res.Message = ApiCode.GetMessage(ApiCode.Success)
    // data 数据直接从上面拿过来
    res.Data = data
    // 进一步返回给前端
    c.JSON(http.StatusOK, res)
}

// Failed 失败
func Failed(c *gin.Context, code int, message string) {
    // 和上面的大同小异,先接收 Result
    res := Result{}
    res.Code = code
    res.Message = message
    // 错误通过 gin 来处理
    res.Data = gin.H{}
    c.JSON(http.StatusOK, res)
}

写好之后创建一个test的API,来测试一下 /api/test.go

// 测试 API
// @author DaiBaiLuoBo

package api

import (
    "github.com/gin-gonic/gin"
    "goblog-admin/result"
)

// Success 成功测试
// @router /api/success [get]
func Success(c *gin.Context) {
    result.Success(c, 200)
}

// Failed 失败测试
// @router /api/failed [get]
func Failed(c *gin.Context) {
    result.Failed(c, int(result.ApiCode.Failed), result.ApiCode.GetMessage(result.ApiCode.Failed))
}

然后在 router/router.go 文件中增加我们的测试api,同时注册路由:

// 路由初始化以及注册
// @author DaBaiLuoBo

package router

import (
    "github.com/gin-gonic/gin"
    "goblog-admin/api"
    "goblog-admin/config"
)

// RouterInit 初始化先拿到Gin框架
func RouterInit() *gin.Engine {
    // 设置启动模式
    gin.SetMode(config.Config.System.Env)
    // 新建路由
    router := gin.New()
    // 设置跌机时恢复
    router.Use(gin.Recovery())
    // Register 注册
    register(router)
    // 返回路由
    return router
}

// Register 路由接口
func register(router *gin.Engine) {
    // todo 后续的所有接口 url 将在此配置
    router.GET("/api/success", api.Success)
    router.GET("/api/failed", api.Failed)
}

然后运行程序测试一下:

707744385.png

后台输出了api的相关信息:

3321343714.png

373575000.png

可以看到两个api都没问题

接入SWAG

首先先加载依赖:(根目录下执行)

go get github.com/swaggo/files
go get github.com/swaggo/gin-swagger

2443601262.png

main.go 中加入swag信息:

// 主启动程序
// @author DaBaiLuoBo

package main

import (
    "fmt"
    "goblog-admin/config"
    "goblog-admin/core"
    "goblog-admin/global"
    "goblog-admin/router"
)

// @title GoBlog运营后台
// @version 24.04.16.1
// @description GoBlog运营后台API接口文档
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization
func main() {
    // 初始化 logger
    global.Log = core.InitLogger()
    // 初始化 MySQL
    core.MysqlInit()
    // 初始化 Redis
    core.RedisInit()
    // 初始化路由
    router := router.RouterInit()
    // 拿到路由地址
    address := fmt.Sprintf("%s:%d", config.Config.System.Host, config.Config.System.Port)
    global.Log.Infof("系统启动成功,运行在: %s", address)
    // 让系统运行在指定的路由上
    router.Run(address)
}

然后在路由文件 router/router.go 中引入swag:

// 路由初始化以及注册
// @author DaBaiLuoBo

package router

import (
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
    "goblog-admin/api"
    "goblog-admin/config"
)

// RouterInit 初始化先拿到Gin框架
func RouterInit() *gin.Engine {
    // 设置启动模式
    gin.SetMode(config.Config.System.Env)
    // 新建路由
    router := gin.New()
    // 设置跌机时恢复
    router.Use(gin.Recovery())
    // Register 注册
    register(router)
    // 返回路由
    return router
}

// Register 路由接口
func register(router *gin.Engine) {
    // todo 后续的所有接口 url 将在此配置
    router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    router.GET("/api/success", api.Success)
    router.GET("/api/failed", api.Failed)
}

然后在刚才写的test路由文件 /api/test.go 中加入注释:

// 测试 API
// @author DaiBaiLuoBo

package api

import (
    "github.com/gin-gonic/gin"
    "goblog-admin/result"
)

// Success 成功测试
// @Summary 成功测试接口
// @Tags 测试相关接口
// @Produce json
// @Description 成功测试接口
// @Success 200 {object} result.Result
// @router /api/success [get]
func Success(c *gin.Context) {
    result.Success(c, 200)
}

// Failed 失败测试
// @Summary 失败测试接口
// @Tags 测试相关接口
// @Produce json
// @Description 失败测试接口
// @Success 200 {object} result.Result
// @router /api/failed [get]
func Failed(c *gin.Context) {
    result.Failed(c, int(result.ApiCode.Failed), result.ApiCode.GetMessage(result.ApiCode.Failed))
}

然后在项目根目录下执行swag初始化:

如果失败请尝试 go get -u github.com/swaggo/swag/cmd/swag 命令安装swag命令行工具
如果还不行,请更换安装方式:go install github.com/swaggo/swag/cmd/swag@latest 后再添加系统环境变量 %GOPATH%\bin (实测这个可以解决问题)

1650761443.png

初始化完成之后发现根目录中多了一个 docs 目录,回到 main.go 文件中,将该目录加入import扫描目录:

// 主启动程序
// @author DaBaiLuoBo

package main

import (
    "fmt"
    "goblog-admin/config"
    "goblog-admin/core"
    _ "goblog-admin/docs" // swag 文档目录
    "goblog-admin/global"
    "goblog-admin/router"
)

// @title GoBlog运营后台
// @version 24.04.16.1
// @description GoBlog运营后台API接口文档
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization
func main() {
    // 初始化 logger
    global.Log = core.InitLogger()
    // 初始化 MySQL
    core.MysqlInit()
    // 初始化 Redis
    core.RedisInit()
    // 初始化路由
    router := router.RouterInit()
    // 拿到路由地址
    address := fmt.Sprintf("%s:%d", config.Config.System.Host, config.Config.System.Port)
    global.Log.Infof("系统启动成功,运行在: %s", address)
    // 让系统运行在指定的路由上
    router.Run(address)
}

然后启动项目测试一下:(访问 127.0.0.1:5001/swagger/index.html

如果接口显示不出来,检查刚才加入的那些注释是不是不对,然后重新 swag init 一下!

点击 Try it outExecute 测试一下,没毛病:

本篇暂时到这里,下一篇见~