【Gin】初识Gin框架,模板基本语法

1.Gin介绍

Gin 是一个用 Go (Golang) 编写的 HTTP Web 框架。 它具有类似 Martini 的 API,但性能比 Martini 快 40 倍。如果你需要极好的性能,使用 Gin 吧

下载gin:

go get -u github.com/gin-gonic/gin

将gin引入到代码中:

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

2.第一个gin网站

示例

以下展示一个最小的gin web程序

package main

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

// hello 路径的函数
func sayHello(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "hello gin!",
	}) // 返回一个JSON数据
}

func main() {
	r := gin.Default() // 返回默认的路由引擎

	// 指定用户使用GET请求访问/hello时,执行sayHello函数
	r.GET("hello/", sayHello)

	// 启动服务
	r.Run()
}

启动程序之后,浏览器访问:

http://127.0.0.1:8080/hello/

输出信息:

{"message":"hello gin!"}

RESTful API

REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”或“表现层状态转化”。

简单来说,REST的含义就是客户端与Web服务器之间进行交互的时候,使用HTTP协议中的4个请求方法代表不同的动作。

  • GET用来获取资源
  • POST用来新建资源
  • PUT用来更新资源
  • DELETE用来删除资源。

只要API程序遵循了REST风格,那就可以称其为RESTful API。目前在前后端分离的架构中,前后端基本都是通过RESTful API来进行交互。

例如,我们现在要编写一个管理书籍的系统,我们可以查询对一本书进行查询、创建、更新和删除等操作,我们在编写程序的时候就要设计客户端浏览器与我们Web服务端交互的方式和路径。按照经验我们通常会设计成如下模式:

在这里插入图片描述

同样的需求我们按照RESTful API设计如下:

在这里插入图片描述

开发RESTful API的时候我们通常使用Postman来作为客户端的测试工具👜

代码:

package main

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

func main() {
	r := gin.Default() // 返回默认的路由引擎

	// 指定用户使用GET请求访问/hello时,执行函数
	r.GET("hello/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"method": "GET",
		})
	})

	// RESTful风格 API
	r.POST("hello/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"method": "POST",
		})
	})

	r.PUT("hello/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"method": "PUT",
		})
	})

	r.DELETE("hello/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"method": "DELETE",
		})
	})
	// 启动服务
	r.Run()
}

3.模板渲染

html/template包实现了数据驱动的模板,用于生成可防止代码注入的安全的HTML内容。它提供了和text/template包相同的接口,Go语言中输出HTML的场景都应使用html/template这个包。

模板与渲染

在一些前后端不分离的Web架构中,我们通常需要在后端将一些数据渲染到HTML文档中,从而实现动态的网页(网页的布局和样式大致一样,但展示的内容并不一样)效果。

我们这里说的模板可以理解为事先定义好的HTML文档文件,模板渲染的作用机制可以简单理解为文本替换操作–使用相应的数据去替换HTML文档中事先准备好的标记。

很多编程语言的Web框架中都使用各种模板引擎,比如Python语言中Flask框架中使用的jinja2模板引擎。

Go语言的模板引擎

Go语言内置了文本模板引擎text/template和用于HTML文档的html/template。它们的作用机制可以简单归纳如下:

  • 模板文件通常定义为.tmpl.tpl为后缀(也可以使用其他的后缀),必须使用UTF8编码。
  • 模板文件中使用{{和}}包裹和标识需要传入的数据。
  • 传给模板这样的数据就可以通过点号(.)来访问,如果数据是复杂类型的数据,可以通过{{ .FieldName }}来访问它的字段。
  • 除{{和}}包裹的内容外,其他内容均不做修改原样输出。

模板引擎的使用

创建的模板文件:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>hint</title>
</head>
<body>
<h1>Hello {{ . }}</h1>
</body>
</html>

解析模板:

// 解析模板
// 当前路径下的tmpl
t, err := template.ParseFiles("./tem.tmpl")
if err != nil {
	fmt.Println("ParseFiles failed error:%v", err)
	return
}

渲染模板:

// 渲染模板
err = t.Execute(w, "大河之犬")
if err != nil {
	fmt.Println("tmpl Execute failed err=%v", err)
}

后端文件:

package main

import (
	"fmt"
	"html/template"
	"net/http"
)

func sayHello(w http.ResponseWriter, r *http.Request) {
	// 解析模板
	// 当前路径下的tmpl
	t, err := template.ParseFiles("./tem.tmpl")
	if err != nil {
		fmt.Println("ParseFiles failed error:%v", err)
		return
	}
	// 渲染模板
	err = t.Execute(w, "大河之犬")
	if err != nil {
		fmt.Println("tmpl Execute failed err=%v", err)
	}
}
func main() {
	// http服务
	http.HandleFunc("/", sayHello)
	// 使用9000端口
	err := http.ListenAndServe(":9000", nil)
	if err != nil {
		fmt.Println("HTTP server start failed , err %v", err)
		return
	}
}

打开浏览器,可成功渲染:

在这里插入图片描述


4.模板语法

模板渲染结构体

