gin框架一套解决
[toc]
介绍
- Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点
 - 对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的
net/http足够简单,性能也非常不错 - 借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范
 
要求
- Go 1.13 及以上版本
 
安装
要安装 Gin 软件包,需要先安装 Go 并设置 Go 工作区。
1.下载并安装 gin:
go get -u github.com/gin-gonic/gin
💡 补充get参数:
附加参数 备 注 -v 显示操作流程的日志及信息,方便检查错误 -u 下载丢失的包,但不会更新已经存在的包 -d 只下载,不安装 -insecure 允许使用不安全的 HTTP 方式进行下载操作 
2.将 gin 引入到代码中:
import "github.com/gin-gonic/gin"
3.(可选)如果使用诸如 http.StatusOK 之类的常量,则需要引入 net/http 包:
import "net/http"
4.创建你的项目文件夹并 cd 进去
如果是用的
mod包,那么并不需要
$ mkdir -p $GOPATH/src/github.com/myusername/project && cd "$_"
5.拷贝一个初始模板到你的项目里
$ curl https://raw.githubusercontent.com/gin-gonic/examples/master/basic/main.go > main.go
网络不行可以直接访问 这里复制到
main.go
6.运行你的项目
$ go run main.go
最后访问即可:
开始
不确定如何编写和执行 Go 代码? 点击这里.
首先,创建一个名为 example.go 的文件
$ touch example.go
接下来, 将如下的代码写入 example.go 中:
package main
import "github.com/gin-gonic/gin"
func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
然后, 执行 go run example.go 命令来运行代码:
# 运行 example.go 并且在浏览器中访问 HOST_IP:8080/ping
$ go run example.go
🚀 编译结果如下:

hello word
package main
import (
    "net/http"
    "github.com/gin-gonic/gin"
)
func main() {
    // 1.创建路由
   r := gin.Default()
   // 2.绑定路由规则,执行的函数
   // gin.Context,封装了request和response
   r.GET("/", func(c *gin.Context) {
      c.String(http.StatusOK, "hello World!")
   })
   // 3.监听端口,默认在8080
   // Run("里面不指定端口号默认为8080") 
   r.Run(":8000")
}

其他的请求和json
💡简单的一个案例如下:
// gin
package main
import (
	"net/http"
	"github.com/gin-gonic/gin"
)
func main() {
	//创建gin实例
	r := gin.Default()
	//设置路由:请求方式,路径,处理函数
	r.GET("/ping", func(c *gin.Context) {
		c.String(200, "这是一个Get ping请求")
		c.JSON(http.StatusOK, gin.H{
			"message": "pong",
		})
	})
	//Post请求: http://localhost:8080/login 表示向服务器发送登录请求
	r.POST("/login", func(c *gin.Context) {
		c.String(200, "登录成功,这是一个Post请求")
		//获取参数
		username := c.PostForm("username")
		password := c.PostForm("password")
		//返回json数据
		c.JSON(http.StatusOK, gin.H{
			"username": username,
			"password": password,
		})
	})
	//Put请求: http://localhost:8080/put 表示向服务器发送修改请求
	r.PUT("/put", func(c *gin.Context) {
		c.String(200, "修改成功,这是一个Put请求")
		//获取参数
		username := c.PostForm("username") //当存在POST urlenencoded表单或multipart表单时,PostForm返回指定的键,否则返回空字符串'("")'
		password := c.PostForm("password")
		//返回json数据 : 传入的数据:状态码和空接口类型数据
		c.JSON(http.StatusOK, gin.H{ //gin.H是map[string]interface{}的简写,http.StatusOK是200
			"username": username,
			"password": password,
		})
	})
	//Delete请求: http://localhost:8080/delete 表示向服务器发送删除请求
	r.DELETE("/delete", func(c *gin.Context) {
		c.String(200, "删除成功,这是一个Delete请求")
		//获取参数
		username := c.PostForm("username")
		password := c.PostForm("password")
		//返回json数据
		c.JSON(http.StatusOK, gin.H{
			"username": username,
			"password": password,
		})
	})
	//监听端口
	// r.Run() 启动HTTP服务,默认在 0.0.0.0:8080 启动服务
	r.Run(":3001") //也可以使用这种方式设置端口
}
🚀 编译结果如下:
PS D:\文档\最近的\awesome-golang\docs\code\go-super\gin> air
  __    _   ___
 / /\  | | | |_)
