基于 Gin 模块化开发 API 框架设计

本文介绍了Go语言中的轻量级框架Gin,通过对比Flask和Beego展示了其灵活性,并分享了一种基于MVC思想搭建Gin API项目的步骤,包括配置管理、数据库连接、数据验证、路由管理和中间件的使用。同时,提供了详细的代码示例,涵盖了从项目结构到数据库操作、数据校验和路由分组等关键环节。
摘要由CSDN通过智能技术生成

一、gin项目介绍

gin框架对于写go语言的人来说入门很简单,有点类似python中的flask框架,什么都需要自己去找第三方包,然后根据自己的经验来创建目录结构,对于没有项目经验的人来说,这点真的不如同类型的beego框架,已经有清晰的目录结构,有时候我们可以说gin仅仅是一个包,算不上框架。自由组装度比较灵活,这也提现了我们开发人员的经验重要性。如何更好的搭建gin-api项目是一个难事。

以下是本人根据后端经验采用mvc的思路搭建一套基本的gin-api框架。以供大家参考使用,大家觉得好点个👍

二、需要安装的依赖包

  • gin框架包

    go get -u github.com/gin-gonic/gin
    
  • gorm数据库包

    go get -u gorm.io/gorm
    go get -u gorm.io/driver/mysql
    
  • 数据校验的包

    go get github.com/go-playground/validator
    
  • token认证的包

    go get -u github.com/dgrijalva/jwt-go
    
  • 日志管理包

    go get -u github.com/sirupsen/logrus
    go get -u github.com/lestrrat-go/file-rotatelogs
    go get -u github.com/rifflock/lfshook
    
  • 配置文件的包

    go get -u github.com/spf13/viper
    

三、项目配置文件

  • 1、在config/application.yml文件中创建项目需要的配置参数

    server:
      port: 9000
    # 数据库配置
    datasource:
      driverName: mysql
      host: localhost
      port: "3306"
      database: gin_admin_api
      username: root
      password: 123456
      charset: utf8mb4
      loc: Asia/Shanghai
    
  • 2、在main.go中定义一个初始化配置的文件

    // 初始化配置
    func InitConfig() {
    	workDir, _ := os.Getwd()
    	viper.SetConfigName("application")
    	viper.SetConfigType("yml")
    	viper.AddConfigPath(path.Join(workDir, "config"))
    	// 或者使用全路径
    	//viper.AddConfigPath(path.Join(workDir, "config/application.yml"))
    	err := viper.ReadInConfig()
    	if err != nil {
    		fmt.Print("获取配置文件错误")
    		panic(err)
    	}
    }
    
  • 3、在init函数中调用初始化配置的文件

    func init() {
    	InitConfig()
    }
    
  • 4、测试配置文件是否成功

    func main() {
    	router := gin.Default()
    	router.GET("/", func(c *gin.Context) {
    		c.JSON(http.StatusOK, gin.H{
    			"code": 1,
    		})
    	})
    	port := viper.GetString("server.port")
    	fmt.Println("当前端口", port)
    	if port != "" {
    		router.Run(":" + port)
    	} else {
    		router.Run()
    	}
    }
    
  • 5、或者可以单独到common/config文件中

    package common
    
    import (
    	"fmt"
    	"github.com/spf13/viper"
    	"os"
    	"path"
    )
    
    // 初始化配置
    func InitConfig() {
    	workDir, _ := os.Getwd()
    	viper.SetConfigName("application")
    	viper.SetConfigType("yml")
    	viper.AddConfigPath(path.Join(workDir, "config"))
    	// 或者使用全路径
    	//viper.AddConfigPath(path.Join(workDir, "config/application.yml"))
    	err := viper.ReadInConfig()
    	if err != nil {
    		fmt.Print("获取配置文件错误")
    		panic(err)
    	}
    }
    
    func init() {
    	InitConfig()
    }
    

    借用在main.go中引入的文件,那么初始化就会先执行init函数

    import (
    	...
      // 这里表示编译的时候不需要,但是运行的时候需要,不加这行下面的mian函数中是不能获取到参数的
    	_ "gin_admin_api/common" // gin_admin_api是在go.mod里面配置的module gin_admin_api,一般与项目名称一致
    	...
    )
    
    func main() {
    	...
    	port := viper.GetString("server.port")
    	fmt.Println("当前端口", port)
    	...
    }
    

