Gin框架 -- 环境搭建

0. 官方文档

https://gin-gonic.com/zh-cn/docs/

1. 下载

go get github.com/gin-gonic/gin

2. Hello World

gin框架内置了httprouter包,gin中的路由库是基于httprouter实现的

main.go

package main

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

func main() {
    // 实例化gin对象
	router := gin.Default()
    
    // 设置路由和handler
	router.GET("/index", func(context *gin.Context) {
		context.String(http.StatusOK, "Hello World")
	})
    
    // 监听8002端口
	router.Run(":8002")
}

3. 配置

1. 启动配置

直接使用 http.ListenAndServe(),如下所示:

func main() {
	router := gin.Default()
	http.ListenAndServe(":8080", router)
}

func main() {
	router := gin.Default()

	s := &http.Server{
		Addr:           ":8080",
		Handler:        router,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	s.ListenAndServe()
}

2. 数据库连接配置

1. 模块下载

go get gopkg.in/ini.v1

2. 配置文件格式

#数据库类型:mysql/sqlite3
db_type = "mysql"

[mysql]
db_alias = "default"
db_name = "test"
db_user = "root"
db_pwd = "123"
db_host = "127.0.0.1"
db_port = 3306
db_charset = "utf8"


[sqlite3]
db_alias = "default"
db_name = "gin_test.db"

3. 配置文件加载

func main() {
	r := gin.Default()
 
	// 读取配置文件
	conf, err := ini.Load("./config/my.ini")
	if err != nil {
		log.Fatal("配置文件读取失败, err = ", err)
	}
 
	// 初始化路由路径
	router.InitRouter(r)
 
	// 初始化数据库
	db := models.InitDB(conf)
	defer db.Close()
 
	// 项目的启动端口在这儿设置,也可以从配置文件中读取到这儿
	port := ":" + conf.Section("").Key("httpport").String()
	if err := r.Run(port); err != nil {
		log.Fatal("程序启动失败:", err)
	}
}

3. 网站图标

1. 模块下载

go get github.com/thinkerou/favicon

2. 准备图标

在线生成工具, 并放在项目对应目录中

https://boke112.com/tools/toico/

3. 使用

package main

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

func main() {
	router := gin.Default()
	router.Use(favicon.New("./favicon.ico"))

	router.GET("/", func(context *gin.Context) {
		context.JSON(http.StatusOK, gin.H{"msg": "Hello, World"})
	})

	router.Run(":8003")
}

4. 静态文件

func main() {
	router := gin.Default()
	router.Static("/static", "./static")   // 静态文件配置
	router.StaticFS("/more_static", http.Dir("my_file_system"))
	router.StaticFile("/favicon.ico", "./resources/favicon.ico")
    
	// 监听并在 0.0.0.0:8080 上启动服务
	router.Run(":8080")
}

5. 模板文件

func main(){
    // 加载模板文件
	r.LoadHTMLGlob("template/*")
}

6. 日志

func main(){
    // 记录到文件。
	f, _ := os.Create("gin.log")
	gin.DefaultWriter = io.MultiWriter(f)
}

7. IP白名单

func main(){
    // 设置信任的客户端IP
	r.SetTrustedProxies([]string{"192.168.1.33"})
}

7. 开启DeBug模式

func main(){
    // 开启DeBug模式
	gin.SetMode(gin.DebugMode)
}

8. 配置文件读取运行端口

func main(){
    // 1. 加在配置文件
    conf, err := ini.Load("./config/my.ini")
	if err != nil {
		log.Fatal("配置文件读取失败, err = ", err)
	}
    // 2. 获取项目运行端口
    port := conf.Section("").Key("http_host").String() +":" + conf.Section("").Key("http_port").String()
	if err = r.Run(port); err != nil{
		fmt.Println("服务端启动错误:",err)
	}

}

10. Mysql连接配置

models/initDB.go

package models

import (
	"github.com/gogf/gf/os/gfile"
	"github.com/jinzhu/gorm"
	"gopkg.in/ini.v1"
	"log"
	"os"
	"path"

	// 加载MySQL数据库驱动
	_ "github.com/go-sql-driver/mysql"

	// 加载sqlite3数据库驱动
	//_ "github.com/mattn/go-sqlite3"
)

// 全局db对象
var db *gorm.DB

func InitDB(conf *ini.File) *gorm.DB {
	var err error

	// 数据库类型:mysql/sqlite3
	// db_type = "mysql"
	dbType := conf.Section("").Key("db_type").String()

	// mysql配置信息
	mysqlName := conf.Section("mysql").Key("db_name").String()       // 数据库名称
	mysqlUser := conf.Section("mysql").Key("db_user").String()       // 用户名
	mysqlPwd := conf.Section("mysql").Key("db_pwd").String()         // 密码
	mysqlHost := conf.Section("mysql").Key("db_host").String()       // 数据库ip地址
	mysqlPort := conf.Section("mysql").Key("db_port").String()       // 数据库端口
	mysqlCharset := conf.Section("mysql").Key("db_charset").String() // 指定字符集

	// sqlite3配置信息
	sqliteName := conf.Section("sqlite3").Key("db_name").String()

	var dataSource string
	switch dbType {
	case "mysql":
                // parseTime=true 表示自动解析为时间
		dataSource = mysqlUser + ":" + mysqlPwd + "@tcp(" + mysqlHost + ":" + mysqlPort + ")/" + mysqlName + "?charset=" + mysqlCharset + "&parseTime=true"
		db, err = gorm.Open(dbType,dataSource)
	case "sqlite3":
		dataSource = "database" + string(os.PathSeparator) + sqliteName
		if !gfile.Exists(dataSource){
			os.MkdirAll(path.Dir(dataSource),os.ModePerm)
			os.Create(dataSource)
		}
		db, err = gorm.Open(dbType,dataSource)
	}

	if err != nil{
		db.Close()
		log.Println("数据库加载失败",err)
	}

        // 设置数据库操作显示原生SQL 语句
	Db.LogMode(true)

        // 数据库表动态迁移
	db.AutoMigrate(&auth.User{})

	// 设置数据库连接池空闲连接数
	db.DB().SetConnMaxIdleTime(50)

	// 打开连接
	db.DB().SetMaxOpenConns(100)
        

	// 表明禁用后缀加s
	db.SingularTable(true)

        
	return db
}

main.go

func main(){
    // 初始化数据库
	db := models.InitDB(conf)
	defer db.Close()   
}

11. 多服务运行

1. 参考博客

https://github.com/gin-gonic/gin/issues/346

2. 多服务代码示例

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
)

