涉及到页面显示的问题,用自定义标签总能够能事不少,即使是最原始的自定义 JSP 标签也有人乐此不疲,进化到 Play 中的自定义标签数得上很轻量级的实现,简单的只需要一小页文档 The template engine 就足矣。
概括起来 Play1 支持三种方式自定义标签: HTML 文件方式
, 自定义 FastTags
, Java 对象扩展方法
. 前二者为面向过程的方式,第三种方式为面向对象的方式,是在往某种数据类型追加一个方法。
确切的说针对 Java 对象的方法的扩展并不能称之为自定义标签。
一个这样的场景,股票价格变化值要显示在页面上,根据正,负,零,再加上不同的区域四种条件分别显示为不同的颜色,比如美国分别为绿色,红色和黑色(注: 美国股市显示的颜色正好与中国相反)。假设 priceChange 是 Integer 类型,我们就可以定义对 Integer 对象的扩展,所在类必须继承自 JavaExtensions 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package utilities; import groovy.lang.Closure; import java.io.PrintWriter; import java.util.Map; import play.templates.JavaExtensions; import play.templates.GroovyTemplate.ExecutableTemplate; public class PlayTagExtensions extends JavaExtensions { public static String showFor(Integer priceChange, String region) { String color = "black"; if(priceChange > 0){ color = "US".equals(region) ? "green" : "red"; }else if(priceChange < 0){ color = "US".equals(region) ? "red" : "green"; } return "<span style='color:"+color+"'>" + priceChange + "</span>"; } } |
Play1 中的模板是用的是 Groovy 模板,看到后面用 ${obj.abc()} 格式来调用就知道,FastTags 是用 #{abc} 这样的形式。
以上 showFor() 函数第一个参数的类型表示是对 Integer 类型进行扩展,相当于 Integer 类型拥有了 showFor(String region) 这么个方法,其余参数才是使用标签方法时的参数列表,这里除 region 外还可以有更多。方法返回的字符串就是要在页面上输出的内容。
注:这里不能声明为 showFor(int priceChange, String region),否则会提示
Exception raised was MissingMethodException : No signature of method: java.lang.Integer.showFor() is applicable for argument types: (java.lang.String) values: [US] Possible solutions: power(java.lang.Number), power(java.lang.Integer).
我们这是要为对象 Integer 扩展方法,原始类型不能扩展方法,也就是像往集合里放对象一样,调用时只会装箱,不会拆箱。
使用方法,创建了上面的类及方法,无需作任何的配置操作,Play 就知道找到来用。
假设在 Controller 中是这样渲染模板的
int priceChange = 10; // Integer priceChange = 10; 在 viewTemplate 中会装箱为 Integer
String region = "US";
renderTemplate("abc.html", priceChange, region);
在 abc.html 页面中就可以这么使用自定义的标签了
${priceChange.showFor('US').raw()}
到浏览器中输出的源文件就会是
<span style='color:green'>10</span>
防止直接显示 HTML 源代码除了上面 .raw() 也可以用
#{verbatim}
${priceChange.showFor('US')
#{/verbatim}
Java 对象扩展方法中只要第一个参数匹配的类型就被扩展了该方法,各级属性也行,如
${stock.priceChangePercentage.showFor('CN').raw()}
${(-25).showFor("US").raw()}
${100.showFor("CN").raw()}
剩下就是自己发挥的问题了。