四、初始化gorm数据库连接工具

  • 1、在common/database下配置数据库连接

    package common
    
    import (
    	"fmt"
    	_ "github.com/go-sql-driver/mysql"
    	"github.com/spf13/viper"
    	"gorm.io/driver/mysql"
    	"gorm.io/gorm"
    	"gorm.io/gorm/logger"
    	"log"
    	"net/url"
    	"os"
    	"time"
    )
    
    var DB *gorm.DB
    
    func init() {
    	fmt.Println("数据库连接")
    	InitDB()
    }
    
    func InitDB() *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")
    	loc := viper.GetString("datasource.loc")
    	// 字符串拼接
    	sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true&loc=%s",
    		username,
    		password,
    		host,
    		port,
    		database,
    		charset,
    		url.QueryEscape(loc),
    	)
    	fmt.Println("数据库连接:", sqlStr)
    	// 配置日志输出
    	newLogger := logger.New(
    		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
    		logger.Config{
    			SlowThreshold:             time.Second,   // 缓存日志时间
    			LogLevel:                  logger.Silent, // 日志级别
    			IgnoreRecordNotFoundError: true,          // Ignore ErrRecordNotFound error for logger
    			Colorful:                  false,         // Disable color
    		},
    	)
    	db, err := gorm.Open(mysql.Open(sqlStr), &gorm.Config{
    		Logger: newLogger,
    	})
    	if err != nil {
    		fmt.Println("打开数据库失败", err)
    		panic("打开数据库失败" + err.Error())
    	}
    	DB = db
    	return DB
    }
    
    // TODO 文档地址: https://gorm.io/zh_CN/docs/
    
  • 2、在model/Account.go的数据模型

    package model
    
    import (
    	"gorm.io/gorm"
    )
    
    type Account struct {
    	gorm.Model
    	UserName string `gorm:"type:varchar(50);column(username);not null;unique;comment:账号"`
    	Password string `gorm:"type:varchar(200);not null;comment:账号密码"`
    	Mobile   string `gorm:"varchar(11);not null;unique;comment:手机号码"`
    }
    
  • 3、在main.go中测试创建的数据模型及数据库连接工具

    func init()  {
      // 自动同步数据模型到数据表
    	common.DB.AutoMigrate(&model.Account{})
    }
    
  • 4、查看数据库的数据表这里默认会加上一个s上去,表示复数,如果要重命名表名可以参考下面代码

    // 在数据模型的实体类文件中
    
    // 自定义表名
    func (Account) TableName() string {
    	return "account"
    }
    

五、在gin中使用路由分组实现路由管理

  • 1、创建一个route的文件夹,里面负责收集全部控制器下的路由

    package route
    
    import (
    	"gin_admin_api/controller/account"
    	"gin_admin_api/controller/login"
    	"gin_admin_api/controller/register"
    	"gin_admin_api/middleware"
    	"github.com/gin-gonic/gin"
    )
    
    func CollectRoute(router *gin.Engine) {
    	// 创建账号路由分组,先忽视中间件的存在
    	accountGroup := router.Group("/account", middleware.AuthMiddleWare())
    	account.AccountRouter(accountGroup)
    	// 登录的路由
    	loginGroup := router.Group("/login")
    	login.LoginRouter(loginGroup)
     
    	registerGroup := router.Group("/register")
    	register.RegisterRouter(registerGroup)
    }
    
  • 2、比如登录的路由

    package login
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    func LoginRouter(router *gin.RouterGroup) {
    	router.POST("/", Login)
    }
    
  • 3、在main.go中使用路由组

    func main() {
    	router := gin.Default()
    	// 注册路由组
    	route.CollectRoute(router)
      ...
    }
    