/_/--\ |_| |_| \_ , built with Go
watching .
!exclude tmp
building...
running...
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET    /ping                     --> main.main.func1 (3 handlers)
[GIN-debug] POST   /login                    --> main.main.func2 (3 handlers)
[GIN-debug] PUT    /put                      --> main.main.func3 (3 handlers)
[GIN-debug] DELETE /delete                   --> main.main.func4 (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :3001
[GIN] 2022/11/01 - 20:45:41 | 200 |            0s |       127.0.0.1 | PUT      "/put"

相应 json 数据并且返回自定义 json 名称
// 定义结构体
type User struct {
	Username string `json:"用户名"`
	Password string `json:"密码"`
}	
// jaon
func main() {
	r.POST("/json", func(c *gin.Context) {
		//声明结构体
		a := &User{
			Username: "admin",
			Password: "123456",
		}
		c.JSON(http.StatusOK, a)
		//绑定参数
	})
}
🚀 编译结果如下:
{
    "用户名": "admin",
    "密码": "123456"
}
响应 jsonp 请求
💡简单的一个案例如下:
// 定义结构体
type User struct {
	Username string `json:"用户名"`
	Password string `json:"密码"`
}	
// jaon
func main() {
    //相应jsonp数据: http://localhost:3001/jsonp?callback=callback
	r.Get("/jsonp", func(c *gin.Context) {
		//声明结构体
		a := &User{
			Username: "admin",
			Password: "123456",
		}
		c.JSON(http.StatusOK, a)
		//绑定参数
	})
}
🚀 编译结果如下:
callback({"用户名":"admin","密码":"123456"});
加载yaml和xml
// 定义结构体
type User struct {
	Username string `json:"用户名"`
	Password string `json:"密码"`
}	
// jaon
func main() {
    //相应xml数据: http://localhost:3001/xml
	r.GET("/xml", func(c *gin.Context) {
		//声明结构体
		a := &User{
			Username: "admin",
			Password: "123456",
		}
		//返回xml数据
		c.XML(http.StatusOK, a)
	})
	//相应yaml数据: http://localhost:3001/yaml
	r.GET("/yaml", func(c *gin.Context) {
		//声明结构体
		a := &User{
			Username: "admin",
			Password: "123456",
		}
		//返回yaml数据
		c.YAML(http.StatusOK, a)
	})
}
🚀 编译结果如下:
#xml:
<User>
    <Username>admin</Username>
    <Password>123456</Password>
</User>
#yml
username: admin
password: "123456"
加载html
//对应html数据: http://localhost:3001/html
r.GET("/html", func(c *gin.Context) {
	//声明结构体
	a := &User{
		Username: "admin",
		Password: "123456",
	}
	//返回html数据
	c.HTML(http.StatusOK, "./web/index.html", gin.H{
		"test": a,
	})
})
gin框架采用的路由库
gin框架中采用的路由库是基于httprouter做的- 地址为:https://github.com/julienschmidt/httprouter
 
Gin模板渲染
main.go 文件:
package main
import (
	"net/http"
	"github.com/gin-gonic/gin"
)
type New struct {
	Title   string `json:"新闻标题"`
	Content string `json:"新闻内容"`
}
func main() {
	r := gin.Default()
	//html: http://localhost:8080/
	r.LoadHTMLGlob("templates/*") //表示加载templates文件夹下的所有文件
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{
			"title": "Main website",
			"t":     "xiongxinwei",
		})
	})
	//html: http://localhost:8080/news
	r.GET("/news", func(c *gin.Context) {
		n := &New{
			Title:   "new title",
			Content: "new content",
		}
		c.HTML(http.StatusOK, "news.html", gin.H{
			"title": "News website",
			"news":  n,
			"t":     "t",
		})
	})
	r.Run()
}
index.html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>这是index文件</h1>
    <!-- 渲染 -->
    <h2>{{.title}}</h2>
    <h3>t = {{.t}}</h3>
    {{$t = .title}}  <!-- 定义变量 -->
    {{$t}}  <!-- 使用变量 -->
    {{$t = 30 }}  <!-- 修改变量 -->
    {{$t}}  <!-- 使用变量 -->
    <h3>{{.t}}</h3>
