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结果如下
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")
}
<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")
}
静态文件是一般指一些样式文件(.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")
}
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")
}
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")
}
访问结果是
可以看到向前端响应的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")
}
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")
}
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")
}
当请求采用 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")
}
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>
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")
}
<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")
}
对不同的请求,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")
}
gin框架允许开发者在处理请求的过程中加入自己的钩子函数,所谓钩子函数就是,在正常的处理逻辑中间加入一个函数能做其他的跟业务无关的处理(也可以相关把),像个钩子一样挂在正常的逻辑线上。通常钩子函数用于 处理 日志、计时、登录认证、权限控制等。这样的钩子函数就是中间件
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(){
......
}
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")
}
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")
}
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")
}
注意事项:
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。
可以使用gin.New()创建一个不含上述两个中间件的路由引擎
2. *当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c gin.Context),必须使用其只读副本(c.Copy())。