六、使用数据校验实现用户注册

  • 1、在控制器下创建一个dto的文件,专门用来接收前端传递过来的数据

    package dto
    
    import (
    	"fmt"
    	"gin_admin_api/model"
    	"github.com/go-playground/validator"
    	"unicode/utf8"
    )
    var valildate *validator.Validate
    
    func init() {
    	valildate = validator.New()
    	valildate.RegisterValidation("checkName", CheckNameFunc)
    }
    
    //定义注册的结构体(前端需要发送的数据结构)
    type RegisterDto struct {
    	UserName string `validate:"required,checkName" json:"username"`
    	Password string `validate:"required" json:"password"`
    }
    
    // 自定义校验器校验用户名
    func CheckNameFunc(f validator.FieldLevel) bool {
    	count := utf8.RuneCountInString(f.Field().String())
    	if count >= 2 && count <= 12 {
    		return true
    	} else {
    		return false
    	}
    }
    
    // 定义校验数据的方法
    func ValidatorRegister(account RegisterDto) error {
    	err := valildate.Struct(account)
    	if err != nil {
    		// 输出校验错误 .(validator.ValidationErrors)是断言
    		for _, e := range err.(validator.ValidationErrors)[:1] {
    			fmt.Println("错误字段:", e.Field())
    			fmt.Println("错误的值:", e.Value())
    			fmt.Println("错误的tag:", e.Tag())
    		}
    		return err
    	} else {
    		return nil
    	}
    }
    
  • 2、在控制器中实现将前端传递过来的数据插入到数据库中

    // 用户注册账号
    func Register(c *gin.Context) {
    	// 1.获取前端传递过来的数据
    	var registerDto dto.RegisterDto
    	err := c.Bind(&registerDto)
    	if err != nil {
    		response.Fail(c, "解析前端传递的数据错误")
    		return
    	}
    	// 2.对前端传递过来的数据进行校验
    	err = dto.ValidatorRegister(registerDto)
    	if err != nil {
    		response.Fail(c, "数据校验错误")
    		return
    	}
    	// 3.将数据插入到数据库中
    	newPassword, err := utils.GeneratePassword(registerDto.Password)
    	if err != nil {
    		response.Fail(c, "密码加密错误")
    		return
    	}
      // 4.组装成数据模型的数据结构
    	account := model.Account{
    		UserName: registerDto.UserName,
    		Password: newPassword,
    	}
    	tx := common.DB.Create(&account)
    	fmt.Println(tx.RowsAffected, tx.Error)
    	if tx.RowsAffected > 0 {
    		response.Success(c, nil)
    	} else {
    		response.Fail(c, "插入数据错误")
    	}
    }
    
  • 3、关于密码加密和解密,可以参考utils里面的方法

  • 4、查看数据库是否插入成功

七、关于中间件的使用

  • 1、登录中间件可以参考文章链接地址
  • 2、跨域中间件比较固定,可以直接百度或者参考我百度的数据
  • 3、日志处理可以参考文档链接地址
gin-admin-api是一个基于Gin框架开发的后台管理系统的API接口。Gin框架是一个轻量级的、高性能的Go语言框架,具有路由和中间件的功能,适合用于构建Web应用程序。 gin-admin-api提供了一套完善的API接口,用于实现后台管理系统的各种功能,例如用户管理、角色管理、权限管理、菜单管理、日志管理等。通过这些接口,可以方便地进行用户的注册、登录和认证,管理用户的角色和权限,管理系统的菜单和日志信息。 gin-admin-api的优点之一是高性能。由于采用了Gin框架,它具有快速的路由匹配和中间件处理的能力,能够处理大量的请求,并在高并发的情况下保持稳定性和可靠性。 另一个优点是易于扩展和定制。gin-admin-api使用了模块化设计,各个功能模块之间松耦合,可以根据实际需求进行灵活的扩展和定制。例如,可以根据业务需求添加新的功能模块,或者修改和优化已有的模块。 此外,gin-admin-api还提供了友好的文档和示例代码,方便开发者理解和使用。它的源代码也是开源的,可以在GitHub上找到,这样可以方便地进行二次开发和定制,满足特定的业务需求。 总之,gin-admin-api是一个功能丰富、高性能、易扩展的后台管理系统API接口,大大简化了后台管理系统的开发工作,帮助开发者快速构建稳定、可靠的后台管理系统。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水痕01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值