Play2 中使用自定义的路由器文件 routes

用过 PlayFramework 的都知道默认的路由器文件是 conf/routes,Play2 可以定义自己的 routes 文件。在默认的 application.conf 中有这么一段注释

# Router
# ~~~~~
# Define the Router object to use for this application.
# This router will be looked up first when the application is starting up,
# so make sure this is the entry point.
# Furthermore, it's assumed your route file is named properly.
# So for an application router like conf/my.application.Router,
# you may need to define a router file my.application.routes.
# Default to Routes in the root package (and conf/routes)
# application.router=my.application.Routes

也就是通过 application.router 可以定义自己的 routes 文件。上面的解释很容易把人搞混,问题在于何处是文件路径,何处是类路径,至少写着的 'conf/my.applicaton.Router 就是在混淆视听。对于上面的解释要明白下面几点 阅读全文 >>

Play1 直接调用 Action 方法,不作 302 跳转

用过 PlayFramework 的同学们应该都知道,Action 方法间的调用是进行的  302 重定向操作。

简单例子说明一下,当基于下面的 r1, r2 路由配置时,如果 Application.f1() 方法中调用了 f2() 方法,实际运作是 f1() 在调用 f2() 时,会先反向出 f2() 方法对应的路由  GET /r2,然后向 /r2 发出的一个 302 跳转.

上面也算是绕个弯形成了对 f2() 方法的调用,这也是非常合理,在 Action 中很容易理解的。

GET     /r1                                                                     Application.f1
GET     /r2                                                                    Application.f2
GET     /r3                                                                    Application.f3

为什么说会反向出 f2() 方法对应的路由,可以反证一下。

例如说在 f1() 中调用了一个 public static void f4() 方法,但是 f4() 并未出现在 routes 配置中,也就是 f4() 没有对应的路由配置,我们将会看到这样一个异常 阅读全文 >>

Java 设计之初为何就不让用 == 比较两字符串呢?

Java 的字符串值比较不能用 == 号这个设计不知道最初是怎么考虑的,它最大的贡献无疑是滋生了一个长久未衰的面试题,加之连 Code Review 都可能被忽略掉的 Bug。本来两个字符串用等号相比较是最自然而然的做法,然而它却是要迫使我们相信想当然很可能是错误的那样一个道理。

我一直认为 Java 的字符串比较值不能用 == 而必须用 equals() 方法是个不恰当的设计,这从其他种种语言的现实做法(人家都用 == 比较值)就知道。

猜想一下 Java 为何要这样对待字符串,可能 Java 又想类型全部对象化,同时考虑到方便性,仍然保留了 int, short, boolean 等原始类型,它们是可以用 == 比较值,其他真正的对象类型用 equals() 方法比较也是无可厚非的。这时候夹缝中的字符串却被为难到了,它那么的常用,还常以字面量的面目出现,它更该是个基本类型,而实为对象类型,因此不被认可用 == 直接比较值, 而选择了用 equals() 方法来比较字符串值。

而另一方面,由于字符串是多例的,所以有些情况下又更令人迷惑,比如下面的种种情况 阅读全文 >>

JMockit 如何 mock 异常

2014-07-26 修改本文

后来发现用 JMockit 来 mock 异常根本没有之前文中描述的那么复杂,其实还是在那个 result 上,给它赋个异常实例就轻而易举的解决了,只需如此

原文可不用看下去了。


做过几篇 JMockit 使用 Expectations 来 Mock 方法,私有方法,私有属性的的日志,今天工作上突然有个需求是要 Mock 异常。现在再也不能为了跑个单元测试而去拔下网线了,也不该人为的去制造其他混乱来测试。开始是想能不能用 Expectations 来 Mock 异常,尚未发现相关的属性可以设置,没有类似 result 那样的属性,比如想像中有个 exception/throwable 属性: 阅读全文 >>

初始化 Gradle 工程目录

最近重新在 Eclipse 中打开旧的 Maven 项目,总有些什么错误,备受折磨。期间试手了 Ant+Ivy, 现今试用了下 Gradle,感觉不错,它应该才是我真想要的,Maven 差不多该扔到一边去了。

Gradle 像 sbt 构建工具一样,也不会帮我们生成默认的目录布局,这些要自己来做。这不是什么麻烦事,因为只需做一次,可预先写好初始化脚本,幸好本人已习惯 shell 操作。

假设我们有这样的 build.gradle 文件

apply plugin: 'java'
apply plugin: 'war'    //有这行时我们需要创建 src/main/webapp 目录
apply plugin: 'eclipse'

我们执行 gradle eclipse 后是不会生成src 目录的,工程下的源文件目录是需要自己来生成的。Gradle 参考 Maven 的标准目录布局,即

我们有两种办法初始化目录布局 阅读全文 >>

基于 Groovy 的自动化构建工具 Gradle 入门

