[[toc]]
[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
🚀 编译结果如下:
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")
}
💡简单的一个案例如下:
// 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"
// 定义结构体
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"
}
💡简单的一个案例如下:
// 定义结构体
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"});
// 定义结构体
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数据: 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
框架中采用的路由库是基于httprouter做的- 地址为:https://github.com/julienschmidt/httprouter
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>
:::
::: details 预定义函数浏览⚡ 预定义的全局变量:
- 通过
{{.}}
访问结构体对象 - 通过
{{.属性名}}
访问结构体对象的属性 .
当前对象..
父对象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传值
//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 **
-
✴️版权声明 © :本书所有内容遵循CC-BY-SA 3.0协议(署名-相同方式共享)©