HTTP 路由

内置的HTTP路由器

这个路由器用于翻译每一个接收到的HTTP请求到对应的action(一个controller类的public方法)调用.
一个HTTP请求被视为MVC框架的一个event.这个event包含两个主要的信息部分:

  • request path (e.g. /clients/1542, /photos/list),包含query string.
  • HTTP method (GET,POST,...).

路由被定义在conf/routes 文件中,是被编译过的.这意味着你会在路由出错的时候直接在你的浏览器中看到他们:


路由出错的时候,你会在你的浏览器中与她相逢
路由出错的时候,你会在你的浏览器中与她相逢

路由的依赖注入

Play 支持生成两种类型的路由器.一个是依赖注入路由器,另一个是静态路由器.默认的是依赖注入路由器,这也是 Play的种子模板(Play seed Activator templates)中选择的方案,因为我们推荐你使用依赖注入的controllers.如果你需要使用静态controller,你可以切换静态路由生成器 通过添加下面的配置到你的 build.sbt 文件中:

routesGenerator := StaticRoutesGenerator

Play 的文档中代码例子假定你使用的是依赖注入的路由生成器.如果是静态路由生成器,你可以通过在路由文件中controller的调用地方使用@符号作为前缀,或者声明每一个action方法为一个 static 方法来适配代码示例.

路由文件的书写语法

conf/routes 是路由器使用的配置文件.这个文件列出了应用需要的所有路由.每一个路由由一个HTTP method, 一个URI pattern和需要调用的相关action method组成.
让我们看看路由定义的样子:

GET      /clients/:id            controllers.Clients.show(id: Long)

注意:在action的调用地方,需要将参数的类型写在参数名称后面, 类似Scala风格.

每一个路由由HTTP method 开始,后面是URI pattern.最后是一个调用定义.你也可以添加一些注释在路由文件中,使用 # 字符:

# Display a client.
GET      /clients/:id            controllers.Clients.show(id: Long)

HTTP method

这个 HTTP method 可以是任何 HTTP支持的有效方法(GET, PATCH, POST, PUT, DELETE, HEAD,OPTIONS).

URI pattern

URI pattern 定义了路由的请求路径.请求路径的一部分可以是动态的.

静态的path

举个例子,要完全匹配 GET /clients/all 这个请求,你可以这样定义路由:

GET      /clients/all            controllers.Clients.list()
动态部分

如果你想定义一个路由,比如说,通过ID检索客户端,你需要添加一个动态部分:

GET      /clients/:id            controllers.Clients.show(id: Long)

注意:一个URI pattern可能有不止一个动态部分.

动态部分的默认匹配策略是由正则表达式:

[^/]+

定义的,即任何使用 :id 定义的动态部分将匹配一个URI的path段.

动态部分跨越多个/

如果你想要一个动态部分来捕获多个URI path段,用斜线分开,你可以使用* id语法来定义一个动态部分,它使用 .* 正则表达式:

GET      /files/*name            controllers.Application.download(name)

这里,像 GET /files/images/logo.png 这样的请求, 这个name动态部分将捕获 /images/logp.png 作为值.

自定义正则表达式的动态部分

当然你通过你自己的正则表达式定义一个动态部分,使用 $id<regex> 语法:

GET      /items/$id<[0-9]+>            controllers.Items.show(id:Long)

调用action生成器方法

路由的最后一部分定义了一个调用.这部分必须定义一个有效的action method 调用.
如果这个调用方法没有定义任何参数,那么只需要一个方法名称就可以:

GET      /            controllers.Application.homePage() 

如果action方法定义了参数,相对应的参数就会在request URI中查找匹配,URI中的URI path和query string都会被查找。

# Extract the page parameter from the path.
# i.e. http://myserver.com/index
GET      /:page            controllers.Application.show(page)

或者是:

# Extract the page parameter from the query string
#  i.e. http://myserver.com/?page=index
GET      /            controllers.Application.show(page)

下面是定义在 controllers.Application控制器中对应的show方法:

public Result show(String page) { 
        String content = Page.getContentOf(page);             
        response().setContentType("text/html");
        return ok(content);
}
参数类型

对于String类型的参数,参数类型是可选的.如果你想要 Play去转换参数为一个指定的Scala类型,你可以添加一个显式类型:

GET      /clients/:id            controllers.Clients.show(id: Long)

然后在对应控制器的action方法参数中使用相同的类型:

public Result show(Long id) { 
      Client client = clientService.findById(id);
      return ok(views.html.Client.show(client));
}

注意:这个参数类型的指定使用的是后缀语法.此外,泛型的指定使用[]符号代替java中的<>符号.比如,List[String]就是Java 里的List<String>.

固定值的参数

有时候你可能想要使用一个固定值的参数:

# Extract the page parameter from the path, or fix the value for /
GET      /            controllers.Application.show(page = "home")
GET      /:page            controllers.Application.show(page)
具有默认值的参数

当然你也可以提供一个默认值用在一个请求没有携带参数值的时候:

# Pagination links, like /clients?page=3
# 分页的时候
GET      /clients            controllers.Clients.list(page: Int ?= 1)
可选参数

你可以指定只一个不需要存在于所有请求中的可选参数:

# The version parameter is optional. E.g. /api/list-all?version=3.0
GET      /api/list-all            controllers.Api.list(version ?= null)

路由优先级

很多路由可以匹配一些相同的请求,如果有冲突,按照声明顺序的第一个路由将被使用.

反向路由

路由器可以被java调用生成一个URL.这使你可以将你的URI patterns 集中在一个单独的配置文件中,这样当你重构你的应用的时候你可以更加自信.

对于路由文件使用的每一个控制器,路由器会生成一个反向控制器在routes包中,包含相同的action方法,相同的签名但是返回的play.mvc.Result对象被paly.mvc.Call对象替代.
这个play.mvc.Call 定义了一个HTTP调用,提供相同的HTTP method和 URI.
举个例子,如果你创建了一个这样的controller:

package controllers;
import play.*;
import play.mvc.*;
public class Application extends Controller{
    public Result hello(String name) { 
        return ok("Hello " + name + "!"); 
       }
}

并且在 conf/routes文件中映射它:

# Hello action
GET      /hello/:name            controllers.Application.hello(name)

那么你可以导向一个URL到 hello action方法,通过使用 controllers.routes.Application reverse controller:

// Redirect to /hello/Bob
public Result index() { 
return redirect(controllers.routes.Application.hello("Bob"));
}

注意: 这里每个controller有一个routes子包,比如 controllers.admin.Applications.hello 的action可以被反向调用通过 controllers.admin.routes.Application.hello .

高级路由

参考 Routing DSL

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • HTTP请求/响应路由是用于决定在当前请求下,哪一个句柄去接收和响应。句柄可以是一个函数、过程或者方法,只要能够接...
    小笨憨阅读 1,956评论 0 0
  • 1.基本路由 所有应用路由都定义在 App\Providers\RouteServiceProvider 类载入的...
    lmem阅读 905评论 0 0
  • 上图列出了 Laravel HTTP 层的相关知识大纲。由于目前自己的工作中网页、App、小程序等都采用前后台分离...
    胖福哥阅读 1,833评论 0 21
  • “慎独” “此谓诚于中,形于外,故君子必慎其独也”出自《大学》意思即是一个人内心中的喜怒哀乐、善良邪恶,无论如何隐...
    大才阅读 981评论 0 5