- 应用全局设置
全局对象
在你的项目中定义一个Global对象,它为你处理应用的全局设置. 这个对象必须定义在默认包中(即不带 package 声明的包).1import play.api._ 2 3object Global extends GlobalSettings { 4 5}小贴士: 你也可使用
Unmi 注: GlobalSettings.scala 放在 app 目录比较合适,Scala 的 package 层次与目录并不存在严格的对应关系。application.globalkey 值在在配置中指定自己的GlobalSettings实现类名称.
要说呢,不带 package 声明的写法确实不是什么好习惯,因为其他带 package 声明的类无法使用它。见:为何Java的有包名的类不能引用默认包中的类。这就对了,本来这个全局对象就不是给别的类用的 - Don't call me, I'll call you。
勾住应用启动和停止事件
你可以覆盖方法onStart和onStop,它们会在应用的生命周期启动,停止时得到通知: Read More
有时候我们要在 Play 应用中调用其他的 HTTP 服务. Play 是通过它的play.api.libs.ws.WS库对此支持的, 该库提供了进行异步的 HTTP 调用.
任何由play.api.libs.ws.WS发出的调用都必须返回Promise[play.api.libs.ws.Response],我们可以接着可用 Play 的异步机制来处理它.
Unmi 注: 这里有必须挪出 Play 1 和 Play 2 的 WS 稍加对比:
Play 1 中 play.libs.WS 类,Play 2 里是 play.api.libs.ws.WS,Play 2 中许多给外部调用的 API 都放在 play.api.libs 包中了。
Play 1 的 play.libs.WS.WSRequest 中有 get():HttpResponse, getAsync():Promise<HttpResponse>, put():HttpResponse, putAsync():Promise<HttpResponse>,它把同步和异步调用分得很清楚。
而 Play 2 的 play.api.libs.ws.WS.WSRequestHolder 里只有 get(): Promise<Response>, post(): Promise<Response> 这样方法,在这个位置上,它不再分同步还是调用,这个任务交给 Async 方法去决定。
对异步请求的数据获仍然是由 Action 处理,如 Play 1 中 Action 的各个 await() 方法; Play 2 里的 Action 用 Async 方法。 Read More- 默认的 Cache API 实现是用的 EHCache. 你也可以通过插件来提供自己的缓存实现.
访问 Cache API
缓存 API 由play.api.cache.Cache对象提供. 它需要注册一个缓存插件.注: Cache API 尽力保持自身最小化,而允许插入多种实现. 如果你需要一个更具体的 API, 那就通过你自己的缓存插件来使用它.
Unmi 注: EhCachePlugin 的注册方式可以查看 play_x.x.x.jar(比如 $PLAY_HOME/repository/local/play/play_2.9.1/2.0.4/jars/play_2.9.1.jar) 包中的 play.plugins 中的内容:1100:play.api.i18n.MessagesPlugin 2200:play.api.db.BoneCPPlugin 3300:play.db.ebean.EbeanPlugin 4400:play.db.jpa.JPAPlugin 5500:play.api.db.evolutions.EvolutionsPlugin 6600:play.api.cache.EhCachePlugin 71000:play.api.libs.concurrent.AkkaPlugin 810000:play.api.GlobalPlugin
这是 Play2.0.4 默认注册的插件,其中就包含了 600:play.api.cache.EhCachePlugin 插件。 Read More
Unmi 注: 当你采用 TDD 进行开发过一段时间后,很快你就会对 TDD 产生依恋了。没直正去实践过 TDD,对于测试先行的提法只会觉得是一种理想状态。其实不然,从此开发模式变成 测试->实现->重构,同时也指导你的设计,基础架构并不需要那么稳定,它总在应需而变。所以 TDD 让你不该总在项目中后期抱怨架构设计不好之类的事,因为主动权一直在你。废话一堆后就是:测试真的很重要,尽快进入角色吧。
测试你的应用程序
测试源代码文件必须放置在你的应用的test目录下. 你可以在 Play 控制台下用test和test-only任务来运行它们.
使用 specs2
测试一个 Play 2 应用默认的方式是采用 specs2.
单元规格须继承自org.specs2.mutable.Specification特质并应用 should/in 的格式: Read More
概述
推荐的处理 JSON 的方式是使用 Play 基于 JSON 库的类型类, 位置在play.api.libs.json.
这个库是构建于 Jerkson, 之上的,它又是基于 Java 的超快的 JSON 库 Jackson 的 Scala 封闭。
Unmi 注:在 Play 1.x 所用的 JSON 库是 Gson,而 Play 2.0 后更换成了 Jackson。还得 Play 2.0 是基于 SBT 构建的,所以 Play 2.0 的所有的 jar 都是在 $PLAY_HOME/repository/local 目录中。
这样做的好处是无论是 Java 还是 Scala 的 Play 应用依赖了相同的底层库 (Jackson), 同时 Scala 用户可以享受到 Play’s JSON 所带来的额外的类型安全性.play.api.libs.json包含有七种 JSON 数据类型:JsObjectJsNullJsUndefinedJsBooleanJsNumberJsArrayJsString
上面的类型都继承自通用的 JSON 值类型,JsValue. Read More- 模板引擎
模板, 实际作为简单函数存在的, 它可以任何你希望的方式被组合应用. 下面是一些通用场景的使用案例.
布局
我们来声明一个views/main.scala.html模板来用作主布局模板:1@(title: String)(content: Html) 2<!DOCTYPE html> 3<html> 4 <head> 5 <title>@title</title> 6 </head> 7 <body> 8 <section class="content">@content</section> 9 </body> 10</html>
正如你所看到的, 这个模板有两个参数: 一个标题和一个 HTML 内容块. 现在我们可在另一个模板views/Application/index.scala.html中用它: Read More- 模板引擎
Unmi 注:因为是 Web 框架,所以展示层必不可少,也就是接下来两章,我们进入到 Play2.0 中的模板引擎的世界,不同与Play 1.x 让你眼花缭乱的 ${}, #{}, @{}, @@{}, &{}, %{}% 和 {} 如此众多的标签样式,而在 Play 2.0 中只有一个魔幻的 @ 符号。这就叫化繁为简,Play 1.x 的模板是基于 Groovy 的,而 Play 2.0 是基于 Scala 的,它在效率上也改善不少。
基于 Scala 的类型安全的模板引擎
Play 2.0 带来了崭新而真正强大的基于 Scala 的模板引擎. 这一新引擎的设计灵感来自于 ASP.NET 的 Razor. 具体表现在:- 简洁, 富有表现力, 且流畅: 它最小化了一个文件所需的字符和按键的数量, 并且开启了一个快速而流畅的代码流. 不像多数的模板语法, 你不必中断你的代码去显式的告诉你的 HTML 说这儿有一个服务端代码块. 解析器足够的聪明,能依据你的代码进行推断(Unmi 注: 推断出哪块代码应该由服务端来执行). 这使得简洁而富有表现力的语法显得更干净, 并且输入变得快速而有乐趣.
- 易学: 源于其最小化的概念,而让你快速而富有成效的掌握它. 只需用到你现有的 Scala 语言和 HTML 知识.
- 并非新的语言: 我们尽量选择不去创建一门新语言. 相应的,我们希望能让开发者使用它们现有的 Scala 语言技能。也就是要在选择你自己语言的情况下,提供一套模板标记语法,从而让你书写出令人敬畏的 HTML 结构流.
- 可用任何文本编辑器: 无须特别的工具,在任何纯文本编辑器中都能保持高效. Read More
- 本章介绍几种定义通用 Action 功能的方法.
基本的 Action 组合
我们首先从一个简单的日志装饰器(logging decorator) 开始: 我们想要记录下当前 Action 每次被调用的日志.
我们不直接就定义自己的 Action, 而是首先提供一个用于创建标准 Action 的帮助方法:1def LoggingAction(f: Request[AnyContent] => Result): Action[AnyContent] = { 2 Action { request => 3 Logger.info("Calling action") 4 f(request) 5 } 6}
接着你可以这么来使用: Read More - 什么是 Body 解析器?
HTTP PUT 或 POST 请求含有一个请求体(Body). 请求体可以使用任何格式, 只要在请求头中指定相应的Content-Type即可. 在 Play 中, 一个 Body 解析器 转换请求体为对应的 Scala 值.
然而,HTTP 请求体可能非常的大,这时候 Body 解析器 不可能在解析之前光等着把数据全部加载到内存.BodyParser[A]是个基本的Iteratee[Array[Byte],A], 这就是说它一块一块的接收数据 (只要 Web 浏览器在上传数据) 并计算出类型为 A 的值作为结果.
让我们考虑一下几个例子.- 一个文本型 Body 解析器能够把逐块的字节数据连缀成一个字符串, 并把计算得到的字符串作为结果 (
Iteratee[Array[Byte],String]). - 一个文件型 Body 解析器能够把逐块的字节数据存为一个本地文件, 并以
java.io.File引用作为结果 (Iteratee[Array[Byte],File]). - 一个 s3 型 Body 解析器能够把逐块的字节数据推送给 Amazon S3 并以 S3 对象 ID 作为结果 (
Iteratee[Array[Byte],S3ObjectId]). Read More
- 一个文本型 Body 解析器能够把逐块的字节数据连缀成一个字符串, 并把计算得到的字符串作为结果 (