Gin微服务框架_golang web框架_完整示例Demo

news/2024/11/26 11:51:43/

Gin简介

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站

Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点。其实对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。

gin特点
  • 性能优秀
  • 基于官方的net/http的有限封装
  • 方便 灵活的中间件
  • 数据绑定很强大
  • 社区比较活跃

官方源代码地址: https://github.com/gin-gonic/gin

gin web微服务框架示例

总体功能

  • 集成logrus.Logger日志按天切割,json格式打印
  • 集成swagger文档
  • 指定yml配置文件启动
  • 异常处理
  • 拦截器打印请求和响应参数
main.go项目入口

init方法: 初始化相关配置
main方法: 上面的注释定义了swagger信息,然后gin初始化,路由初始化,是否启用swagger


package mainimport ("flag""fmt". "gin_demo/config"_ "gin_demo/docs". "gin_demo/log""gin_demo/router""github.com/gin-gonic/gin""github.com/swaggo/gin-swagger""github.com/swaggo/gin-swagger/swaggerFiles""runtime""time"
)var version = flag.Bool("version", true, "是否打印版本,默认打印")
var swagger = flag.Bool("swagger", true, "是否启动swagger接口文档,默认不启动")
var configFile = flag.String("configFile", "config/config.yml", "配置文件路径")
var projectPath = flag.String("projectPath", "/gin_demo", "项目访问路径前缀")func init(){flag.Parse()ConfigRead(*configFile)LogInit()
}//@title gin示例 API
//@version 0.0.1
//@description  相关接口文档
//@host 127.0.0.1:8080
//@BasePath
func main() {if *version {showVersion := fmt.Sprintf("%s %s@%s", "gin_demo", "1.0.0", time.Now().Format("2006-01-02 15:04:05"))fmt.Println(showVersion)fmt.Println("go version: " + runtime.Version())}Log.Info("start server...")gin.SetMode(gin.DebugMode) //全局设置环境,此为开发环境,线上环境为gin.ReleaseModerouter.GinInit()//gin工程实例 *gin.Enginer := router.Router//路由初始化router.SetupRouter(*projectPath)if *swagger {//启动访问swagger文档r.GET(*projectPath + "/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))}Log.Info("listen on :%s", Cfg.ListenPort)//监听端口r.Run(":" + Cfg.ListenPort)}
router.go 路由
package routerimport ("github.com/gin-gonic/gin""net/http"
)var Router *gin.Enginefunc GinInit()  {// 禁用控制台颜色//gin.DisableConsoleColor()//gin.New()返回一个*Engine 指针//而gin.Default()不但返回一个*Engine 指针,而且还进行了debugPrintWARNINGDefault()和engine.Use(Logger(), Recovery())其他的一些中间件操作Router = gin.Default()//Router = gin.New()
}func SetupRouter(projectPath string) {//使用日志//Router.Use(gin.Logger())//使用Panic处理方案//Router.Use(gin.Recovery())Router.Use(InitErrorHandler)Router.Use(InitAccessLogMiddleware)// 未知调用方式Router.NoMethod(InitNoMethodJson)// 未知路由处理Router.NoRoute(InitNoRouteJson)// PingRouter.GET(projectPath + "/ping", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"ping": "pong",})})Router.POST(projectPath + "/pp", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"ping": "post",})})}
middleware.go 中间件拦截器
package routerimport ("encoding/json". "gin_demo/log". "gin_demo/threadlocal""github.com/gin-gonic/gin". "github.com/jtolds/gls""github.com/sirupsen/logrus""io/ioutil""net/http""strconv""time"
)// ErrorHandler is a middleware to handle errors encountered during requests
func InitErrorHandler(c *gin.Context) {c.Next()if len(c.Errors) > 0 {c.JSON(http.StatusBadRequest, gin.H{"errors": c.Errors,})}
}//未知路由处理 返回json
func InitNoRouteJson(c *gin.Context) {c.JSON(http.StatusNotFound, gin.H{"code": http.StatusNotFound,"msg":  "path not found",})
}//未知调用方式 返回json
func InitNoMethodJson(c *gin.Context) {c.JSON(http.StatusMethodNotAllowed, gin.H{"code": http.StatusMethodNotAllowed,"msg":  "method not allowed",})
}//打印请求和响应日志
func InitAccessLogMiddleware(c *gin.Context) {//request idrequestId := c.Request.Header.Get("X-RequestId")if requestId == "" {requestId = strconv.FormatInt(time.Now().UnixNano(), 10)}//response requestIdc.Writer.Header().Set("X-RequestId", requestId)// 开始时间startTime := time.Now()//处理请求 do chianMgr.SetValues(Values{Rid: requestId}, func() {c.Next()})// 结束时间endTime := time.Now()// 执行时间latencyTime := endTime.Sub(startTime)// 请求方式reqMethod := c.Request.Method// 请求路由reqUri := c.Request.RequestURI// 状态码statusCode := c.Writer.Status()// 请求IPclientIP := c.ClientIP()//请求参数body, _ := ioutil.ReadAll(c.Request.Body)//返回参数responseMap := c.KeysresponseJson, _ := json.Marshal(responseMap)//日志格式//LogAccess.Infof("| %3d | %13v | %15s | %s | %s | %s | %s | %s |",//	statusCode,//	latencyTime,//	clientIP,//	reqMethod,//	reqUri,//	requestId,//	string(body),//	string(responseJson),//)// 日志格式LogAccess.WithFields(logrus.Fields{"status_code":  statusCode,"latency_time": latencyTime,"client_ip":    clientIP,"req_method":   reqMethod,"req_uri":      reqUri,"req_Id":       requestId,"req_body":     string(body),"res_body":     string(responseJson),}).Info()}
logger.go 日志定义和配置
package logimport ("fmt""gin_demo/config""github.com/sirupsen/logrus"rotatelogs "github.com/lestrrat-go/file-rotatelogs""github.com/rifflock/lfshook""os""path""time"
)var Log *logrus.Logger
var LogAccess *logrus.Loggerfunc LogInit() {logFilePath := ""logPath := config.Cfg.LogPathif len(logPath) == 0 {//获取当前目录if dir, err := os.Getwd(); err == nil {logFilePath = dir + "/logs/"}} else {//指定目录logFilePath = logPath + "/logs/"}if err := os.MkdirAll(logFilePath, 0777); err != nil {fmt.Println(err.Error())}rootLogInit(logFilePath)accessLogInit(logFilePath)
}func rootLogInit(logFilePath string) {logFileName := "root.log"//日志文件fileName := path.Join(logFilePath, logFileName)if _, err := os.Stat(fileName); err != nil {if _, err := os.Create(fileName); err != nil {fmt.Println(err.Error())}}//写入文件src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)if err != nil {fmt.Println("err", err)}//实例化Log = logrus.New()//设置输出Log.Out = srcLog.Out = os.Stdout//设置日志级别Log.SetLevel(logrus.DebugLevel)// 设置 rotatelogslogWriter, err := rotatelogs.New(// 分割后的文件名称fileName + "-%Y%m%d.log",// 生成软链,指向最新日志文件rotatelogs.WithLinkName(fileName),// 设置最大保存时间(2天)rotatelogs.WithMaxAge(2*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",})// 新增 HookLog.AddHook(lfHook)}func accessLogInit(logFilePath string) {logFileNameAccess := "access.log"fileNameAccess := path.Join(logFilePath, logFileNameAccess)if _, err := os.Stat(fileNameAccess); err != nil {if _, err := os.Create(fileNameAccess); err != nil {fmt.Println(err.Error())}}srcAccess, err := os.OpenFile(fileNameAccess, os.O_APPEND|os.O_WRONLY, os.ModeAppend)if err != nil {fmt.Println("err", err)}//实例化LogAccess = logrus.New()//设置输出LogAccess.Out = srcAccessLogAccess.Out = os.Stdout//设置日志级别LogAccess.SetLevel(logrus.DebugLevel)// 设置 rotatelogslogWriterAccess, err := rotatelogs.New(// 分割后的文件名称fileNameAccess + "-%Y%m%d.log",// 生成软链,指向最新日志文件rotatelogs.WithLinkName(fileNameAccess),// 设置最大保存时间(2天)rotatelogs.WithMaxAge(2*24*time.Hour),// 设置日志切割时间间隔(1天)rotatelogs.WithRotationTime(24*time.Hour),)writeMapAccess := lfshook.WriterMap{logrus.InfoLevel:  logWriterAccess,logrus.FatalLevel: logWriterAccess,logrus.DebugLevel: logWriterAccess,logrus.WarnLevel:  logWriterAccess,logrus.ErrorLevel: logWriterAccess,logrus.PanicLevel: logWriterAccess,}lfHookAccess := lfshook.NewHook(writeMapAccess, &logrus.JSONFormatter{TimestampFormat:"2006-01-02 15:04:05",})// 新增 HookLogAccess.AddHook(lfHookAccess)
}
Demo运行

swag 的安装使用后续会讲解

#执行:swag init 生成swagger文件
gin_demo git:(main) swag init
#显示如下,会在项目生成docs文件夹
2021/07/23 21:30:36 Generate swagger docs....
2021/07/23 21:30:36 Generate general API Info
2021/07/23 21:30:36 create docs.go at  docs/docs.go#启动项目
go run main.go 
#打印如下,表示成功启动8080端口
Listening and serving HTTP on :8080

在这里插入图片描述

浏览器访问接口:
http://127.0.0.1:8080/gin_demo/ping

{“ping”:“pong”}

浏览器访问swagger:

在这里插入图片描述

Demo源代码地址:https://github.com/tw-iot/gin_demo

参考链接地址:
http://www.topgoer.com/gin%E6%A1%86%E6%9E%B6/%E7%AE%80%E4%BB%8B.html
https://zhuanlan.zhihu.com/p/165633941
https://github.com/skyhee/gin-doc-cn
https://www.jianshu.com/p/98965b3ff638


http://www.ppmy.cn/news/350662.html

相关文章

APP性能测试,你需要关注哪些指标?

一、Android客户端性能测试常见指标 1、内存 2、CPU 3、流量 4、电量 5、启动速度 6、滑动速度、界面切换速度 7、与服务器交互的网络速度 二、预期标准指定原则 1、分析竞争对手的产品,所有指标要强于竞品 2、产品经理给出的预期性能指标数据 3、符合业…

网易云ncm文件转mp3

本人卖了一个ipod nano6,帮买家导些歌,结果用网易云下下来一堆ncm文件,一脸懵逼,因为ipod只能放mp3文件。上网查了一下ncm文件,只能在会员有效期内放这个歌。 于是上网查了下,发现GitHub上有例程代码可以破…

SYRE蓝牙表带:让iPod nano支持蓝牙耳机

众所周知 iPod nano是个很神奇的产品,不单单可以听歌,还可以当作手表。但是,把iPod nano当作手表戴在手上了以后接上耳机线连接在手上不觉得很奇怪吗?有时候会因为动作太大会拉扯到耳机带来不便,或者是把耳机活生生从耳…

nano怎么设置一开始就显示时针

nano6 按下电源键时,是显示正式播放或目录啥的。 如果想把它当作手表的话,是一开始就显示时钟。 设置如下: 设置→通用→日期与时间→唤醒时显示时间 解决办法来自于下面的视频3分12秒 http://v.youku.com/v_show/id_XMzUwMDUxODUy.html…

鸟哥的linux私房菜学习笔记 ---第5章-2

1,bc 简易计算器2,[ctrl]d end of file3,~代表用户的主文件夹,是个变量 root的主文件夹在 /root4,sync 将内存中的数据写入到硬盘中,一般在关机之前必做步骤,好的习惯5,nano 简单好用的文本编辑器 nano 文件名直接打开新或已有文件 可以直接…

ubuntu18.04 安装melodic 版本ros

1 打开软件更新 选择清华源代码,点击关闭后,选择弹出的提示更新软件源。 2。设置软件源 sudo sh -c . /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ $DISTRIB_CODENAME main" > /etc/apt/sou…

Python实现BP网络并进行语音识别(三)

title: Python实现BP网络并进行语音识别(三) date: 2019-06-09 20:45:40 tags: [python, BP, 语音识别] 前言 在深度学习领域,一份好的数据决定了成功的一半。为了得到优质的声音样本,我特意选取了三位相声大师的单口相声&#…

dpkg 被中断问题解决方法

linux系统安装软件是有时会碰到“dpkg 被中断,您必须手工运行 sudo dpkg –configure -a解决此问题”,然而按照提示运行却并没能很好的解决问题。其实导致这个问题的主要原因是因为/var/lib/dpkg/updates文件下的文件有问题,可能是其他软件安装过程或是其…