type User struct {
	Name string
	Sex  string
	Age  int
}

func sayHello(w http.ResponseWriter, r *http.Request) {
	// 解析模板
	// 当前路径下的tmpl
	t, err := template.ParseFiles("./tem.tmpl")
	if err != nil {
		fmt.Println("ParseFiles failed error:%v", err)
		return
	}
	// 渲染模板
	u1 := User{
		Name: "dahe", // 别人可以访问时,首字母要大写
		Sex:  "男",
		Age:  18,
	}
	err = t.Execute(w, u1)
	if err != nil {
		fmt.Println("tmpl Execute failed err=%v", err)
	}
}

模板文件:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>hint</title>
</head>
<body>
<h1>Hello {{ .Name }}</h1>
<h1>Sex {{ .Sex }}</h1>
<h1>Age {{ .Age }}</h1>
</body>
</html>

同样的,模板渲染map:

func sayHello(w http.ResponseWriter, r *http.Request) {
	// 解析模板
	// 当前路径下的tmpl
	t, err := template.ParseFiles("./tem.tmpl")
	if err != nil {
		fmt.Println("ParseFiles failed error:%v", err)
		return
	}
	// 渲染模板
	m1 := map[string]interface{}{
		"Name": "dahe", // map无需首字母大写
		"Sex":  "女",
		"Age":  "20",
	}
	err = t.Execute(w, m1)
	if err != nil {
		fmt.Println("tmpl Execute failed err=%v", err)
	}
}

模板传递多个参数

func sayHello(w http.ResponseWriter, r *http.Request) {
	// 解析模板
	// 当前路径下的tmpl
	t, err := template.ParseFiles("./tem.tmpl")
	if err != nil {
		fmt.Println("ParseFiles failed error:%v", err)
		return
	}
	// 渲染模板
	u1 := User{
		Name: "wangwei",
		Sex:  "男",
		Age:  18,
	}
	m1 := map[string]interface{}{
		"Name": "dahe", // map无需首字母大写
		"Sex":  "女",
		"Age":  "20",
	}
	err = t.Execute(w, map[string]interface{}{
		"u1": u1,
		"m1": m1,
	})
	if err != nil {
		fmt.Println("tmpl Execute failed err=%v", err)
	}
}

模板文件:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>hint</title>
</head>
<body>
<h1>Hello {{ .u1.Name }}</h1>
<h1>Sex {{ .u1.Sex }}</h1>
<h1>Age {{ .u1.Age }}</h1>

<h1>Hello {{ .m1.Name }}</h1>
<h1>Sex {{ .m1.Sex }}</h1>
<h1>Age {{ .m1.Age }}</h1>
</body>
</html>

成功渲染:

在这里插入图片描述

注释

{{/* a comment */}}
注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止。

变量

{{ $hello := "ai" }}
{{ $tempSex := .m1.Sex }}
{{ $hello }}
{{ $tempSex }}

移除空格

有时候我们在使用模板语法的时候会不可避免的引入一下空格或者换行符,这样模板最终渲染出来的内容可能就和我们想的不一样,这个时候可以使用{{-语法去除模板内容左侧的所有空白符号, 使用-}}去除模板内容右侧的所有空白符号。

{{- .Name -}}

条件判断

Go模板语法中的条件判断有以下几种:

{{if pipeline}} T1 {{end}}

{{if pipeline}} T1 {{else}} T0 {{end}}

{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}

例如:

{{ if eq .m1.Name "dahe" }}
  <h2>你好啊,dahe</h2>
{{ end }}

比较函数

布尔函数会将任何类型的零值视为假,其余视为真。

下面是定义为函数的二元比较运算的集合:

eq      如果arg1 == arg2则返回真
ne      如果arg1 != arg2则返回真
lt      如果arg1 < arg2则返回真
le      如果arg1 <= arg2则返回真
gt      如果arg1 > arg2则返回真
ge      如果arg1 >= arg2则返回真

为了简化多参数相等检测,eq(只有eq)可以接受2个或更多个参数,它会将第一个参数和其余参数依次比较,返回下式的结果:

{{eq arg1 arg2 arg3}}

range

我们在后端传入一个切片:

hobbyList := []string{
	"C++",
	"Java",
	"Go",
}
m1 := map[string]interface{}{
	"Name":  "dahe", // map无需首字母大写
	"Sex":   "女",
	"Age":   "20",
	"Hobby": hobbyList,
}

模板使用range进行渲染:

{{ range $idx,$hobby := .m1.Hobby }}
    <p>{{$idx}} - {{$hobby}}</p>
{{ end }}

在这里插入图片描述
range-else:

{{ range $idx,$hobby := .m1.Hobby }}
    <p>{{$idx}} - {{$hobby}}</p>
{{else}}
    没有爱好
{{ end }}

index取值:

{{with .m1}}
    <p>{{ index .Hobby 2 }}</p>
    <!--取第三个元素-->
{{end}}

with

简化模板语言变量的使用,例如,局部使用.m1值

{{with .m1}}
    <p>{{.Name}}</p>
    <p>{{.Age}}</p>
{{end}}
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世界尽头与你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值