Gin框架入门系列-路由与控制器及静态网站

1.概述

路由是一个过程,指的是一个http请求,如何找到对应的处理器函数(也可以叫控制器函数),Gin框架的路由是基于httprouter包实现的。

控制器函数主要负责执行http请求-响应任务。

一个简单的例子:

代码语言:javascript
复制
r := gin.Default()

// 路由定义post请求, url路径为:/user/login, 绑定doLogin控制器函数
r.POST("/user/login", doLogin)

// 控制器函数
func doLogin(c *gin.Context) {
// 获取post请求参数
username := c.PostForm("username")
password := c.PostForm("password")

// 通过请求上下文对象Context, 直接往客户端返回一个字符串
c.String(200, "username=%s,password=%s", username,password)

}

2.路由规则

一条路由规则由三部分组成:

  • • http请求方法
  • • url路径
  • • 控制器函数

1.http请求方法

常用的http请求方法有下面4种:

  • • GET
  • • POST
  • • PUT
  • • DELETE

2.url路径

gin框架,url路径有三种写法:

  • • 静态url路径
  • • 带路径参数的url路径
  • • 带星号(*)模糊匹配参数的url路径

下面看下各种url路由的例子

代码语言:javascript
复制
// 例子1, 静态Url路径, 即不带任何参数的url路径
/users/center
/user/111
/food/12

// 例子2,带路径参数的url路径,url路径上面带有参数,参数由冒号(:)跟着一个字符串定义。
// 路径参数值可以是数值,也可以是字符串

//定义参数:id, 可以匹配/user/1, /user/899 /user/xiaoli 这类Url路径
/user/:id

//定义参数:id, 可以匹配/food/2, /food/100 /food/apple 这类Url路径
/food/:id

//定义参数:type和:page, 可以匹配/foods/2/1, /food/100/25 /food/apple/30 这类Url路径
/foods/:type/:page

// 例子3. 带星号()模糊匹配参数的url路径
// 星号代表匹配任意路径的意思, 必须在
号后面指定一个参数名,后面可以通过这个参数获取*号匹配的内容。

