go web 开发 学习笔记之gin框架学习

gin入门

index.html

<html>
	<head>
		<title>
			index.html
		title>
	head>
	<body>
		{{.title}}
	body>
html>

main.go

package main

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

func main(){
	//创建默认路由引擎
	r := gin.Default()
	//设置路由和渲染数据
	r.Get("/index", func (c *gin.Context){
		c.JSON(http.StatusOK,gin.H{
			"title":"lijiahui",
		})
	})
	//启动服务
	r.Run(":8080")
}

启动服务后访问 localhost:8080/index结果如下
在这里插入图片描述

1. gin模板使用

(1)demo

index.html

<html>
	<head>
		<title>
			index.html
		title>
	head>
	<body>
		{{.title}}
	body>
html>

main.go

package main

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

func main(){
	//定义默认路由引擎
	r := gin.Default()
	//模板解析
	r.LoadHTMLFiles("index.html")
	//定义路由 渲染模板
	r.GET("/index",func(c *gin.Context){
		c.HTML(http.StatusOK,"index.html",gin.H{
			"title":"lijiahui",
		})
	})
	//启动服务
	r.Run(":8080")
}

访问结果为
go web 开发 学习笔记之gin框架学习_第1张图片

(2)gin框架默认将传入模板的数据转义,如果我们想要它不转义,同样需要自定义方法

<html>
	<head>
		<title>
			不转义
		title>
	head>
	<body>
		{{safe .title}}
	body>
html>

main.go

package main

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

func main(){

	r := gin.Default()
	//自定义模板方法
	r.SetFuncMap(template.FuncMap{
		"safe" : func(str string)template.HTML{
			return template.HTML(str)
		},
	})
	//解析模板
	r.LoadHTMLFiles("index.html")
	//定义路由 
	r.GET("/index",func(c *gin.Context){
		//渲染模板
		c.HTML(http.StatusOK,"index.html",gin.H{
			"title":"百度"
		}),
	})
	//启动服务
	r.Run(":8080")
}

访问结果是:
在这里插入图片描述

(3) 静态文件处理

静态文件是一般指一些样式文件(.css,js)或者图片等。gin处理静态文件如下:

index.html

<html>
	<head>
		<title>
			静态文件
		title>
		<link rel="stylesheet" href="/static/css/index.css"/>
	head>
	<body>
	
	body>
html>

index.css

body{
	background-color:burlywood;
}

main.go

package main

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

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

	//定义静态文件访问路由。前一个参数代指静态文件的访问路径,
	//后一个参数指该路径对应项目中的文件目录,这里是相对于main.go文件的相对路径
	r.Static("/static","./static")
	r.LoadHTMLFiles("index.html")
	r.GET("/index",func(c *gin.Context){
		c.HTML(http.StatusOK,"index.html",nil)
	})
	r.Run(":8080")
}

项目结构如下:
go web 开发 学习笔记之gin框架学习_第2张图片
访问的结果如下:
go web 开发 学习笔记之gin框架学习_第3张图片
背景色被换成了深黄色。

(4)返回json和返回结构体

package main

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

func main(){
	r := gin.Default()
	r.GET("index",func(c *gin.Context){
		c.JSON(http.StatusOK,gin.H{
			"name":"lijiahui",
			"age":20,
			"address":"China",
		})
	})
	r.Run(":8080")
}

访问结果为
go web 开发 学习笔记之gin框架学习_第4张图片
如果需要返回结构体,则可以如下处理

func main(){

	r := gin.Default()
	type MSG struct{
		name string
		Age int64
		Address string
	}
	data = MSG{
		name:"lijiahui",
		Age :20,
		Address : "China",
	}
	r.GET("/index2",func(c *gin.Context){
		c.JSON(http.StatusOK,data)
	})
	r.Run(":8080")
}

访问结果是
go web 开发 学习笔记之gin框架学习_第5张图片
可以看到向前端响应的json中,name字段的值不见了,这是因为gin框架中对数据的序列化默认还是采用原生的序列化方法,对于结构体中小写的字段会被隐藏,此时要让前端能接收到小写字段的数据,可以使用tag
如:

