Gin中文文档
本文参考
https://www.yoytang.com/go-gin-doc.html
Gin简单示例
GoLand为例:
-
新建项目,选择Go Module(vgo) 。 proxy设置为 https://goproxy.cn
-
生成的 go.mod
存放依赖信息
-
go get -u github.com/gin-gonic/gin
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/book", func(context *gin.Context) {
context.JSON(200, gin.H{
"message": "GET book!",
})
})
r.POST("/book", func(context *gin.Context) {
context.JSON(200, gin.H{
"message": "POST book!",
})
})
_ = r.Run(":9090")
}
http/template
- 模板文件通常定义为.tmpl和.tpl为后缀(也可以使用其他的后缀),必须使用UTF8编码。
- 模板文件中使用{{和}}包裹和标识需要传入的数据。
- 传给模板这样的数据就可以通过点号(.)来访问,如果数据是复杂类型的数据,可以通过{ { .FieldName }}来访问它的字段。
- 除{{和}}包裹的内容外,其他内容均不做修改原样输出。
import (
"fmt"
"github.com/gin-gonic/gin"
"html/template"
)
func main() {
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
temp, err := template.ParseFiles("./demo.templ")
if err != nil {
fmt.Println("template parser error:", err)
return
}
u2 := map[string]interface{}{
"Name": "小王子",
"Gender": "男",
"Age": 18,
}
err = temp.Execute(writer, u2)
if err == nil {
fmt.Println("render template failed,", err)
}
})
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println("HTTP server failed,err:", err)
return
}
}
传值
使用struct
模板文件:
<p>姓名 {{.Name}}</p>
<p>年龄 {{.Age}}</p>
<p>性别 {{.gender}}</p> (性别不会显示)
type User struct {
Name string
gender string
Age int
}
u1 := User{Name: "小王子", gender: "男", Age: 18}
err = temp.Execute(context.Writer, u1)
if err == nil {
fmt.Println("render template failed,", err)
}
使用map
map通过key访问,key的大小写均可以。
u2 := map[string]interface{}{
"Name": "小王子",
"Gender": "男",
"Age": 18,
}
err = temp.Execute(context.Writer, u2)
if err == nil {
fmt.Println("render template failed,", err)
}
常用命令
1). 注释
2). pipeline
支持管道指令,支持使用管道符号|
链接多个命令。
3). 声明变量
4). 移除空格
5). 条件判断
{{if pipeline}} T1 {{end}}
{{if pipeline}} T1 {{else}} T0 {{end}}
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
等等不一一列举。 参考地址
Gin中使用template
func main() {
r := gin.Default()
r.LoadHTMLFiles("templates/index.tmpl")
r.GET("/index", func(context *gin.Context) {
context.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "tyard.cc",
})
})
_ = r.Run(":9091")
}
define
转载自:原文地址
使用define
定义模板名字,示例如下:
文件目录: templates/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}}
文件目录: templates/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}}
渲染的代码:
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/**/*")
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(":9091")
}
模板函数(管道)
例如:防止html函数转义,定义一个safe函数。
代码如下:
r.SetFuncMap(template.FuncMap{
"safe": func(str string) template.HTML {
return template.HTML(str)
},
})
r.LoadHTMLGlob("templates/**/*")
r.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "posts/index",
"content": "<a href='http://baidu.com'>baidu.com</a>",
})
})
_ = r.Run(":9091")
html模板代码中,通过管道使用{{.content | safe}}
即可。
静态资源
r := gin.Default()
r.Static("/static", "./static/")
JSON
func main() {
r := gin.Default()
r.GET("/map", func(c *gin.Context) {
mp := map[string]interface{}{
"name": "xiaoming",
}
c.JSON(http.StatusOK, mp)
})
r.GET("json", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "hello world",
})
})
r.GET("/json2", func(c *gin.Context) {
var msg struct {
Name string
Message string
Age int
}
msg.Name = "小明"
msg.Message = "hello world"
msg.Age = 18
c.JSON(http.StatusOK, msg)
})
_ = r.Run(":9091")
}
querystring参数
r.GET("/query", func(c *gin.Context) {
name := c.Query("name")
value := c.QueryArray("value")
df := c.DefaultQuery("score", "100")
gf, success := c.GetQuery("GetQuery")
if !success {
gf = "sv"
}
c.JSON(http.StatusOK, gin.H{
"name": name,
"value": value,
"df": df,
"gf": gf,
})
})
r.POST("/login", func(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
c.JSON(http.StatusOK, gin.H{
"username": username,
"password": password,
})
})
path参数(URI参数)
注意url匹配不要冲突。
r.GET("/username/:name", func(c *gin.Context) {
name := c.Param("name")
c.JSON(http.StatusOK, gin.H{
"name": name,
})
})
参数绑定到struct
注意:
- struct绑定的字段需要大写
- ShouldBind传递地址
- 注解
type UserInfo struct {
Username string `form:"username"`
Password string `form:"password"`
}
r.POST("/loginRd", func(c *gin.Context) {
var u UserInfo
if err := c.ShouldBind(&u); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"err": err.Error(),
})
} else {
c.JSON(http.StatusOK, &u)
}
})
通过struct tag 可以自动解析QueryString、form表单、JSON、XML等参数到结构体中。 下面是解析JSON、form表单和QueryString参数的示例:
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func main() {
router := gin.Default()
router.POST("/loginJSON", func(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err == nil {
fmt.Printf("login info:%#v\n", login)
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
router.POST("/loginForm", func(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
router.GET("/loginForm", func(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
router.Run(":8080")
}
ShouldBind
会按照下面的顺序解析请求中的数据完成绑定:
- 如果是 GET 请求,只使用 Form 绑定引擎(query)。
- 如果是 POST 请求,首先检查 content-type 是否为 JSON 或 XML,然后再使用 Form(form-data)
其他的, 还可以进行参数校验功能,详情见官方文档。
文件上传
r.POST("upload", func(c *gin.Context) {
if file, err := c.FormFile("f1"); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(),
})
return
} else {
dst := fmt.Sprintf("/tmp/fileUpload/%s", file.Filename)
if e := c.SaveUploadedFile(file, dst); e != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": e.Error(),
})
} else {
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("'%s' uploaded!", file.Filename),
})
}
}
})
多文件上传
r.POST("mutiUpload", func(c *gin.Context) {
if form, err := c.MultipartForm(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(),
})
} else {
files := form.File["file"]
for index, file := range files {
log.Println(file.Filename)
dst := fmt.Sprintf("/tmp/fileUpload/%s_%d", file.Filename, index)
if saveErr := c.SaveUploadedFile(file, dst); saveErr != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": saveErr.Error(),
})
return
}
}
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("%d files uploaded!", len(files)),
})
}
})
重定向
url重定向
r.GET("urlRedirect", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/")
})
路由重定向
r.GET("/redirectRouter", func(c *gin.Context) {
c.Request.URL.Path = "/test2"
r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"hello": "world"})
})
路由
Gin框架中的路由使用的是httprouter这个库。其基本原理就是构造一个路由地址的前缀树。
普通路由
r.GET("/test2", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"hello": "world"})
})
此外,还有一个可以匹配所有请求方法的Any方法如下:
r.Any("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"hello": "test"})
})
路由组,有相同前缀的可以统一用路由组处理,支持多级嵌套:
userGroup := r.Group("/user")
{
userGroup.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"user": "index"})
})
userGroup.GET("/login", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"user": "login"})
})
userGroup.POST("/login", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"user": "login"})
})
}
shopGroup := r.Group("/shop")
{
shopGroup.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"shop": "index"})
})
shopGroup.GET("/cart", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"shop": "cart"})
})
shopGroup.POST("/checkout", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"shop": "checkout"})
})
xx := shopGroup.Group("xx")
xx.GET("/oo", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"shop/xx": "oo"})
})
}