//以/foods/ 开头的所有路径都匹配
//匹配:/foods/1, /foods/200, /foods/1/20, /foods/apple/1
/foods/*path

//可以通过path参数获取*号匹配的内容。

3.控制器函数

控制器函数定义:

代码语言:javascript
复制
func HandlerFunc(c *gin.Context)

控制器函数接受一个上下文参数。可以通过上下文参数,获取http请求参数,响应http请求。

4.路由定义例子

代码语言:javascript
复制
//实例化gin实例对象。
r := gin.Default()

//定义post请求, url路径为:/users, 绑定saveUser控制器函数
r.POST("/users", saveUser)

//定义get请求,url路径为:/users/:id (:id是参数,例如: /users/10, 会匹配这个url模式),绑定getUser控制器函数
r.GET("/users/:id", getUser)

//定义put请求
r.PUT("/users/:id", updateUser)

//定义delete请求
r.DELETE("/users/:id", deleteUser)

//控制器函数实现
func saveUser(c *gin.Context) {
...忽略实现...
}

func getUser(c *gin.Context) {
...忽略实现...
}

func updateUser(c *gin.Context) {
...忽略实现...
}

func deleteUser(c *gin.Context) {
...忽略实现...
}

提示:实际项目开发中不要把路由定义和控制器函数都写在一个go文件,不方便维护,可以参考第一章的项目结构,规划自己的业务模块。

3.分组路由

在做api开发的时候,如果要支持多个api版本,我们可以通过分组路由来实现api版本处理。

例子:

代码语言:javascript
复制
func main() {
router := gin.Default()

// 创建v1组
v1 := router.Group("/v1")
{
   // 在v1这个分组下,注册路由
    v1.POST("/login", loginEndpoint)
    v1.POST("/submit", submitEndpoint)
    v1.POST("/read", readEndpoint)
}

// 创建v2组
v2 := router.Group("/v2")
{
   // 在v2这个分组下,注册路由
    v2.POST("/login", loginEndpoint)
    v2.POST("/submit", submitEndpoint)
    v2.POST("/read", readEndpoint)
}

router.Run(":8080")

}

上面的例子将会注册下面的路由信息:

  • • /v1/login
  • • /v1/submit
  • • /v1/read
  • • /v2/login
  • • /v2/submit
  • • /v2/read

路由分组,其实就是设置了同一类路由的url前缀。

html模板处理

Gin 框架默认封装了golang内置的html/template包用于处理html模版,如果你开发的是接口服务,不提供html页面可以跳过本章内容。

前置技术知识点:

  • • 模板引擎 - 点击Go模板引擎教程,学习完整的模板引擎语法。

1.返回html结果的例子

代码语言:javascript
复制
func main() {
// 初始化gin对象
router := gin.Default()
// 首先加载templates目录下面的所有模版文件,模版文件扩展名随意
router.LoadHTMLGlob("templates/*")

// 绑定一个url路由 /index
router.GET("/index", func(c *gin.Context) {
            // 通过HTML函数返回html代码
            // 第二个参数是模版文件名字
            // 第三个参数是map类型,代表模版参数
            // gin.H 是map[string]interface{}类型的别名
    c.HTML(http.StatusOK, "index.html", gin.H{
        "title": "Main website",
    })
})
    // 启动http服务,并且绑定在8080端口
router.Run(":8080")

}

模版代码

文件名:templates/index.html

代码语言:javascript
复制
<html>
<h1>
{{ .title }}
</h1>
</html>

2.处理模版子目录的情况

一般在项目中,因为有多个模块的模版文件,我们都会以多个子目录的方式来组织模版文件,上面的例子只能加载某个目录下面的模版文件,无法加载子目录的模版文件。

例子:

代码语言:javascript
复制
func main() {
router := gin.Default()
// 加载templates目录下面的所有模版文件,包括子目录
// / 代表所有子目录下的所有文件
router.LoadHTMLGlob("templates/
*/*")

router.GET(&#34;/posts/index&#34;, func(c *gin.Context) {
            // 子目录的模版文件,需要加上目录名,例如:posts/index.tmpl
    c.HTML(http.StatusOK, &#34;posts/index.tmpl&#34;, gin.H{
        &#34;title&#34;: &#34;Posts&#34;,
    })
})
router.GET(&#34;/users/index&#34;, func(c *gin.Context) {
            // 子目录的模版文件,需要加上目录名,例如:users/index.tmpl
    c.HTML(http.StatusOK, &#34;users/index.tmpl&#34;, gin.H{
        &#34;title&#34;: &#34;Users&#34;,
    })
})
router.Run(&#34;:8080&#34;)

}

模版文件:templates/posts/index.tmpl

代码语言:javascript
复制
{{ define "posts/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}

模版文件:templates/users/index.tmpl

代码语言:javascript
复制
{{ define "users/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using users/index.tmpl</p>
</html>
{{ end }}

如何访问静态资源文件

如果项目中包含js、css、jpg之类的静态文件,怎么访问访问静态文件?

下面例子介绍如何处理访问静态资源文件:

代码语言:javascript
复制
func main() {
router := gin.Default()
// 设置静态资源文件目录,并且绑定一个Url前缀
// 静态资源文件目录:/var/www/xj/assets
// /assets是访问静态资源的url前缀
// 例如:
// /assets/images/1.jpg 这个url文件,存储在/var/www/xj/assets/images/1.jpg
router.Static("/assets", "/var/www/xj/assets")

    // 为单个静态资源文件,绑定url
    // 这里的意思就是将/favicon.ico这个url,绑定到./resources/favicon.ico这个文件
router.StaticFile(&#34;/favicon.ico&#34;, &#34;./resources/favicon.ico&#34;)

// Listen and serve on 0.0.0.0:8080
router.Run(&#34;:8080&#34;)

}

提示:设置/favicon.ico这个url,其实就是为网站设置图标,浏览器默认会将这个url作为网站默认图标。