func main(){

	r := gin.Default()
	type MSG struct{
		Name string `json:"name"`
		Age int64 `json:age`
		Address string `json:address`
	}
	data = MSG{
		name:"lijiahui",
		Age :20,
		Address : "China",
	}
	r.GET("/index2",func(c *gin.Context){
		c.JSON(http.StatusOK,data)
	})
	r.Run(":8080")
}

访问结果为:
go web 开发 学习笔记之gin框架学习_第6张图片

2. gin获取请求参数

(1)gin获取querystring上的参数,即get请求的参数

package main

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

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

	r.GET("/index",func(c *gin.Context){
		//方式一
		name := c.Query("name")
		//方式二
		name := c.DefaultQuery("name","BBB")
		//方式三
		name,ok := c.GetQuery("name")
		c.JSON(http.StatusOK,name)
	})
	
	r.Run(":8080")
}

方式一:
go web 开发 学习笔记之gin框架学习_第7张图片
方式二:
go web 开发 学习笔记之gin框架学习_第8张图片
方式三:
go web 开发 学习笔记之gin框架学习_第9张图片

(2)gin获取post请求的参数,即表单提交参数

login.html

<html>
	<head>
		<title>
			登录
		title>
	head>
	<body>
		<form action="/login" method="post">
			用户名:<input name="username" placeholder="用户名" />
			密码:<input name="password" placeholder="密码" />
			<input type="submit" value="提交" />
		form>
	body>
html>
package main

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

func main(){
	r := gin.Default()
	r.LoadHTMLFiles("login.html")
	r.GET("/login",func(c *gin.Context){
		c.HTML(http.StatusOK,"login.html",nil)
		}
	)

	r.POST("/login",func(c *gin.Context){
		//方式一
		//username := c.PostForm("username")
		//password := c.PostForm("password")
		//方式二
		username := c.DefaultPostForm("username","小刘")
		password := c.DefaultPostForm("xx","xxxxx")
		c.JSON(http.StatusOK,gin.H{
			"username":username,
			"password":password,
		})
	})
	r.Run(":8080")
}

方式一的访问结果
go web 开发 学习笔记之gin框架学习_第10张图片
方式二的访问结果:
go web 开发 学习笔记之gin框架学习_第11张图片
方式三:
go web 开发 学习笔记之gin框架学习_第12张图片

(3)获取path路径的参数

当请求采用 http://localhost:8080/user/zhangsan/18这种方式来传递参数,该怎么获取路径上的参数呢

package main

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

func main(){
	r:= gin.Default()
	
	r.GET("/login/:username/:age",func(c *gin.Context){
		username :=  c.Param("username")
		age := c.Param("age")
		c.JSON(http.StatusOK,gin.H{
			"username":username,
			"age":age,
		})
	})
	r.Run(":8080")
}

访问结果是
go web 开发 学习笔记之gin框架学习_第13张图片

(4)参数绑定

package main

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

type User struct{
	Username string `form:"username" json:"username"`
	Password string `form:"password" json:"password"`
}

func main(){
	r := gin.Default()
	//方式一 :query string方式参数绑定
	r.GET("/login2",func(c *gin.Context){
		var u User
		r.ShouldBind(&u)
		c.JSON(http.StatusOK,gin.H{
			"username" :username,
			"password" :password,
		})
	})
	//方式二 : form表单提交方式
	r.LoadHTMLFiles("login.html")
	r.GET("/login",func(c *gin.Context){
		c.HTML(http.StatusOK,"login.html",nil)
	})
	r.POST("/login",func(c *gin.Context){
		var u User
		c.ShouldBind(&u)
		c.JSON(http.StatusOK,gin.H{
			"username":username,
			"password":password,
		})
	})
	//方式三 : json提交方式
	r.POST("/login",func(c *gin.Context){
		var u User
		c.ShouldBind(&u)
		c.JSON(http.StatusOK,gin.H{
			"username":username,
			"password":password,
		})
	})
	r.Run(":8080")
}

