1、Action、Controller、Result
Action指的是动作,play中大多数请求可以使用action来处理,一个请求对应一个动作也就是一个java方法,然后处理请求返回一个响应,这个响应用Result来体现
Controller就是一个继承了 play.mvc.Controller 的java类,他的返回值也是一个Result,也可以用来处理请求
Result用于返回请求的处理响应信息,它提供了一些html生成器,帮助开发者直接返回
上边这些都可以包含响应的参数。Play还提供了一种返回方式重定向,使用redirect实现
2、请求的处理-HTTP路由
Rouing路由是一种用于将传入到服务器的http请求转换成操作调用的组件,例如:将请求对应到一个controller中的公共方法,mvc框架将没有给请求看成一个事件,一个动作。每一个请求都有两个属性:请求方式、请求路径,而开发者就可以在play的路由配置文件(conf下的routes文件)中配置请求的这两个属性
play的默认路由生成器创建一个路由器类,该类接受@inject注释的构造函数中的控制器实例。这意味着类适用于依赖项注入,也可以使用构造函数手动实例化。
路由的配置格式说明,每个路由从HTTP方法开始,然后是URI模式,最后一个元素是调用定义。如下:
路由的第一部分是HTTP方法,Play路由中支持的http方法有:GET, PATCH, POST, PUT, DELETE, HEAD, OPTIONS
路由的第二部分是配置的URI模式,大致可分为两类:静态路由和动态路由,静态路由就是URI中没有任何可变参数,是什么就是什么,例如:
而动态路由则表示URI中可以包含可变的参数,例如想要根据ID来获取user信息:
又例如静态资源的访问,可以使用*来代替URI中的多段:
也可以在路由器中使用正则来进行模式匹配:
路由的第三部分是动作生成器,也就是对应的请求处理方法,处理方法可以带有参数,获取参数时会现在URI中进行查找,如果没有对应参数,则去request中查找,两种方式如下:
上图中show方法接收参数page,如果page类型是字符串时,可以默认不标明参数类型,如果想要其他类型参数,则应该显示声明,例如:
如果接收的参数使用了泛型,例如:List,那么在配置时应该使用[]来表示泛型而不是<>
传入的参数也可以设为定值,如下:
传入的参数也可以设置默认值,当请求中找不到此参数时,则使用此默认值,如下:
传入的参数可以设置为可选值,就是当参数为空时,则抛弃这个参数,如下:
上边说的都是将请求对应到一个Controller,也可以通过为动作生成器设置参数,将参数设置成request,将他发送到一个action,如下:
路由具有优先级,当一个请求同时对应多个路由时,则会以第一个路由对应的方法为准。
路由器可以用来从Java调用中生成URL。这使得可以将所有的URI模式集中在一个配置文件中,对于路由文件中使用的每个控制器,路由器将在路由包中生成“反向控制器”,具有相同的操作方法和相同的签名,但返回play.mvc.call而不是play.mvc.result。play.mvc.call定义一个HTTP调用,并提供HTTP方法和URI。调用使用方式如下:
有些情况下,返回相对路径而不是绝对路径可能很有用。play.mvc.call返回的路由总是绝对的(它们以/开头),当对Web应用程序的请求被HTTP代理、负载均衡器和API网关重写时,这可能会导致问题。(此处没有理解透)
3、响应的处理
对于响应信息,play提供了ok方法来帮助完成,可以根据返回的内容来自动的生成对应内容类型的响应信息,例如:
Play会总动根据返回的内容生成对应内容的响应信息,一个是text/plain类型的,一个是application/json类型的。如果不想让其自动生成,可以使用.as方法来设置内容的类型(Content-Type),如下:
开发者也可以自己设置响应的头信息,如下:
开发者也可以在响应中添加和清空cookie信息,如下:
返回的文本信息,play默认使用的字符编码是utf-8,也支持用户自定义编码方式,如下:
4、session和flash域
Play中的Session和flash域中的数据不存储在服务器中,而是使用cookie的方式添加到每个后续的HTTP请求中。存储的数据大小最大不能超过4KB,play中的Session不能用作缓存,因为它的实质相当于一个cookie,当用户关闭浏览器结束此次会话时,session就过期了,达不到作为缓存的目的,如果想用缓存可以使用play内置的缓存机制,也可以使用第三方缓存,例如:redis。
Session中存储的数据在整个用户会话期间都可用,在一次会话中可以通过设置session过期:在application.conf中添加配置play.http.session.maxAge。Session cookie中的值使用密钥进行了加密,因此客户端无法修改cookie数据。
flash作用域中存储的数据只对下一个请求可用。其用法和session相同,只不过flash cookie中的值没有经过加密,可以被修改,所以一般使用flash域来存储响应状态信息。
5、请求(体)解析器
Play中将request的头信息封装到RequestHeader类中,将request的body信息封装到BodyParser中。
play是一个异步框架,传统的IO不能用于读取请求体,当试图读取时,输入流会被阻塞,对应线程必须等待数据可用。因此play使用异步流库AKKA流。Akka Streams是反应流的一种实现,它是一种SPI,允许许多异步流API无缝地协同工作。
一般使用play默认的解析器即可满足要求,解析器可以将application/json格式的内容封装到一个JsonNode对象中:
其他的格式内容封装:
使用默认的解析器缓冲请求体时,可能在内存和磁盘上都有缓冲区,为了避免恶意的大量数据缓冲,可以配置缓冲区的大小,在application.conf文件中配置两个缓冲区的大小:
内存中缓存区限制:play.http.parser.maxMemoryBuffer = 256k
磁盘上缓存区限制:play.http.parser.maxDiskBuffer = 1024k
上边是使用play默认的解析器,还允许开发人员写自己的解析器,需要实现 BodyParser 类,具体如下:
使用新建的解析器:
更复杂的操作可以访问官网
6、动作组合
我们知道当访问一个路径时,最终指向的是一个action中方法,一个只能对应一个,而动作组合则可以实现在执行指定方法之前执行别的动作,play中使用 @with 注解来实现。首先需要我们先写一个可以和别的方法组合的action,如下:
组合时直接用with注解即可,如下:
这是请求就会先到达VerboseAction中执行相应操作,然后通过call方法,请求再进入到verboseIndex方法中,有点前置动作的意思。注意:每一个请求都必须对应一个实例,否则可能出现问题。
Play允许自己声明动作组合的注解,此注解必须@with注解进行注释,开发者想组合的动作类需要填充到with注解中,如下:
可以直接使用注解VerboseAnnotation实现动作组合即可,可以使用动作组合(动态绑定)的方式实现权限控制或者日志的记录。可以用动作组合的注释直接修饰控制器类,将应用于该控制器类中所有操作方法。
可以将组合动作中的数据传递到要访问的对应的请求中,如下: