Go (Gin+Gorm+swagger)搭建项目框架

原文章:https://zhuanlan.zhihu.com/p/605869965
如有侵权请联系我

代码结构
    constants                          # 定义常量目录
        state.go 
    db                                 # 数据库连接初始化
        core.go
    handler                            # 控制器
        ......
    middleware                         # 中间件
        ......
    models                             # 模型
        ......
    routers                            # 路由
        router.go
    service                            # 服务层,业务逻辑处理,与models交互操作数据库
        ......
    types                              # 状态码,状态信息
        code.go
    util                               # 工具包
        encrypt.go
        result.go
    .gitignore
    gin-blog
    go.mod 
    main.go
    README.md

一. 项目初始化

cd /Users/cc/goproject  # go项目目录mkdir gin-blog # 创建项目
➜ go mod init gin-blog
➜ go get -u github.com/gin-gonic/gin
➜ go get -u gorm.io/gorm
➜ go get -u gorm.io/driver/mysql
1. vim main.go测试ping
package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func main() {
    r :=  gin.Default()
    r.Use(gin.Logger())
    r.Use(gin.Recovery())

    r.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "success...",
        })
    })

    r.Run(":8080")
}

运行 go run main.go启动项目
运行 go build编译项目

2. 配置热重载

fresh

# 项目目录gin-blog下执行
➜ go get github.com/pilu/fresh
➜ go install github.com/pilu/fresh	// fresh命令无法识别执行
➜ fresh
3. 设计状态码 && 提示信息

vim types/code.go

package types

type Codes struct {
    SUCCESS  uint
    FAILED   uint
    GENERATETOKEN uint
    NOAUTH uint
    AUTHFAILED uint
    AUTHFORMATERROR uint
    INVALIDTOKEN uint
    NOSUCHID uint
    CREATEUSERFAILED uint
    LCAKPARAMETERS uint
    CONVERTFAILED uint
    NOSUCHNAME uint
    EXISTSNAME uint
    Message  map[uint]string
}

var ApiCode = &Codes{
    SUCCESS: 200,
    FAILED: 0,
    AUTHFAILED: 4001,
    GENERATETOKEN: 4002,
    NOAUTH: 4003,
    AUTHFORMATERROR: 4004,
    INVALIDTOKEN: 4005,
    NOSUCHID: 1001,
    CREATEUSERFAILED: 2001,
    LCAKPARAMETERS: 3001,
    CONVERTFAILED: 3002,
    NOSUCHNAME: 5001,
    EXISTSNAME: 5002,
}

func init()  {
    ApiCode.Message = map[uint]string{
        ApiCode.SUCCESS: "成功",
        ApiCode.FAILED:  "失败",
        ApiCode.GENERATETOKEN: "生成Token失败",
        ApiCode.AUTHFAILED: "鉴权失败",
        ApiCode.NOAUTH: "请求头中auth为空",
        ApiCode.AUTHFORMATERROR: "请求头中auth格式有误",
        ApiCode.INVALIDTOKEN:"无效的Token",
        ApiCode.NOSUCHID: "id不存在",
        ApiCode.CREATEUSERFAILED: "用户创建失败",
        ApiCode.LCAKPARAMETERS: "缺少参数",
        ApiCode.CONVERTFAILED: "参数类型转换报错",
        ApiCode.NOSUCHNAME: "根据名称查不到数据",
        ApiCode.EXISTSNAME: "名称重复",
    }
}

func (c *Codes) GetMessage(code uint) string {
    message, ok := c.Message[code]
    if !ok {
        return ""
    }
    return message
}
4. 封装统一APT返回格式

vim util/result.go

package util

import (
    "gin-blog/types"
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)

//返回的结果:
type Result struct {
    Time  time.Time   `json:"time"`
    Code  int         `json:"code"`
    Msg   string      `json:"msg"`
    Data  interface{} `json:"data"`
}

//成功
func Success(c *gin.Context, data interface{}) {
    if (data == nil) {
        data = gin.H{}
    }
    res := Result{}
    res.Time = time.Now()
    res.Code = int(types.ApiCode.SUCCESS)
    res.Msg = types.ApiCode.GetMessage(types.ApiCode.SUCCESS)
    res.Data = data

    c.JSON(http.StatusOK,res)
}

//出错
func Error(c *gin.Context, code int,msg string) {
    res := Result{}
    res.Time = time.Now()
    res.Code = code
    res.Msg = msg
    res.Data = gin.H{}

    c.JSON(http.StatusOK,res)
}
5. 封装md5加密

vim util/encrypt.go

package util

import (
    "crypto/md5"
    "encoding/hex"
)

//EncryMd5
func EncryMd5(s string) string {
    ctx := md5.New()
    ctx.Write([]byte(s))
    return hex.EncodeToString(ctx.Sum(nil))
}
6. 封装连接mysql

vim db/core.go

package core

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
    "gorm.io/gorm/schema"
)

// 定义db全局变量
var Db *gorm.DB

func init() {
    var err error
    dsn := "root:root@tcp(127.0.0.1:3306)/gin-blog-api?charset=utf8mb4&parseTime=True&loc=Local"
    Db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
        SkipDefaultTransaction: false,
        NamingStrategy: schema.NamingStrategy{
            SingularTable: true, // 禁用表名加s
        },
        Logger: logger.Default.LogMode(logger.Info),// 打印sql语句
        DisableAutomaticPing: false,
        DisableForeignKeyConstraintWhenMigrating: true, // 禁用创建外键约束
    })
    if err != nil {
        panic("Connecting database failed: " + err.Error())
    }
}