login.html

<html>
	<head>
		<title>
			表单提交方式
		title>
	head>
	<body>
		<form action="/login" method="post">
		<div>
			<input name="username" type="text" value="用户名" />
		div>
		<div>
			<input name="password" type="password" value="密码" />
		div>
		<div>
			<input type="submit" value="提交"/>
		div>
		form>
	body>
html>

方式一的结果为
go web 开发 学习笔记之gin框架学习_第14张图片
方式二的结果为
go web 开发 学习笔记之gin框架学习_第15张图片
方式三的访问结果为:
go web 开发 学习笔记之gin框架学习_第16张图片

(5)文件上传

  1. 单个文件上传

upload.html

<html>
	<head>
		<title>
			单个文件上传
		title>
	head>
	<body>
		<form action="/upload" method="post" enctype="multipart/form-data">
			上传文件<input type="file" name="file" value="选择文件"/>
			<input type="submit" value="提交"/> 
		form>
	body>
html>

main.go

package main

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

func main(){
	router := gin.Default()
	router.LoadHTMLFiles("upload.html")
	router.GET("/upload",func(c *gin.Context){
		c.HTML(http.StatusOK,"upload.html",nil)
	})
	router.POST("/upload",func(c *gin.Context){
		file,err := c.FormFile("file")
		if err != nil{
			c.JSON(http.StatusBadRequest,gin.H{
				"msg":"读取文件失败!",
			})
		}else{
			dst := fmt.Sprintf("./%s",file.Filename)
			c.SaveUploadFile(file,dst)
			c.JSON(http.StatusOK,gin.H{
				"msg":"读取文件成功!"
			})
		}
	})
	
	router.Run(":8080")
}

选择文件上传 结果为:
go web 开发 学习笔记之gin框架学习_第17张图片
go web 开发 学习笔记之gin框架学习_第18张图片
2. 多个文件上传

<html>
	<head>
		<title>
			多个文件上传
		title>
	head>
	<body>
		<form action="/upload" method="post" enctype="multipart/form-data">
			<input  type="file" name="files" multipart/>
			<input  type="submit" value="提交"/>
		form>
	body>
html>

main.go

package main

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

func main(){
	router:= gin.Default()
	router.LoadHTMLFiles("upload.html")
	router.GET("/upload",func(c *gin.Context){
		c.HTML(http.StatusOK,"upload.html",nil)
	})
	router.POST("/upload",func(c *gin.Context){
		form,_ := c.MultipartForm()
		files := form.File["files"]
		for _,file := range files{
			dst := fmt.Sprintf("./%s",file.Filename)
			c.SaveUploadFile(file,dst)
		}
		c.JSON(http.StatusOK,gin.H{
			"msg":"上传文件成功!"
		})
	})
	router.Run(":8080")
}

上传文件结果:
go web 开发 学习笔记之gin框架学习_第19张图片
go web 开发 学习笔记之gin框架学习_第20张图片

(6)gin请求重定向

(7)路由和路由组

对不同的请求,gin框架有不同的方法来处理, 如 GET ,POST,PUT,DELETE
路由组的概念就是在路由的路径的前半部分有很大相似的时候,单独将相同的部分设置为一个路由组,提高代码的可读性和整洁性 如下:

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

func main(){
	router:=gin.Default()
	router.GET("/index/get1",func(c *gin.Context){
		c.JSON(http.StatusOK,gin.H{
			"msg":"/index/get1OK",
		})
	})
	router.GET("/index/get2",func(c *gin.Context){
		c.JSON(http.StatusOK,gin.H{
			"msg":"/index/get2OK",
		})
	})
	//上面的代码路由的前缀 相似,都有 "/index/",此时就可以设置一个路由组,增加可读性和整洁性
	indexGroup := router.Group("/index")
	indexGroup.GET("/get3",func(c *gin.Context){
		c.JSON(http.StatusOK,gin.H{
			"msg":"/group/index/get3OK",
		})
	})
	indexGroup.GET("/get4",func(c *gin.Context){
		c.JSON(http.StatusOK,gin.H{
			"msg":"/group/index/get4OK",
		})
	})
	router.Run(":8080")
}

