美文网首页
HTTP 路由

HTTP 路由

作者: zerolinke | 来源:发表于2016-04-11 14:00 被阅读198次

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

    相关文章

      网友评论

          本文标题:HTTP 路由

          本文链接:https://www.haomeiwen.com/subject/uruvlttx.html