栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

gin框架的安装使用(路由冲突conflict、URL处理规则、请求参数以及参数绑定)

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力
一、gin入门 1、创建go module项目步骤

1、file——》go modeles——创建

2、设置代理:

setting——》go Modules

GOPROXY=https://mirrors.aliyun.com/goproxy/,direct;

3、在go.mod中引入gin

require github.com/gin-gonic/gin v1.6.3/

如果没有安装gin,在引入gin后使用go mod tidy就会自动下载(或者直接下载)
go get -u github.com/gin-gonic/gin

4、创建main.go

package main

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

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

	engine.GET("/helloworld", func(c *gin.Context){
		c.String(http.StatusOK, "hello world")
	})

	//返回JSON格式的数据
	engine.GET("/json", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"name": "admin",
			"age": 18,
		})
	})

	//返回xml格式的数据
	engine.GET("/xml", func(c *gin.Context) {
		c.XML(http.StatusOK, gin.H{
			"name": "zhangsan",
			"age": 19,
		})
	})
	engine.Run()
}

5、运行

在Terminal中输入go run main.go,然后浏览器搜索http://127.0.0.1:8080/helloworld

2、静态文件
package main

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

func main() {
	engine := gin.Default()
	//加载templates下的模板文件
	engine.LoadHTMLGlob("templates

package main

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

//自定义中间件
func Test() gin.HandlerFunc{
	return func(c *gin.Context) {
		fmt.Println("当前的url是:", c.Request.URL)
	}
}

func main() {
	engine := gin.New()
	//在此使用表示所有请求都经过中间件
	//engine.Use(Test())
	//engine.Use(Test(), gin.Logger())  //同时打印日志

	engine.GET("/get", Test(), func(c *gin.Context) {  //只对某一个请求使用中间件
	//engine.GET("/get", func(c *gin.Context) {
		c.String(http.StatusOK, "get")
	})

	engine.GET("/hello", func(c *gin.Context) {
		c.String(http.StatusOK, "hello")
	})

	//对整个路由组使用中间件
	api := engine.Group("/api", Test())
	{
		api.GET("/get_info", func(c *gin.Context) {
			c.String(http.StatusOK, "api get_info")
		})
		api.GET("/get_user", func(c *gin.Context) {
			c.String(http.StatusOK, "api get_user")
		})
	}
	engine.Run()
}
二、gin框架详解

使用传统go处理请求


package main

import (
	"fmt"
	"net/http"
)

func sayHello(w http.ResponseWriter,r *http.Request){
	//使用绝对路径
	//b, _ := ioutil.ReadFile("E:\Go\workspace\study\go-study\static\txt\hello.txt")
	//获取当前文件路径
    cur, _ := os.Getwd()
	filename := filepath.Join(cur, "static/txt/hello.txt")
	b, _ := ioutil.ReadFile(filename)
	_, _ = fmt.Fprintln(w, string(b))

	//_, _ = fmt.Fprintln(w, "hello Golang")
}

func main() {
	http.HandleFunc("/hello",sayHello)
	err := http.ListenAndServe(":9090", nil)
	if err!=nil {
		fmt.Println("http serve failed, err:%vn", err)
		return
	}
}
Gin框架简单使用

下载并安装

go get -u github.com/gin-gonic/gin

第一个gin示例

package main

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

func test(c *gin.Context)  {
	c.JSON(200, gin.H{
		"message": "Hello golang",
	})
}

func main() {
	engine := gin.Default()    //返回默认的路由引擎

	//指定用户使用GET请求访问/hello时,执行test这个函数
	engine.GET("/hello",test)

	//启动服务
	//engine.Run()   //默认8080端口
	engine.Run(":9090")  //指定访问端口
}

api程序的REST风格

  • Get用来获取资源(查询)
  • POST用来新建资源(创建)
  • PUT用来更新资源(更新)
  • DELETE用来删除资源(删除)
模板与渲染

Go语言内置了文本模板引擎text/template和用于HTML文档的html/template。模板文件中使用{{和}}包裹和标识需要传入的数据,传给模板的数据可以通过**{.}h或者{.FieldName}**来访问它的字段

解析模板文件

package main

import (
	"fmt"
	"html/template"
	"net/http"
	"os"
	"path/filepath"
)

type User struct {
	Name string
	Gender string   //首字母小写访问不到
	Age int
}

func teplatetest(w http.ResponseWriter, r *http.Request){
	//========解析模板========

	//使用绝对路径
	//template, err := template.ParseFiles("E:\Go\workspace\study\go-study\templates\hello.tmpl")
	//获取当前文件路径
	cur, _ := os.Getwd()
	filename := filepath.Join(cur, "templates/hello.tmpl")
	template, err := template.ParseFiles(filename)

	if err != nil{
		fmt.Println("Parse template failed,err:",err)
		return
	}

	//===========渲染模板========
	name := "静静"
	//结构体
	user1 := User{
		Name: "张三",
		Gender: "男",
		Age: 18,
	}
	//map
	map1 := map[string]interface{}{
		"name":   "张三",
		"school": "西华",
	}
	//切片
	hobbies := []string{
		"唱",
		"跳",
		"rap",
	}

	//通过渲染传单个值
	//err = template.Execute(w, name)
	//通过渲染传多个值
	err = template.Execute(w, map[string]interface{}{
		"name" : name,
		"user1" : user1,
		"map1" : map1,
		"hobby" : hobbies,
	})

	if err != nil{
		fmt.Println("render template failed,err:",err)
		return
	}
}

func main() {
	http.HandleFunc("/", teplatetest)
	err := http.ListenAndServe(":9090", nil)
	if err != nil{
		fmt.Println("HTTP serve start failed,err:",err)
		return
	}
}

定义模板文件.tmpl(如templates文件夹下的hello.html)




    
    Select
    


这是查询页面

{{}}

Hello: {{.name}}

user1: {{.user1.Name}},{{.user1.Gender}},{{.user1.Age}}

map1: {{.map1.name}},{{.map1.school}}


{{}} {{ $v1 := 100 }} {{ $name := .map1.name }} {{}}

{{ if $v1 }} {{$v1}} {{else}} v1不存在 {{end}}

{{if $name}} {{$name}} {{else}} age不存在 {{end}}


{{}} {{if lt .user1.Age 22}} 好好上学 {{else}} 好好工作 {{end}}
{{}} {{range $idx, $hobby :=.hobby}}

{{$idx}} - {{$hobby}}

{{else}} 没有爱好 {{end}}
{{}} {{with .user1}}

{{.Name}},{{.Age}},{{.Gender}}

{{end}}
{{}} {{}} {{index .hobby 2}}

输出结果如下所示:

这是查询页面

Hello: 静静

user1: 张三,男,18

map1: 张三,西华


100

张三


好好上学


0 - 唱

1 - 跳

2 - rap


张三,18,男


rap

Gin框架模板渲染

首先定义一个存放模板的templates文件夹,然后在其内部按照业务分别定义一个posts文件夹和一个users文件。里面存放index.tmpl




    
    
    
    posts/index


{{.title}}

模板解析与渲染(包括加载静态文件与给模板添加自定义函数)

package main

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

//静态文件:HTML页面上用到的样式文件:css,js,图片

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

	//加载静态文件
	engine.Static("/xxx","./statics")

	//Gin框架中给模板添加自定义函数
	engine.SetFuncMap(template.FuncMap{
		"safe" : func(str string) template.HTML{
			return template.HTML((str))
		},
	})

	//模板解析
	//engine.LoadHTMLFiles("templates/index.tmpl","templates/users/index.html")
	//加载文件夹下的所有文件(**表目录,*表文件)
	engine.LoadHTMLGlob("templates*")

	engine.GET("/posts/index", func(c *gin.Context) {
		//HTTP请求
		c.HTML(http.StatusOK, "index.tmpl", gin.H{  //模板渲染
			"title" : "posts/index.html",
		})

	})

	engine.GET("/users/index", func(c *gin.Context) {
		//HTTP请求
		c.HTML(http.StatusOK, "index.tmpl", gin.H{  //模板渲染
			"title" : "百度一下",
		})

	})

	//启动serve
	engine.Run(":9090")
}

user/index.html 引用模板函数




    
    
    

{{}}
    

    posts/index



{{}}

{{.title | safe}}

Gin框架路由组
package main

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

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

	//路由
	//逐个设置请求的方式
	engine.GET("/index", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"method" : "GET",
		})

	})
	engine.POST("/index", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"method" : "POST",
		})

	})


	//用Any方法可以匹配所有请求方式
	engine.Any("/test", func(c *gin.Context) {
		switch c.Request.Method {
		case "GET":
			c.JSON(http.StatusOK, gin.H{"method" : "GET"})
		case http.MethodPost:
			c.JSON(http.StatusOK, gin.H{"method" : "POST"})
		//...
		}
	})

	//设置没有路由时访问的页面(以免出现404)
	engine.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusNotFound, gin.H{"msg" : "该页面不存在,请重新输入!"})
	})

	//路由组
	shopGroup := engine.Group("/shop")
	{
		shopGroup.GET("/index", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg" : "/shop/index"})
		})
		shopGroup.GET("/hello", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg" : "/shop/hello"})
		})
	}
	engine.Run(":9090")
}
Gin框架中间件

Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数,这个钩子就叫做中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等