</body>
</html>
news.html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>这是news文件</h1>
    <!-- 渲染 -->
    <h2>{{.title}}</h2>
    <!-- 访问news -->
    <div>
        {{.news}}  <!-- 拿到结构体对象 -->
    </div>
    <div>
        {{.news.Title}}  <!-- 拿到结构体对象的属性 -->
    </div>
    <div>
        {{.news.Content}}  <!-- 拿到结构体对象的属性 -->
    </div>
    <div>
        
    </div>
</body>
</html>
🚀 编译结果如下:



预定义函数
预定义函数浏览⚡
预定义的全局变量:
- 通过 
{{.}}访问结构体对象 - 通过 
{{.属性名}}访问结构体对象的属性 .当前对象..父对象index当前对象的索引len当前对象的长度urlquery当前对象的URL编码js当前对象的JavaScript编码html当前对象的HTML编码json当前对象的JSON编码xml当前对象的XML编码yaml当前对象的YAML编码csv当前对象的CSV编码tsv当前对象的TSV编码urlpath当前对象的URL路径编码slice当前对象的切片first当前对象的第一个元素last当前对象的最后一个元素sort当前对象的排序reverse当前对象的反转and当前对象的逻辑与or当前对象的逻辑或not当前对象的逻辑非eq当前对象的等于ne当前对象的不等于lt当前对象的小于le当前对象的小于等于gt当前对象的大于ge当前对象的大于等于add当前对象的加法sub当前对象的减法mul当前对象的乘法div当前对象的除法mod当前对象的取模call当前对象的函数调用print当前对象的打印printf当前对象的格式化打印println当前对象的换行打印
常用的内置函数和自定义模板函数
💡简单的一个案例如下(main.go 文件):
package main
import (
	"fmt"
	"html/template"
	"net/http"
	"github.com/gin-gonic/gin"
)
type New struct {
	Title   string `json:"this is 新闻标题"`
	Content string `json:"this is 新闻内容"`
}
// 自定义模板函数
func Text(title string) string {
	fmt.Println("title:", title)
	return title + " this is 自定义模板函数Text"
}
func Text2(title string, content string) string {
	fmt.Println("title:", title, "content:", content)
	return title + " " + content + " this is 自定义模板函数Text2"
}
func main() {
	r := gin.Default()
	// 加载自定义模板函数
	r.SetFuncMap(template.FuncMap{
		"Text":  Text,
		"Text2": Text2,
	})
	//html: http://localhost:8080/
	r.LoadHTMLGlob("templates/*") //表示加载templates文件夹下的所有文件
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{
			"title":  "this is a title",
			"msg":    "this is a msg",
			"score":  99,                          //score是int类型,表示分数
			"score2": 99.9,                        //score2是float64类型,表示分数
			"score3": "99.9",                      //score3是string类型,表示分数
			"hobby":  []string{"篮球", "足球", "乒乓球"}, //hobby是切片类型,表示爱好  //hobby是切片类型,表示爱好
			"map": map[string]interface{}{ //map是map类型,表示地图
				"address": "北京市海淀区",
				"tel":     "010-12345678",
			},
			//结构体
			"news": &New{
				Title:   "新闻标题",
				Content: "新闻内容",
			},
		})
	})
	r.Run()
}
index.html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 缩小h6间距 -->
    <style>
        h6 {
            margin: 0;
        }
    </style>
