Gin框架
Gin的模板
HTML渲染
案例一:
main.go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.LoadHTMLFiles("./index.tmpl")
r.GET("/index", func(c *gin.Context) {
//http请求
c.HTML(http.StatusOK, "index.tmpl", gin.H{ //模板渲染
"title": "百度",
})
})
r.Run(":9090")
}
index.tmpl
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
{{.title}}
</body>
</html>
案例二:
我们首先定义一个存放模板文件的templates
文件夹,然后在其内部按照业务分别定义一个posts
文件夹和一个users
文件夹。 posts/index.tmpl
文件的内容如下:
{{define "posts/index.tmpl"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>posts/index</title>
</head>
<body>
{{.title}}
</body>
</html>
{{end}}
users/index.tmpl
文件的内容如下:
{{define "users/index.tmpl"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>users/index</title>
</head>
<body>
{{.title}}
</body>
</html>
{{end}}
Gin框架中使用LoadHTMLGlob()
或者LoadHTMLFiles()
方法进行HTML模板渲染。
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/**/*")
//r.LoadHTMLFiles("templates/posts/index.tmpl", "templates/users/index.tmpl")
r.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "posts/index",
})
})
r.GET("users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "users/index",
})
})
r.Run(":9090")
}
自定义模板函数
和普通的template一样
r.SetFuncMap(template.FuncMap{
"safe": func(str string) template.HTML {
return template.HTML(str)
},
})
{{.title | safe}}
静态文件处理
当我们渲染的HTML文件中引用了静态文件时,我们只需要按照以下方式在渲染页面前调用gin.Static
方法即可。
func main() {
r := gin.Default()
r.Static("/xxx", "./static")
r.LoadHTMLGlob("templates/**/*")
// ...
r.Run(":8080")
}
<link rel="stylesheet" href="/xxx/index.css">
Gin返回JSON
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/json", func(c *gin.Context) {
//方法1 :使用map
//data := map[string]interface{}{
// "name": "小王子",
// "message": "hello",
//}
data := gin.H{
"name": "小王子",
"message": "hello",
"age": 18,
}
c.JSON(http.StatusOK, data)
})
//方法二:结构体
type msg struct {
Name string `json:"name"`
Age int `json:"age"`
Message string `json:"message"`
}
r.GET("/another_json", func(c *gin.Context) {
data := msg{
"小王子",
18,
"hello",
}
c.JSON(http.StatusOK, data)
})
r.Run(":9090")
}
Gin获取querystring
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
//GET请求 URL ?后面是querystring参数
//key=value格式,多个key-value用 & 连接
//eq : /web/query=jt&age=20
r.GET("/web", func(c *gin.Context) {
//获取浏览器那个发请求携带的query string 参数
name := c.Query("query") //通过Query获取请求中携带的querystring参数
age := c.Query("age")
//name := c.DefaultQuery("query", "somebody")//取不到就用指定的默认类型
//name, ok := c.GetQuery("query") //取不到第二个参数返回false
//if !ok {
// //取不到
// name = "somebody"
//}
c.JSON(http.StatusOK, gin.H{
"name": name,
"age": age,
})
})
r.Run(":9090")
}
Gin获取form参数
login
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/login" method="post">
<div>
<label for="username">username:</label>
<input type="text" name="username" id="username">
</div>
<div>
<label for="password">password:</label>
<input type="password" name="password" id="password">
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
index
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1>hello {{.name}}</h1>
<h1>hello {{.password}}</h1>
</body>
</html>
main.go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
//获取form表单的参数
func main() {
r := gin.Default()
r.LoadHTMLFiles("./login.html", "./index.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", "somebody")
//password := c.DefaultPostForm("xxx", "PWD")
username, ok := c.GetPostForm("username")
if !ok {
username = "122"
}
password, _ := c.GetPostForm("password")
c.HTML(http.StatusOK, "index.html", gin.H{
"name": username,
"password": password,
})
})
r.Run(":9090")
}
Gin获取path参数
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
//获取请求的path参数,返回的都是字符串类型
func main() {
r := gin.Default()
r.GET("/user/:name/:age", func(c *gin.Context) {
//获取路径参数
name := c.Param("name")
age := c.Param("age") //string类型
c.JSON(http.StatusOK, gin.H{
"name": name,
"age": age,
})
})
r.GET("/blog/:year/:month", func(c *gin.Context) {
year := c.Param("year")
month := c.Param("month")
c.JSON(http.StatusOK, gin.H{
"year": year,
"month": month,
})
})
r.Run(":9090")
}
Gin参数绑定
为了能够更方便的获取请求相关参数,提高开发效率,我们可以基于请求的Content-Type
识别请求数据类型并利用反射机制自动提取请求中QueryString
、form表单
、JSON
、XML
等参数到结构体中。 下面的示例代码演示了.ShouldBind()
强大的功能,它能够基于请求自动提取JSON
、form表单
和QueryString
类型的数据,并把值绑定到指定的结构体对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<form action="/form" method="post">
用户名:
<input type="text" name="username">
密码:
<input type="password" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
type UserInfo struct {
Username string `form:"username" json:"username"`
Password string `form:"password" json:"password"`
}
func main() {
r := gin.Default()
r.LoadHTMLFiles("./index.html")
r.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})
r.POST("/form", func(c *gin.Context) {
//username := c.Query("username")
//password := c.Query("password")
//u := UserInfo{
// username: username,
// password: password,
//}
var u UserInfo //声明结构体
err := c.ShouldBind(&u)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
} else {
fmt.Printf("%#v\n", u)
c.JSON(http.StatusOK, gin.H{
"static": "ok",
"username": u.Username,
})
}
})
r.POST("/json", func(c *gin.Context) {
//username := c.Query("username")
//password := c.Query("password")
//u := UserInfo{
// username: username,
// password: password,
//}
var u UserInfo //声明结构体
err := c.ShouldBind(&u)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
} else {
fmt.Printf("%#v\n", u)
c.JSON(http.StatusOK, gin.H{
"static": "ok",
"username": u.Username,
})
}
})
r.Run(":9090")
}
ShouldBind
会按照下面的顺序解析请求中的数据完成绑定:
- 如果是
GET
请求,只使用Form
绑定引擎(query
)。 - 如果是
POST
请求,首先检查content-type
是否为JSON
或XML
,然后再使用Form
(form-data
)。