(8)中间件

gin框架允许开发者在处理请求的过程中加入自己的钩子函数,所谓钩子函数就是,在正常的处理逻辑中间加入一个函数能做其他的跟业务无关的处理(也可以相关把),像个钩子一样挂在正常的逻辑线上。通常钩子函数用于 处理 日志、计时、登录认证、权限控制等。这样的钩子函数就是中间件

  1. 定义一个钩子函数(中间件)
    main.go
package main
import (
	"time"
	"fmt"
	"github.com/gin-gonic/gin"
)
//midWare 中间件函数
func midWare()func(c *gin.Context){
	return func(c *gin.Context){
		fmt.Println("midware in...")
		start := time.Now()
		//c.Next()函数表示让下一个钩子函数执行,
		//且下一个钩子函数执行完成之前不会执行c.Next()后面的代码
		c.Next()
		cost:= time.Since(start)
		fmt.Println("cost :",cost)
		fmt.Println("midware out...")
	}
}

func main(){
	......
}
  1. 为单个路由注册一个中间件
package main

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

//midWare 中间件函数
func midWare()func(c *gin.Context){
	return func(c *gin.Context){
		fmt.Println("midware in...")
		start := time.Now()
		//c.Next()函数表示让下一个钩子函数执行,
		//且下一个钩子函数执行完成之前不会执行c.Next()后面的代码
		c.Next()
		cost:= time.Since(start)
		fmt.Println("cost :",cost)
		fmt.Println("midware out...")
	}
}

func main(){
	router := gin.Default()
	router.GET("/index",midWare(),func(c *gin.Context){
		c.JSON(http.StatusOK,gin.H{
			"msg":" test midWare",
		})
	})
	router.Run(":8081")
}

访问的执行结果是:
go web 开发 学习笔记之gin框架学习_第21张图片
3. 为全局路由注册中间件

package main

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

//midWare 中间件函数
func midWare()func(c *gin.Context){
	return func(c *gin.Context){
		fmt.Println("midware in...")
		start := time.Now()
		//c.Next()函数表示让下一个钩子函数执行,
		//且下一个钩子函数执行完成之前不会执行c.Next()后面的代码
		c.Next()
		cost:= time.Since(start)
		fmt.Println("cost :",cost)
		fmt.Println("midware out...")
	}
}

func main(){
	router := gin.Default()
	//在这里设置全局路由中间件
	router.Use(midWare())
	router.GET("/index",func(c *gin.Context){
		c.JSON(http.StatusOK,gin.H{
			"msg":" test midWare",
		})
	})
	router.Run(":8081")
}
  1. 为路由组注册中间件
package main

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

func main(){
	router := gin.Default()
	//方式一
	indexGroup := router.Group("/index",midWare())
	{
		indexGroup.GET("/a",func(c *gin.Context){
			c.JSON(http.StatusOK,gin.H{
				"msg":"test /index/a",
			})
		})
		indexGroup.GET("/b",func(c *gin.Context){
			c.JSON(http.StatusOK,gin.H{
				"msg":"test /index/b",
			})
		})
	}
	
	//方式二
	index2Group := router.Group("/index2")
	//使用User()方法
	index2Group.Use(midWare())
	{
		index2Group.GET("/c",func(c *gin.Context){
			c.JSON(http.StatusOK,gin.H{
				"msg":"test /index2/c",
			})
		})
		index2Group.GET("/d",func(c *gin.Context){
			c.JSON(http.StatusOK,gin.H{
				"msg":"test /index2/d",
			})
		})
	}
	router.Run(":8081")
}

注意事项:

  1. gin框架中默认添加了两个中间件 Logger(), Recovery().

Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。

可以使用gin.New()创建一个不含上述两个中间件的路由引擎
2. *当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c gin.Context),必须使用其只读副本(c.Copy())。

你可能感兴趣的:(go web 开发 学习笔记之gin框架学习)