- 原来 Java 项目中用的 JSON 组件库主要是 Gson 和 json-lib,Gson 算是很错的库,json-lib 略显寒碜。好啦,最近 Play 2.x 中弃用了 Gson 而采纳了 Jackson,所以现在就来打探一下 Jackson,踩个点吧。
Jackson 号称非常高的性能,听说比另两位兄弟 Gson 和 json-lib 高出一大截,我没有亲测,可是有心人做了,看这个链接 两款JSON类库Jackson与JSON-lib的性能对比(新增第三款测试) 中的数据。2010 年 8 月份的测试结果,不知现在随着版本的变更是否仍然保持着这种悬殊。
通常我会在把文章开头塞丰满,做足前戏,并不是因为在天涯混习惯了的缘故,况且我在天涯总是讷于言的; 在这里,自己的地盘自己作主,不会有要求码足多少字才能发表的自虐性需求,仅仅是让本文在主页上显示时的的概要不空洞而已,可以简单粗暴的称之为废话。
了了,先了解 Jacson 最贴近实际应用场景的应用,即 Jackson 怎么把一个 Java 生成对应的 JSON 字符串,看看前面的文字有这么多了,直接上一段代码吧,而后再慢慢假设与分解: Read More 在 Scala 2.10.0 之前类型的隐式转换必须通过隐式方法来完成,现在的 Scala 可以用 implicit class 来声明类, 并且它的主构造器 (Primary Constructor) 只有一个参数时,就可以用来把参数隐式转换成该类型。
能理解上面什么意思,知道怎么用隐式类吗? 就上面那句话,我自己都不知道在说什么。
首先要知道 Scala 先前是怎么依据隐式方法进行类型的隐式转换,其次又何谓主构造器呢? 关于 Scala 2.10.0 的 implicit class, 官方的解释在这里 http://docs.scala-lang.org/sips/pending/implicit-classes.html 再多说只能让大家更摸不到头,实例演示是王道:
- 应用全局设置
全局对象
在你的项目中定义一个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- Unmi 注: 有了前面对 Play 2.0 的 Json 支持的了解。见:1. Play 2.0 中文资料 - Play JSON 库,2. Play 2.0 中文资料 - 处理和响应 JSON 请求, 3. Play 2.0 中文资料 - Play JSON 库使用泛型。现在来看 Play 2.0 对 XML 的支持就更简单了,原因是 Scala 使用 Json 还需依赖于第三方的库 Jackson,而 Scala 对 XML 的支持直接利益于它的内建语法。如在 Scala 控制台下:
上面演示了 Scala XML 遍历 XML,访问属性,文本节点。方法和遍历 JSON 类似,也有 \ 和 \\ 方法。例如 user\"@name" 访问 name 属性。
而且有了 Scala 这样的内建语法,想要实现 toXML, fromXML 方法也很简单。
处理 XML 请求
XML 请求是指请求体为一个有效的 XML 数据的 HTTP 请求. 必须用Content-Type头指定 MIME 类型为text/xml. Read More
概述
当使用基于 JSON 库的 typeclass(Unmi: typeclass 还没摸准翻译成什么词较合适,此前译作 类型类,觉得有点不妥,所以暂时保留原样) 时,可能会把泛型支持包含进这些 typeclass 中来. 针对基于终端控制查询参数,使用基本的结构作为查询结果的 REST API 来说可能是一个很好的应用方式.
Scala 对泛型的支持
给定如下基本的结构作为搜索结果:1case class SearchResults[T]( 2 elements: List[T], 3 page: Int, 4 pageSize: Int, 5 total :Int 6)
Unmi 注: 上面 case class 涉及到了 Scala 的样本类的特性,Scala 会给这个类自动添加一些句法:1)添加与类名一致的工厂方法,2)参数列表中的所有参数前隐式获得了 val 前缀,即会由相应的的实例变量保持状态,3)自动添加了 toString, hashCode, 和 equals 方法。 Read More
处理 JSON 请求
JSON 请求是一个以有效的 JSON 数据作为请求体的 HTTP 请求. 它必须指定Content-Type头为text/json或是application/json作为 mime 类型.
默认的,Action使用 any content 作为 Body 解析器, 这让你接收 Body 并解析为 JSON (实际为JsValue):1def sayHello = Action { request => 2 request.body.asJson.map { json => 3 (json \ "name").asOpt[String].map { name => 4 Ok("Hello " + name) 5 }.getOrElse { 6 BadRequest("Missing parameter [name]") 7 } 8 }.getOrElse { 9 BadRequest("Expecting Json data") 10 } 11}
更好的(也是更简单的)办法是指定你自己的BodyParser用以告诉 Play 把类容 Body 直接解析为 JSON: Read More