gin数据解析,绑定和渲染

发布于:2024-06-30 ⋅ 阅读:(14) ⋅ 点赞:(0)

一. 数据解析和绑定

        1.1 Json数据解析和绑定

html文件:

<!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>Document</title>
</head>
<body>
<form action="/loginForm" method="post"enctype="application/x-www-form-urlencoded">
用户名<input type="text" name="username"><br>
密码<input type="password" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>

代码: 

  • gin.Context中的ShouldBind方法将请求中的正文中的数据,自动按照json格式解析到结构体。
package main

import (
	"net/http"

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

// 定义接收数据的结构体
type Login struct {
	//binding:"required"修饰字段,若接收为空值,则报错
	Account string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
	Passwd  string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
}

func main() {
	//创建路由
	r := gin.Default()
	//设置HTML文件所在目录
	r.LoadHTMLGlob("./*.html")
	r.GET("/", func(c *gin.Context) {
		//发送html文件内容
		c.HTML(http.StatusOK, "index.html", nil)
	})

	r.POST("/loginForm", func(c *gin.Context) {
		//声明接收变量
		var json Login
		//将request的body中的数据,自动按照json格式解析到结构体
		if err := c.ShouldBindJson(&json); err != nil {
			//gin.H封装了生成json数据工具
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
			return
		}
		//判断用户名密码是否正确
		if json.Account != "root" || json.Passwd != "admin" {
			c.JSON(http.StatusBadRequest, gin.H{
				"status": ".304",
			})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"status": "ok",
		})
	})
	r.Run()
}

演示:

        1.2. 表单数据解析和绑定

html文件:

<!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>Document</title>
</head>
<body>
<form action="/loginForm" method="post"enctype="application/x-www-form-urlencoded">
用户名<input type="text" name="username"><br>
密码<input type="password" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>

代码:

  • gin.Context的Bind方法默认解析并绑定form格式,根据请求头中的content-type自动推断。
package main

import (
	"net/http"

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

// 定义接收数据的结构体
type Login struct {
	//binding:"required"修饰字段,若接收为空值,则报错
	Account string `form:"username" binding:"required"`
	Passwd  string `form:"password" binding:"required"`
}

func main() {
	//创建路由
	r := gin.Default()
	//设置HTML文件所在目录
	r.LoadHTMLGlob("./*.html")
	r.GET("/", func(c *gin.Context) {
		//发送html文件内容
		c.HTML(http.StatusOK, "index.html", nil)
	})

	r.POST("/loginForm", func(c *gin.Context) {
		//声明接收变量
		var form Login

		//Bind()默认解析并绑定form格式
		//根据请求头中的content-type自动推断
		if err := c.Bind(&form); err != nil {
			//gin.H封装了生成json数据工具
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
			return
		}
		//判断用户名密码是否正确
		if form.Account != "root" || form.Passwd != "admin" {
			c.JSON(http.StatusBadRequest, gin.H{
				"status": ".304",
			})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"status": "ok",
		})
	})
	r.Run()
}

        1.3. URI数据解析和绑定

  • gin.Context中的ShouldBindUri方法将uri中的数据,自动按照uri格式解析到结构体。
package main

import (
	"net/http"

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

// 定义接收数据的结构体
type Login struct {
	//binding:"required"修饰字段,若接收为空值,则报错
	Account string `uri:"user" binding:"required"`
	Passwd  string `uri:"password" binding:"required"`
}

func main() {
	//创建路由
	r := gin.Default()

	r.GET("/:user/:password", func(c *gin.Context) {
		//声明接收变量
		var uri Login

		if err := c.ShouldBindUri(&uri); err != nil {
			//gin.H封装了生成json数据工具
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
			return
		}
		//判断用户名密码是否正确
		if uri.Account != "root" || uri.Passwd != "admin" {
			c.JSON(http.StatusBadRequest, gin.H{
				"status": ".304",
			})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"status": "ok",
		})
	})
	r.Run()
}