本人工作之初没有使用自动化构建,后来敏捷了,开始使用 Ant - 完全面向过程的定义步骤,不进行依赖管理。再发展到 Maven,面向对象的方式管理工程,有了依赖的管理,JAR 包统一从中央仓库获得,保存在本地库。同时产生了 Ivy + Ant,让 Ant 也能管理依赖,不过 JAR 包依赖仓库也是用 Maven 的。

前面都是用 XML 来配置的,虽说 XML 的标签描述性也很强,但阅读性还是有些牵强,并且 Maven 和 Ant+Ivy 都需要 IDE 的支持,比如在 Eclipse 中有专门 Maven Dependenciesivy.xml [*] 中列出项目的依赖包,这里常会出现些问题。

而我今天想尝试使用的是基于 Groovy 的 Gradle,只要一个 build.gradle 文件,实质是一个 groovy 文件,由于可以 DSL,所以 Gradle 比 XML 更写意,更主要的是 Gradle 项目不需要 IDE 的特别支持,见后面的图

先要安装 Gradle,在我的 Mac 系统下我是用 brew install gradle 安装的,不同平台下可能用 yum, apt-get,安装后执行 gradle 命令验证。

接着按以下步骤:

1. 创建项目目录 testgradle,并进入到新创建的目录

mkdir testgradle
cd testgradle 阅读全文 >>

PlayFramework 1 自定义标签 -- FastTags

最早是用 HTML 来自定义标签,现在觉得 HTML 写有关逻辑的代码就有点不伦不类了,HTML 里着重是显示代码。前有一篇 PlayFramework 1 模板应用 -- Java 对象扩展 学习了对 Java 对象扩展的方式,如果不是基于已有对象类型进行方法扩展来进行调用,就可以自定义 FastTags 的方式。

Java 对象扩展的使用是 ${obj.abc()}, FastTags 标签是 #{abc}...${/abc}。

FastTags 标签类继承自 play.templates.FastTags,标签对应方法的原型是

public static void _tagName(Map<?, ?> args, Closure body, PrintWriter out,     ExecutableTemplate template, int fromLine)

这些都是得益约定优于配置,下面来几个例子,分别说明默认参数,命名参数,及多参数,标签体的处理。 阅读全文 >>

PlayFramework 1 模板应用 -- Java 对象扩展

涉及到页面显示的问题,用自定义标签总能够能事不少,即使是最原始的自定义 JSP 标签也有人乐此不疲,进化到  Play 中的自定义标签数得上很轻量级的实现,简单的只需要一小页文档 The template engine 就足矣。

概括起来 Play1 支持三种方式自定义标签: HTML 文件方式, 自定义 FastTags, Java 对象扩展方法. 前二者为面向过程的方式,第三种方式为面向对象的方式,是在往某种数据类型追加一个方法。

确切的说针对 Java 对象的方法的扩展并不能称之为自定义标签。

一个这样的场景,股票价格变化值要显示在页面上,根据正,负,零,再加上不同的区域四种条件分别显示为不同的颜色,比如美国分别为绿色,红色和黑色(注: 美国股市显示的颜色正好与中国相反)。假设 priceChange 是 Integer 类型,我们就可以定义对 Integer 对象的扩展,所在类必须继承自 JavaExtensions 类: 阅读全文 >>

Apache 配置 SSL(HTTPS) 并整合 Tomcat

我们在 Tomcat 中可以开启 SSL,用 HTTPS 来访问,见前一篇 快速启用 Tomcat 的 HTTPS 协议访问,不过更接近实际的应用是 Tomcat 只担当 Servlet 容器,HTTPS 协议部份,甚至是静态页面是交给 Apache 的处理,Apache 与 Tomcat 之间有一个通道。当然前端用 F5 那类负载均衡设备就另当别论了。

这里实践一下怎么开启 Apache 的 HTTPS,并与 Tomcat 进行整合的操作。平台是 Mac OS X, Apache2, Tomat8,其他平台或不同版本的应用软件配置类似。

第一步: 生成自签署证书

安全加密的东西都得证书,我们需要用到 openssl,没有就先安装它,命令是:

openssl req -new -x509 -days 365 -nodes -out server.crt -keyout server.key

上面命令可以指定生成 server.crt 和 server.key 文件的目录,默认产生在当前目录下,假设这两个文件生成在 /etc/apache2 目录下。 阅读全文 >>

PlayFramework 1 输出所有 WS.url() 访问的 URL

记录下这个其实没有多大的意义,新入手 Play 框架的应该直接就是用版本 2 了,只因我们还要系统工作在 Play1 下,所以记下来,估计在 Play2 中已无借鉴作用了。

我们在 Play1 中访问外部 WebService 资源都是用 WS.url(url),然后调用它的 get(), post(), delete() 等相对应的 HTTP 请求方法。我们可以系统中所有通过 WS.url() 访问的 URL, 需找到切面,Play 是在哪里为访问的 URL 创建请求的。

看 WS 类的实现,它是一个 PlayPlugin 插件,其中定义了

private static WSImpl wsImpl = null;

来看 Play 是如何获得 WSImple 实现的,WS 插件的初始化方法中: 阅读全文 >>