Play2 for Java(三:route)

Module 3 Route路由

在这个模块中,我们将看一下Play!如何处理请求路由。我们首先来看router的作用,以及它为什么重要。我们将看到router的基本机制是如何工作的。然后我们将研究DSL,或者说是领域特定语言,由Play!提供用来定义路由的。我们将介绍一些DSL方面的内容,比如路由定义的基本语法,通过令牌、clobbing和正则表达式定义动态URI部分,为动态部分和路由优先级指定类型和默认值。最后,我们将简要介绍反向路由以及Play!如何通过DSL提供类型安全路由。

3.1 Router

与几乎所有基于mvc的web框架一样,路由器是最基本的概念之一,但它很少被关心。路由器负责检查传入的HTTP请求的各个方面,正如router的名字所表达的,它的作用就是将请求路由到特定controller(控制器)的特定Action(动作)上。
Using Router:

这里写图片描述

Non-Using Router

实际上,路由器是非常重要的,如果没有它,您基本上只能使用一个操作来处理对应用程序的每个请求。

这里写图片描述

在最坏的情况下,那么这就是一个很大的If语句,在每个可能的可接受的路由中都有一个分支。然而,良好编程实践的进一步应用,如单一责任原则,建议每个类都应该有一个单一的责任,最终你最终会得到一个基本的路由器。

这里写图片描述

所以你可以看到路由器是一个非常重要的组件,你最终会通过应用基本的编程原理来创建它。幸运的是,没有必要每次都重新创建路由器,因为每个相当完整的web框架都已经有了。

3.2 工作原理

在我们学习路由的特殊语法之前,我们来学习Play的路由组件的工作原理。

这里写图片描述

如前所述,router(路由器)将传入的HTTP请求转换成特定的控制器的操作。它通过观察请求的两个关键方面来实现这一点;HTTP方法,或动词,以及请求路径。

这里写图片描述

HTTP方法或动词表示请求的意图。HTTP方法或动词表示请求的意图。例如,GET请求指示从服务器检索资源的意图;POST请求将表单数据发送到服务器,目的是创建一个新资源;PUT请求与POST类似,但在更新现有资源时通常使用它;删除请求被用作删除资源的意图。这四种方法提供了实现典型的CRUD应用程序、创建、读取、更新和删除的基本方法。:除了典型的CRUD操作之外,还有许多其他的方法也有特定的意图。

这里写图片描述

请求路径是URL的尾部。如果你认为URL是两个部分;第一部分负责确保您的请求通过internet到达您的服务器和web应用程序;第二部分由web应用程序使用,以确定要执行的操作。虽然请求的每个部分都可以应用于您的应用程序,但是router(路由器)通常只需要知道请求路径和HTTP动词。

3.3 路由规则

要确定请求路由到的地方,路由器需要一系列的规则。
有很多方法可以做到这一点。你可以使用基本的约定;例如,ASP.NET MVC中根据控制器名称、动作名称和可选的id参数的约定,提供了基本的开箱即用。这种方法对于理解该约定的开发者来说是可访问的,并且可以提高生产力,因为它减少了需要执行的配置的配置数量,但当你的路线需要打破这个惯例时,它可能是相当有限的。或者,您可以直接一对一地映射路由规则和处理程序。Ruby的Sinatra和Node的ExpressJS都是将路由映射到处理程序的声明方法。这是一种非常简单、非常有效的方法来表达路线及其相关的处理程序。然而,它可能导致路由定义在您的代码库周围传播,这使得维护变得困难。

ASP.NET MVC:

这里写图片描述

Spring:

这里写图片描述

注释是提供路由的另一种方式。ASP.NET MVC和Spring都支持使用类注释将action或handler映射到特定的路由。注释在路由配置中提供了一定程度的灵活性,但是正如您所看到的,随着应用程序的路由数量的增加,它们可能导致相当嘈杂的代码。

这里写图片描述

最后,通过使用DSL来实现直接路由声明的路由选择(即上图)。Rails,以及我们即将看到的Play!,两者都使用类似DSL的方法来在单独的文件中指定路由。DSL方法为声明路由定义提供了一个单点,该方法使用专门针对路由声明的专门语法来声明路由定义。

3.4 Play的路由

Play!在conf文件夹下的router文件中定义您的路由。在这个文件中,通过使用DSL来声明,正如前面小节中提到的那样。

这里写图片描述

一条基本的路由是这样的,路线声明由三个主要部分组成:
    ①HTTP动词或方法
    ②路径或URI模式
    ③以及对Action本身的调用。
定义的这个路由,以简单的语义描述的话就是:“当一个GET请求被发送到/customer路由时,调用Customers控制器(注:controllers是文件夹名,而customers则是控制器类的名字,list是该控制器内的方法的名字,下面会详细的讲解)的列表操作。”

3.5 Play路由的HTTP动词

Play!为大多数有效的HTTP谓词(GET/POST/PUT/DELETE/TRACE等)提供支持。不过,除非你在写一个广泛的API,这在Play是完全可能的,除此之外您的大多数web应用程序可能会被限制在GET和POST请求上。

