路由

最后更新于:2022-04-01 04:21:51

路由定义在一个单独的 `routes` 文件中. 路由定义规则是: ~~~ (METHOD) (URL Pattern) (Controller.Action) ~~~ 下面演示路由的定义: ~~~ # conf/routes # 这个文件定义了应用程序的所有路由 (优先级按照先后顺序) GET /login App.Login # 一个简单的路由 GET /hotels/ Hotels.Index # 一个简单的路由,带不带斜线后缀都一样 GET /hotels/:id Hotels.Show # 绑定到一个URI参数id WS /hotels/:id/feed Hotels.Feed # WebSockets POST /hotels/:id/:action Hotels.:action # 自动匹配路由到一个控制器的多个方法 GET /public/*filepath Static.Serve("public") # 映射到 /public/下的静态文件 ~~~ * /:controller/:action :controller.:action # 捕获所有控制器方法; 自动生成 URL 接下来我们一个个看。最后在看看如何实现 **反转路由** – 生成URL调用一个特定的方法 ## 一个简单的路由 ~~~ GET /login App.Login ~~~ 直接将一个URL精确匹配到一个控制器方法。 ## 斜线后缀 ~~~ GET /hotels/ Hotels.Index ~~~ `/hotels` 和 `/hotels/` 路由都会调用 `Hotels.Index` 方法。反转 `Hotels.Index`产生的URL则会包含斜线后缀。 斜线后缀无法用于区分两个同名路由,`/login` 和 `/login/`是一样的 ## URL 参数 ~~~ GET /hotels/:id Hotels.Show ~~~ Revel可以从URL重提取参数并绑定到控制器方法。`:id` 变量会尝试匹配除了斜线后缀外的任意值。举个栗子,`/hotels/123`和 `/hotels/abc` 都与这个路由匹配。 提取的参数保存到 `Controller.Params` map中, 绑定到控制器方法Show中. 举个栗子: ~~~ func (c Hotels) Show(id int) revel.Result { ... } ~~~ 或 ~~~ func (c Hotels) Show() revel.Result { var id string = c.Params.Get("id") ... } ~~~ 或 ~~~ func (c Hotels) Show() revel.Result { var id int c.Params.Bind(&id, "id") ... } ~~~ ## 通配符 ~~~ GET /public/*filepath Static.Serve("public") ~~~ 路由器识别第二种通配符 。通配符必须放到路由的最后一个元素前, 匹配所有以*之前路径开头的URL 这里的路由将匹配 “/public/”和以他开头的所有路径 ## Websockets ~~~ WS /hotels/:id/feed Hotels.Feed ~~~ Websockets 以同样的方式接受请求, 它使用 **WS**标识符 相应的方法签名如下: ~~~ func (c Hotels) Feed(ws *websocket.Conn, id int) revel.Result { ... } ~~~ ## 静态文件服务 ~~~ GET /public/*filepath Static.Serve("public") GET /favicon.ico Static.Serve("public","img/favicon.png") ~~~ 对于使用2个参数的Static.Serve, 在 **”** 和 **,** 之间不允许有空格,due to how encoding/csv works. 对于静态资源服务, Revel 有**static** 模块支持, 包含一个单一的带两个参数的[静态](http://godoc.org/github.com/revel/revel/modules/static/app/controllers) 控制器 * 前缀 (字符串) - 指定到静态文件根目录的相对或绝对路径 * 文件路径 (字符串) - 指定文件的相对路径。 (可以参考 [代码结构布局图](http://gorevel.cn/docs/manual/organization.html) 了解更多信息) ## 固定参数 路由可以绑定一个或多个参数到控制器方法中,举个栗子: ~~~ GET /products/:id ShowList("PRODUCT") GET /menus/:id ShowList("MENU") ~~~ 参数通过在路由中的位置绑定到参数名,这里,列表中的字符串将被绑定到方法的第一个参数中。 下面是几种有用的情况: * 一组相似功能的方法 * 相同功能的方法,但工作在不同的模式 * 相同功能的方法,但操作不同的数据类型 ## 自动路由 ~~~ POST /hotels/:id/:action Hotels.:action ~~~ * /:controller/:action :controller.:action URL 的提取也可以用于确定调用哪个控制器方法。匹配规则不区分大小写 第一个例子匹配下面的路由 ~~~ /hotels/1/show => Hotels.Show /hotels/2/details => Hotels.Details ~~~ 第二个例子匹配应用程序中的任意的方法 ~~~ /app/login => App.Login /users/list => Users.List ~~~ 由于匹配控制器和方法不区分大小写,下面的路由也匹配 ~~~ /APP/LOGIN => App.Login /Users/List => Users.List ~~~ 使用自动路由作为一个捕获所有的方法(例如文件中的最后一个路由),用于快速挂接方法,to non-vanity URLs,尤其是在与反向路由器一起使用是很有用的。 ## 反转路由 对于以下几种情况,使用反转路由生成URLs是一个很好的方法, * 避免拼写错误 * 编译器确保反向路由有正确的数量和参数类型。 * 修改路由,仅需要在routes文件中修改一次 构建程序时,Revel自动生成一个路由包`app/routes`,一条语句就可以使用: ~~~ routes.Controller.Action(param1, param2) ~~~ 上面的语句使用Controller.Action和参数返回一个字符串类型的 URL,下面给出一个完整的例子: ~~~ import ( "github.com/revel/revel" "project/app/routes" ) type App struct { *revel.Controller } // 生成一个表单页面 func (c App) ViewForm(username string) revel.Result { return c.Render(username) } // 处理提交的表单 func (c App) ProcessForm(username, input string) revel.Result { ... if c.Validation.HasErrors() { c.Validation.Keep() c.Flash.Error("Form invalid. Try again.") return c.Redirect(routes.App.ViewForm(username)) // <--- 反转路由 } c.Flash.Success("Form processed!") return c.Redirect(routes.App.ViewConfirmation(username, input)) // <--- 反转路由 } ~~~ **局限性:** Only primitive parameters to a route are typed due to the possibility of circular imports. Non-primitive parameters are typed as interface{}.
';