一、项目创建
- api:请求方法
- config:项目配置
- core:核心库
- result:结果返回集
- global:全局共享数据
- middleware:中间件
- mode:模型
- router:路由
- utils:工具类
- constant:常量化
- config.yaml:配置文件
- main.go:启动程序
二、系统配置
2.1 依赖下载
go get gopkg.in/yaml.v2
2.2 在config.yaml配置数据信息
# 系统配置
system:
host: "0.0.0.0"
port: 5001
env: debug
# env: releose
2.3 在config文件夹下新建config.go文件
// 读取配置文件
// @author Percy
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 := os.ReadFile("./config.yaml")
if err != nil {
return
}
yaml.Unmarshal(yamlFile, &Config)
}
三、日志配置
3.1 下载依赖
go get github.com/sirupsen/logrus
3.2 在config.yaml配置数据信息
# logger 日志
logger:
level: info
prefix: "[gin-admin-api]"
director: logger
show_line: true
log_in_console: true
3.3 在config.go新增日志配置
// 读取配置文件
// @author Percy
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:"perfix"`
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
}
yaml.Unmarshal(yamlFile, &Config)
}
3.4 在core文件夹下新建logger.go文件,对日志信息进行自定义
// 日志配置
// @author Percy
package core
import (
"bytes"
"fmt"
"github.com/sirupsen/logrus"
"os"
"path"
"server/config"
)
// 颜色
const (
red = 31
yellow = 33
blue = 36
gray = 37
)
type LogFormatter struct{}
// Format 实现Formatter(entry *logurs.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, funcVal, fileVal, entry.Message)
} else {
fmt.Fprintf(b, "%s[%s] \x1b[%dm[%s]\x1b[0m] %s %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
}
3.5 在global文件夹下新建global.go文件
// 全局共享配置
// @author Percy
package global
var (
Log *logrus.Logger
)
3.6 调用
// 初始化logger
global.Log = core.InitLogger()
global.Log.Warnln("go的日志 -> 警告(颜色黄)")
global.Log.Error("go的日志 -> 异常(颜色红)")
global.Log.Infof("go的日志 -> 正常(颜色蓝)")
四、mysql配置
4.1 下载依赖
// mysql依赖
go get -u gorm.io/driver/mysql
// gorm依赖
go get -u gorm.io/gorm
4.2 在config.yaml配置数据信息
# mysql 配置
mysql:
host: 127.0.0.1
port: 3306
db: gin-blog # 数据库名称
username: root
password: root
log_level: dev
charset: utf8
max_idle: 50
max_open: 150
4.3 在config.go新增日志配置
// config 总配置文件
type config struct {
Mysql mysql `yaml:"mysql"`
}
// 数据库配置
type mysql struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Db string `yaml:"db"`
Username string `yaml:"username"`
Password string `yaml:"password"`
LogLevel string `yaml:"log_level"`
Charset string `yaml:"charset"`
MaxIdle int `yaml:"max_idle"`
MaxOpen int `yaml:"max_open"`
}
4.4 调用
global.log.Infof("mysql配置:%s",config.Config.Mysql)
4.5 在core文件夹下新建mysql.go文件
// mysql初始化配置
// @author Percy
package core
var Db *gorm.DB
func MysqlInit() err {
var err error
var dbConfig = config.Config.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.Db,
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 err
}
sqlDb, err := Db.DB()
sqlDb.SetMaxIdleConns(dbConfig.MaxIdle)
sqlDb.setMaxOpenConns(dbConfig.MaxOpen)
global.Log.Infof("[mysql]连接成功")
return nil
}
4.6 在main.go文件初始化数据库
// 初始化mysql
core.MysqlInit()
五、redis配置
5.1下载依赖
go get github.com/go-redis/redis/v8
5.2 在config.yaml配置数据信息
# redis配置
redis:
address: 127.0.0.1:6379
password: 123456
db: 0
5.3 在config.go新增日志配置
// config 总配置文件
type config struct {
Redis redis`yaml:"redis"`
}
// 数据库配置
type redis struct {
Address string `yaml:"address"`
Password string `yaml:"password"`
Db string `yaml:"db"`
}
5.4 在global.go文件添加上下文
var (
Log *logger.Logger
// 上下文
Ctx = context.Background()
)
5.5 在core文件夹下新建redis.go文件
// redis初始化配置
// @author Percy
package core
var RedisDb *redis.Client
func RedisInit() err {
RedisDb = redis.NewClient(&redis.Options{
Addr: config.Config.Redis.Address,
Password: config.Config.Redis.Password,
DB: config.Config.Redis.Db
})
_, err := RedisDb.Ping(global.Ctx).Result()
if err != nil {
return err
}
global.Log.Infof("[redis]连接成功")
return nil
}
5.6 在main.go文件初始化redis
// 初始化redis
core.RedisInit()
六、初始化路由
6.1 在router文件夹下新建router.go文件,并编写初始化函数
func InitRouter() *gin.Engine {
// 设置启动模式
gin.SetMode(config.Config.System.Env)
router := gin.New()
// 跌机时恢复
router.Use(gin.Recovery())
return router
}
func register(router *gin.Engine) {
// todo 后续接口url
}
6.2 在main.go调用
// 初始化路由
router := router.InitRouter()
address := fmt.Sprintf("%s:%d",config.Config.System.Host, config.Config.System.Port)
global.Log.Infof("系统启动成功,运行在:%s",address)
router.Run(address)
七、通用结构返回
7.1 定义状态码和对应的错误信息
// 状态码和状态信息定义
// @author Percy
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 {
messge, ok := c.Message[code]
if !ok {
return ""
}
return messge
}
7.2 结构体返回
// 结构数据定义
// @author Percy
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{}
}
res := Result{}
res.Code = int(ApiCode.Success)
res.Message = ApiCode.GetMessage(ApiCode.Success)
res.Data = data
c.JSON(http.StatusOK, res)
}
// Failed 失败
func Failed(c *gin.Context, code int, message string) {
res := Result{}
res.Code = code
res.Message = message
res.Data = gin.H{}
c.JSON(http.StatusOK, res)
}
八、接入swag
8.1 下载依赖
go get github.com/swaggo/files
go get github.com/swaggo/gim-swagger
8.2 swag接口注释方法
// GetSysRoleList 分页查询角色列表
// @Summary 分页查询角色列表
// @Tags 角色相关接口
// @Produce json
// @Description 分页查询角色列表
// @Param pageNum query int false "分页数"
// @Param pageSize query int false "每页数"
// @Param roleName query string false "角色名称"
// @Param status query string false "账号启用状态:1->启用,2->禁用"
// @Param beginTime query string false "开始时间"
// @Param endTime query string false "结束时间"
// @Success 200 {object} result.Result
// @router /api/sysRole/list [get]
func GetSysRoleList(c *gin.Context) {
PageNum, _ := strconv.Atoi(c.Query("pageNum"))
PageSize, _ := strconv.Atoi(c.Query("pageSize"))
RoleName := c.Query("roleName")
Status := c.Query("status")
BeginTime := c.Query("beginTime")
EndTime := c.Query("endTime")
if PageSize < 1 {
PageSize = 10
}
if PageNum < 1 {
PageNum = 1
}
var sysRole []model.SysRole
var count int64
curDb := Db.Table("sys_role")
if RoleName != "" {
curDb = curDb.Where("role_name = ?", RoleName)
}
if BeginTime != "" && EndTime != "" {
curDb = curDb.Where("crete_time BETWEEN ? AND ?", BeginTime, EndTime)
}
if Status != "" {
curDb = curDb.Where("status = ?", Status)
}
curDb.Count(&count).Limit(PageSize).Offset(PageNum - 1).Order("create_time DESC").Find(&sysRole)
result.Success(c, map[string]interface{}{"total": count, "pageSize": PageSize, "pageNum": PageNum, "list": sysRole})
}
8.3 使用,swag init会自动创建一个docs文件夹存放文件
// 对swag初始化,每次添加swag接口注释都要重新初始化一下
swag init
// 在main.go文件夹导入调用docs的init函数
import (
···
_ "server/docs"
)
// 在浏览器输入 http://localhost:5001/swagger/index.html