package main

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

//HandlerFunc
func indexHandler(c *gin.Context)  {
	fmt.Println("这是indexHandler")

	//在上下文中获取值
	name, ok := c.Get("name")
	if !ok{
		name = "匿名用户"
	}

	c.JSON(http.StatusOK, gin.H{
		"msg1" : "index",
		"name" : name,
	})
}

//定义一个中间件
func m1(c *gin.Context)  {
	fmt.Println("这是中间件m1")
}

func m2(c *gin.Context)  {
	fmt.Println("m2 in ...")
	//计时
	start := time.Now()

	//先调用后面需要处理的函数,再执行Next后面的代码
	c.Next()      //调用后续的处理函数

	cost := time.Since(start)
	fmt.Printf("调用耗费时间: %vn", cost)

	fmt.Println("m2 out ...")
}

func m3(c *gin.Context)  {
	fmt.Println("m3 in..")
	c.Next()

	//c.Abort()     //阻止调用后续处理函数

	//在上下文中设置值
	c.Set("name", "静静")


	//如果想后续代码不执行,可以使用return返回
	//return
	fmt.Println("m3 out..")
}



func authMiddleware(doCheck bool)gin.HandlerFunc {
	//可以做一些查询数据库、或者一些其他准备工作
	return func(c *gin.Context) {
		if doCheck{
			//存放具体逻辑
		}else{
			c.Next()  //放行
		}

	}
}