var (
	g errgroup.Group
)

func router01() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code":  http.StatusOK,
				"error": "Welcome server 01",
			},
		)
	})

	return e
}

func router02() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code":  http.StatusOK,
				"error": "Welcome server 02",
			},
		)
	})

	return e
}

func main() {
	server01 := &http.Server{
		Addr:         ":8080",
		Handler:      router01(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	server02 := &http.Server{
		Addr:         ":8081",
		Handler:      router02(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	g.Go(func() error {
		return server01.ListenAndServe()
	})

	g.Go(func() error {
		return server02.ListenAndServe()
	})

	if err := g.Wait(); err != nil {
		log.Fatal(err)
	}
}

3. 在handler中使用goroutine

goroutine机制可以方便地实现异步处理.另外,在启动新的goroutine时,不应该使用原始上下文,必须使用它的只读副本

package main

import (
    "log"
    "time"

    "github.com/gin-gonic/gin"
)

func main() {
    // 1.创建路由
    // 默认使用了2个中间件Logger(), Recovery()
    r := gin.Default()
    // 1.异步
    r.GET("/long_async", func(c *gin.Context) {
        // 需要搞一个副本
        copyContext := c.Copy()
        // 异步处理
        go func() {
            time.Sleep(3 * time.Second)
            log.Println("异步执行:" + copyContext.Request.URL.Path)
        }()
    })
    // 2.同步
    r.GET("/long_sync", func(c *gin.Context) {
        time.Sleep(3 * time.Second)
        log.Println("同步执行:" + c.Request.URL.Path)
    })

    r.Run(":8000")
}

4. 在中间件中使用goroutine

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

	r.GET("/long_async", func(c *gin.Context) {
		// 创建在 goroutine 中使用的副本
		cCp := c.Copy()
		go func() {
			// 用 time.Sleep() 模拟一个长任务。
			time.Sleep(5 * time.Second)

			// 请注意您使用的是复制的上下文 "cCp",这一点很重要
			log.Println("Done! in path " + cCp.Request.URL.Path)
		}()
	})

	r.GET("/long_sync", func(c *gin.Context) {
		// 用 time.Sleep() 模拟一个长任务。
		time.Sleep(5 * time.Second)

		// 因为没有使用 goroutine,不需要拷贝上下文
		log.Println("Done! in path " + c.Request.URL.Path)
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	r.Run(":8080")
}

4. 配置文件的设置与读取

1. yaml 模块

yaml 配置文件

2. viper 模块

1. 模块安装

go get github.com/spf13/viper

2. 配置文件准备

config/settings.yaml0

mysql:
  host: 81.70.168.242
  port: 3306
  db: gin_demo
  user: root
  password: 123456
  max-idle-conns: 10
  max-open-conns: 100
  log_level: dev
  config: charset=utf8mb4&parseTime=True&loc=Local
system:
  host: "0.0.0.0"
  port: 8848
  env: debug

3. 基本使用

core/conf.go

package core

import (
	"fmt"
	"github.com/spf13/viper"
)

func InitConfig() {
	viper.SetConfigName("settings") // 设置配置的名字
	viper.AddConfigPath("config")   // 设置配置文件路径
	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Sprintf("读取配置文件错误: %s", err))
	}
}

main.go

package main

import (
	"fmt"
	"gin_demo/core"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"net/http"
)

func main() {

	// 1. 加载文件
	core.InitConfig()

	// 使用 viper 读取 yaml 文件中的对应配置名下的所有配置项
	fmt.Println(viper.Get("mysql")) // map[string]string 类型

	router := gin.Default()

	router.GET("/index", func(context *gin.Context) {
		context.String(http.StatusOK, "Hello World")
	})
    
    // 使用 viper 读取 yaml 文件中 system 配置名中的 host port 配置项 
	err := router.Run(viper.GetString("system.host") + ":" + viper.GetString("system.port"))

	if err != nil {
		fmt.Println("服务器启动err: ", err)
		return
	}
}
posted @ 2021-12-21 14:11  河图s  阅读(691)  评论(0)    收藏  举报