//GetDB
func GetDB() *gorm.DB {
    return Db
}
7. 路由设计示例

vim routers/router.go

package routers

import (
    "gin-blog/handler"
    "gin-blog/middleware"
    "github.com/gin-gonic/gin"
)

func InitRouter() {
    r := gin.Default()

    // 管理后台
    // 管理员登陆
    r.POST("/login", handler.AuthLogin)

    // 管理员路由组
    userGroup := r.Group("/user/v1")
    userGroup.Use(middleware.AuthMiddleware())
    {
        userGroup.POST("/create-user", handler.CreateUser)
        userGroup.GET("/get-users", handler.GetUsers)
        userGroup.POST("/del-user-by-id", handler.DeleteUserById)
        userGroup.GET("/get-user-by-id", handler.GetUserById)
        userGroup.POST("/update-user-by-id", handler.UpdateUserById)
        userGroup.POST("/disable-user-by-id", handler.DisableUserById)
        userGroup.POST("/enable-user-by-id", handler.EnableUserById)

    }

    // 标签路由组
    tagsGroup := r.Group("/tags/v1")
    tagsGroup.Use(middleware.AuthMiddleware())
    {
        tagsGroup.POST("/create-tags", handler.CreateTags)
        tagsGroup.GET("/get-tags-list", handler.GetTagsList)
        tagsGroup.POST("/update-Tags-by-id", handler.UpdateTagsById)
        tagsGroup.POST("/del-tags-by-id", handler.DeleteTagsById)
    }

    // 分类路由组
    cateGroup := r.Group("/cate/v1")
    cateGroup.Use(middleware.AuthMiddleware())
    {
        cateGroup.POST("/create-cate", handler.CreateCate)
        cateGroup.GET("/get-cate-list", handler.GetCateList)
        cateGroup.POST("/update-cate-by-id", handler.UpdateCateById)
        cateGroup.POST("/del-cate-by-id", handler.DeleteCateById)
    }

    // 文章路由组
    postsGroup := r.Group("/posts/v1")
    postsGroup.Use(middleware.AuthMiddleware())
    {
        postsGroup.POST("/create-post", handler.CreatePost)
        postsGroup.GET("/get-posts-list", handler.GetPostsList)
        postsGroup.POST("/update-post-by-id", handler.UpdatePostById)
        postsGroup.POST("/del-post-by-id", handler.DeletePostById)
    }

    // 文章评论路由组
    commentGroup := r.Group("/comment/v1")
    {
        commentGroup.POST("/create-comment", handler.CreateComment)
        commentGroup.GET("/get-comment-list", handler.GetCommentList)
        commentGroup.POST("/del-comment-by-id", handler.DelCommentById)
    }

    // 友联路由组
    linkGroup := r.Group("/link/v1")
    {
        linkGroup.POST("/create-link", handler.CreateLink)
        linkGroup.GET("/get-link-list", handler.GetLinkList)
        linkGroup.POST("/update-link-by-id", handler.UpdateLinkById)
        linkGroup.POST("/del-link-by-id", handler.DeleteLinkById)
    }

    r.Run(":8080")
}

二. api文档

1. 安装
go get -u github.com/swaggo/swag/cmd/swag
go install -u github.com/swaggo/swag/cmd/swag	// swag命令无法识别执行
go get -u -v github.com/swaggo/gin-swagger
go get -u -v github.com/swaggo/files
2. go-swapper注解规范说明
注解描述
@Summary摘要
@Description接口描述
@Tags接口的标签,用来给 API 分组的
@Accept接口接收入参的类型,支持mpfd(表单),json 等
@Produce接口返回的出参类型,支持mpfd(表单),json 等
@Param参数格式,从左到右分别为:参数名、入参类型、数据类型、是否必填、注释
@Success响应成功,从左到右分别为:状态码、参数类型、数据类型、注释
@Failure响应失败,从左到右分别为:状态码、参数类型、数据类型、注释
@Router路由,从左到右分别为:路由地址,HTTP 方法

示例demo:

// @Summary	测试接口
// @Produce	json
// @Param		token	header		string			true	"token"
// @Param		page	query		int				true	"page"
// @Param		size	query		int				true	"size"
// @Success	200		{object}	[]modle.Role	"成功"
// @Failure 400 {object} string "请求错误"
// @Router		/api/test [get]
func test(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, "Ok")
}
3. 生成接口文档数据
swag fmt	// 格式化swag注解
swag init	// 在项目根目录执行以下命令,使用swag工具生成接口文档数据。

注:使用热部署时,执行命令后需要再保存一次,触发第二次热部署后doc.json才会更新

执行完毕生成一下文件

docs
--dosc.go
--swagger.json
--swager.yaml
4. 引入gin-swagger渲染文档数据
import (
	"github.com/gin-gonic/gin"
	"github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
	_ "github/mwqnice/swag/docs" // 千万不要忘了导入把你上一步生成的docs
)

//添加swagger访问路由
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

启动项目,在浏览器中输入地址:http://127.0.0.1:[项目端口]/swagger/index.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值