func main() {
	

	engine := gin.Default()

	//如果不想使用默认的中间件
	//engine := gin.New()

	//全局注册中间件
	//engine.Use(m1, authMiddleware)

	//engine.GET("/index", func(c *gin.Context) {
	//	c.JSON(http.StatusOK,  gin.H{
	//		"msg" : "index",
	//	})
	//})

	engine.GET("/index", indexHandler)  //与上面代码作用一致

	//为某个路由单独注册中间件
	engine.GET("/index_m1",m1, indexHandler)  //调用中间件
	engine.GET("/index_m2",m2, indexHandler)
	engine.GET("/index_m3",m2,m3, indexHandler)

	//为路由组注册中间件
	//shopGroup := engine.Group("/shop", authMiddleware(true))
	shopGroup := engine.Group("/shop")
	engine.Use(authMiddleware(true))

	{
		shopGroup.GET("/index", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg" : "shop/index..."})
		})
		shopGroup.GET("/hello", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg" : "shop/hello..."})
		})
	}

	engine.Run(":9090")

}

调用Abort后会阻止调用后面的中间件

调用输出结果:http://127.0.0.1:9090/index_m3

m2 in …
m3 in…
这是indexHandler
m3 out…
调用耗费时间: 0s
m2 out …

注意:当在Gin中间件或Handler中启动新的goroutine中,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())

三、URL处理之URL匹配规则

?匹配一个字符

* 匹配0个或多个字符

* *匹配0个或多个目录

2、例子

  • /trip/apiapi/alie 匹配 /trip/api/alie,/trip/dax/api/alie;但不匹配 /trip/a/api
  • *.htmlm 匹配所有以.htmlm结尾的路径
:xxx模式

使用这种模式,创建的URL必须全匹配xxx。例如

package main
 
import (
	"github.com/gin-gonic/gin"
	"net/http"
)
 
func main() {
	r := gin.Default()
 
	// 可以匹配/user/dongshao这种模式, 但是不能匹配/user/或者/user
	r.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(http.StatusOK, "name is %s", name)
	})
 
	r.Run(":8000")
}

*xxx模式

使用这种模式时,创建的URL即可以匹配xxx,也可以不匹配xxx。例如

package main
 
import (
	"github.com/gin-gonic/gin"
	"net/http"
)
 
func main() {
	r := gin.Default()
 
	// 可以匹配/user, /user/, /user/dongshao, /user/dongshao/
	r.GET("/user/*name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(http.StatusOK, "name is %s", name)
	})
 
	r.Run(":8000")
}
:xxx模式和*xxx模式混合在同一个URL
package main
 
import (
	"github.com/gin-gonic/gin"
	"net/http"
)
 
func main() {
	r := gin.Default()
 
	// 只能匹配/user/dongshao/, /user/dongshao/20, /user/dongshao/20/
	// 不能匹配/user/dongshao
	r.GET("/user/:name/*age", func(c *gin.Context) {
		name := c.Param("name")
		age := c.Param("age")
		message := name + " is " + age
		c.String(http.StatusOK, message)
	})
 
	r.Run(":8000")
}

:xxx模式和*xxx模式混合分开使用
package main
 
import (
	"github.com/gin-gonic/gin"
	"net/http"
)
 
func main() {
	r := gin.Default()
 
 
    // /user/dongshao的URL都访问这个
	r.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(http.StatusOK, "name is %s", name)
	})
 
    // /user/dongshao/, /user/dongshao/18, /user/dongshao/18/ 的代码都访问这个
	r.GET("/user/:name/*age", func(c *gin.Context) {
		name := c.Param("name")
		age := c.Param("age")
		message := name + " is " + age
		c.String(http.StatusOK, message)
	})
 
	r.Run(":8000")
}

四、路由冲突
panic: wildcard segment ':id' conflicts with existing children in path '/api/v1/devices/:id/sub-devices'

之前运行时出现conflict的错误,这种是因为路径和通配符冲突了

如:

GET /user/info/:name
GET /user/:id
//这种就会产生冲突,例如输出的路由字符串为/user/info,在/user/:id规则中,info会被解释成:id的值

GET /user/info/:name
POST /user/:id
//这种就不会产生冲突,两个热路由的HTTP Method不同
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/910168.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号