演示:

二. gin渲染 

        2.1 各种数据的响应

        多种响应方式:

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/testdata/protoexample"
)

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

	//1. json
	r.GET("/someJson", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "someJson",
			"status":  "ok",
		})
	})

	//2. 结构体响应
	r.GET("/someStruct", func(c *gin.Context) {
		var msg struct {
			Name    string
			Message string
			Number  int
		}

		msg.Name = "root"
		msg.Message = "someStruct"
		msg.Number = 1
		c.JSON(http.StatusOK, msg)
	})

	//3. xml
	r.GET("/someXml", func(c *gin.Context) {
		c.XML(http.StatusOK, gin.H{"message": "abc"})
	})

	//4. YAML响应
	r.GET("/someYaml", func(c *gin.Context) {
		c.YAML(http.StatusOK, gin.H{
			"message": "123",
		})
	})

	//5. protobuf格式
	//构建一个自己的传输格式
	r.GET("/someProtobuf", func(c *gin.Context) {
		resp := []int64{int64(1), int64(2)}
		lable := "lable"

		data := &protoexample.Test{
			Label: &lable,
			Reps:  resp,
		}
		c.ProtoBuf(http.StatusOK, data)
	})

	r.Run()
}

        2.2 HTML模板渲染

  • gin支持加载HTML模板,然后根据模板进行配置并返回相应的数据,本质就是字符串替换。
  • LoadHTMLGlob()方法可以加载模板文件

目录结构:

html文件:

<!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>{{.title}}</title>
</head>
<body>
fgkjdskjdsh{{.ce}}
</body>
</html>

代码:

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("./tem/*") //从运行文件位置开始 需要加载的html文件路径
	r.GET("/someHtml", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})
	r.Run()
}
  • 当html的目录结构如下时

html:

{{ define "user/index.html" }}
<!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>{{.title}}</title>
</head>
    <body>
        fgkjdskjdsh{{.message}}
    </body>
</html>
{{ end }}

 代码:

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("tem/*/*") //从运行文件位置开始 需要加载的html文件路径
	r.GET("/someHtml", func(c *gin.Context) {
		//user/index.html为html中的define
		c.HTML(http.StatusOK, "user/index.html", gin.H{"title": "我是测试", "message": "123"})
	})
	r.Run()
}

演示:

  •  html头尾分离

代码:

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("tem/*/*") //从运行文件位置开始 需要加载的html文件路径
	r.GET("/someHtml", func(c *gin.Context) {
		//user/index.html为html中的define
		c.HTML(http.StatusOK, "user/index.html", gin.H{"title": "我是测试", "message": "123"})
	})
	r.Run()
}

演示:

  •  如果你需要引入静态文件需要定义一个静态文件目录
r.Static("./assets", "./assets")

         2.3 重定向

  • 使用gin.Context的Redirect方法
package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.GET("/index", func(c *gin.Context) {
		//重定向
		c.Redirect(http.StatusMovedPermanently, "redirect")
	})

	r.GET("/redirect", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "hello",
		})
	})
	r.Run()
}

         2.4 同步异步

  • goroutine机制可以方便地实现异步处理
  • 另外,在启动新的goroutine时,不应该使用原始上下文context,必须使用它的只读副本
package main

import (
	"log"
	"time"

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

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

	r.GET("/long_async", func(c *gin.Context) {
		//上下文副本
		c_tmp := c.Copy()
		//异步处理
		go func() {
			time.Sleep(2 * time.Second)
			log.Println("异步执行 " + c_tmp.Request.URL.Path)
		}()
	})

	r.GET("/long_sync", func(c *gin.Context) {
		time.Sleep(3 * time.Second)
		log.Println("同步执行 " + c.Request.URL.Path)
	})

	r.Run()
}

        异步是启动一个协程去执行请求。