</head>
<body>
    <h3>这是index文件</h3>
    <!-- 渲染 -->
    <h6>titls = {{.title}}</h6>
    <h6>msg = {{.msg}}</h6>
    <h6>score(int类型分数) = {{.score}}</h6>
    <h6>score2(float64类型分数) = {{.score2}}</h6>
    <h6>score3(string类型分数) = {{.score3}}</h6>
    <h6>hobby(切片类型爱好) = {{.hobby}}</h6>
    <h6>map(地图) = {{.map}}</h6>
    <h6>news(结构体) = {{.news}}</h6>
    <h6>news.Title(结构体属性) = {{.news.Title}}</h6>
    <!-- 求msg长度 -->
    <h6>msg长度 = {{len .msg}}</h6>
    <!-- 判断msg是否为空 -->
    <h6>msg是否为空 = {{if .msg}}不为空{{else}}为空{{end}}</h6>
    <!-- 判断score是否大于60 -->
    <h6>score是否大于60 = {{if gt .score 60}}大于60{{else}}小于60{{end}}</h6>
    <!-- 遍历hobby -->
    <h6>hobby(切片类型爱好) = {{range .hobby}}{{.}} {{end}}</h6>
    <!-- 遍历map -->
    <h6>map(地图) = {{range $key, $value := .map}}{{$key}} = {{$value}} {{end}}</h6>
    <!-- 自定义模板函数
        直接在模板中调用,比如下面的函数,直接在模板中调用
    -->
    <h3>自定义模板函数/h3>
    <h6>自定义模板函数 = {{Text .title}}</h6>
    <h6>自定义模板函数2 = {{Text2 .title .msg}}</h6>
</body>
</html>
🚀 编译结果如下:

加载一个公共的模板
加载一个公共的模板,也可以叫做嵌套 template
我们一个项目里面可能有一个公共的头部或者尾部,就像我们这个仓库一样,每一页都有一个模板:
在每个html 文件的任意位置都可以使用, 注意后面的 .
<!-- 公共模板 头部-->
{{template "public/page_header.html" .}}
    
<!-- 公共模板 尾部-->
{{template "public/page_footer.html" .}}
public/page_header.html 文件
<!-- 相当于给模板定义一个名字,define end 成对出现 -->
{{define "public/page_foorter"}}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        h1{
            color: blue;
            background-color: yellow;  /* 背景色 */
            text-align: center;  /* 文字居中 */
        }
    </style>
</head>
<body>
    <h1>this is a public test page - footer</h1>
</body>
</html>
public/page_footer.html 文件:
<!-- 相当于给模板定义一个名字,define end 成对出现 -->
{{define "public/page_header"}}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        h1{
            color: red;
            background-color: yellow;  /* 背景色 */
            text-align: center;  /* 文字居中 */
        }
    </style>
</head>
<body>
    <h1>this is a public test page</h1>
</body>
</html>
路由传值
路由(Routing)是由一个 URL 和 HTTP 方法(get、post)等组成
Get传值
💡简单的一个案例如下:
// Get传值
//html: http://localhost:8080/newst?title=新闻标题&content=新闻内容
r.GET("/newst", func(c *gin.Context) {
	title := c.Query("title")
	content := c.Query("content")
	c.JSON(http.StatusOK, gin.H{
		"title":   title,
		"content": content,
	})
})
🚀 编译结果如下:

**同样也可以传递给 html **
END 链接
✴️版权声明 © :本书所有内容遵循CC-BY-SA 3.0协议(署名-相同方式共享)©

