内置的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