一个简单的API,例如在一个页面应用程序架构中,可能还会用到PUT和DELETE方法。

3.6 Play的路径、URI模式

我们的路由所定义的路径更准确地称为URI模式,因为它可以用于捕获多个路径。在我们当前截图中的那个例子中,那条router是完全固定的,这就是所谓的静态路由.

这里写图片描述

如果我们考虑一个更复杂的场景,比如/ustomer/view/2中,我们将完全不可能为数据库中的每个客户id定义静态路由(见上图)。这时,我们需要将动态部分引入到URI模式中。
在Play!中,有许多方法可以从URI模式中提取数据:
    ①它可以通过使用冒号前缀标记来完成,
    ②clobbing,这是一种包罗万象的方法
    ③更严格地通过带有正则表达式验证的符号
路由标记(即①)的方法非常常见,您可能会发现这种方法适合大多数情况,我们可以使用这种办法来解决之前的/customer/view/2的问题。我们只需用一个:id的标记来约束id=2。当路由器匹配此路由的请求时,它将尝试提取:id并将其解析为所需的类型,使它可以传递到操作调用。可以将任意数量的标记指定为URI模式的一部分,但标记名称必须是惟一的,因为它们将被传递到下一个路由段中的操作当中去。

这里写图片描述

这里写图片描述

有些情况下,路由不能被严格定义为静态和动态部分的集合。举个例子,如果你想定义一个路由,从资产文件夹下面提供静态资产,你不会想要为每个资产定义一个静态路由,也不希望通过在文件夹和文件名中引入不同的标记来施加任何特定的结构,因为这会变得过于复杂,当然也会降低灵活性。Play!提供了clob路由参数的能力。使用一个带有星号前缀的名称,Play!将尾随路径片段提取到一个字符串中,并将其传递给action调用。因此,像/assets/js/appjs这样的路由将会匹配上我们的路由,js/appjs将被传递给调用的Action。

这里写图片描述

表达URI模板的动态部分的最后一种方法是正则表达式。正则表达式允许您更严格地指定动态段的格式。例如,在我们的客户视图router中,如果我们知道id始终是数字的,我们可以使用正则表达式指定id部分。那么这有什么区别呢?在基于标记(就是方式①)的方法中,如果我们的操作期望一个数字值,我们通过字母或非数字符号传递它,我们就会得到一个错误。所发生的是路由本身与URI模式匹配,但试图强制将路由段转换成数字实际上会抛出异常。这个错误需要被一个自定义代码捕获并显式地处理。但是,如果我们使用正则表达式指定路由,就像我们刚才看到的那样,路由本身不会匹配,最终会得到一个404 Not Found响应。正则表达式语法有一个潜在的缺点;如果我们更改customer的id的类型,我们不仅需要在领域模型中更改它,而且我们的领域定义已经泄漏到路由器中,我们也需要在那里改变它。

3.7 Play路由的Action调用

这里写图片描述

路由定义的最后一部分是对操作的实际调用。在Play!中,Action被定义为控制器类的静态方法。因此,Action调用只不过是对Action本身的完全限定的引用。

这里写图片描述

如果您的操作从路由中提取了参数,如前面所讨论的,您也可以在这里引用它们。例如,我们的视图客户示例可以表示为controllers.Customers.view方法,使用Long类型的id参数,从路径中提取id参数,并转换或解析为预期类型。

这里写图片描述

还可以指定默认值。例如,如果在我们系统中有一个显示订单页列表的路由,我们想要将页码号作为路由参数传递,我们可以如上图这样做。如果我们所提供的请求路径时/orders/,那么就使用默认值page=1来进行操作,就像传来的请求时/orders/1一样。

3.8 反向路由

可以使用路由器在Java调用中生成URL。这使得在单个配置文件中集中所有URI模式成为可能,因此在重构应用程序时,您可以更加自信。

这里写图片描述

// Redirect to /hello/Bob
public Result index() {
    return redirect(controllers.routes.Application.hello("Bob"));
}
对于在router文件中使用的每个controller(控制器),路由器将在routes包中生成一个“反向控制器”,具有相同的操作方法,具有相同的签名,但返回一个play.mvc.Call而不是play.mvc.Result。play.mvc.Call定义了一个HTTP调用,并提供了HTTP方法和URI。
PS:
每个控制器包都有一个routes子包。所以controllers.Application.hello操作,可以通过controllers.routes.Application.hello翻转(只要在路由文件中没有其他路径,就会与生成的路径匹配)。
PS:
新版本应该是移除了这个工具方法~~所以就以代码形式呈现吧

3.9 总结

所以总而言之,Play!它的路由功能提供了一些很好的好处。集中的配置方式使router的管理变得简单。一个干净的DSL使声明简单易读。而反向路由特性意味着你可以得到编译时的检查路线和它们的参数。

猜你喜欢

转载自blog.csdn.net/qq_31179577/article/details/78728601