Play2 自定义模板类型 (Java&Scala)
Play2 默认支持的模板类型是 html, txt, xml 和 js,不在这些支持之列的模板文件即使放到 app/views 目录中,也不会被编译的。如果要支持自定义的模板类型就要些定制了,这比 Play1 复杂些。模板的定制包括在 Build.scala 或 build.sbt 中加上 templatesTypes 配置,并需创建 BufferedContent 和 Format 实现类。下面以增加 json 模板类型为例,兼顾 Scala 和 Java 的实现类,是基于 Play2.2 的,在 Play2.3 中又略有不同。
官方有相关的文档,参考:Custom formats on Scala, Custom formats on Java 和 模板定义参考.
在较新一些的 2.2 的 PlaySettings 中,可以看到
弄清了上面的原理后,开始我们的步骤
第一步:修改项目构建文件
在构建文件 build.sbt 或 Build.scala 中增加下面的内容作为项目的 setting
Build.scala 中要加到下面的位置上
第二步:实现 Json 和 JsonFormat 类
和相应的实现类,前面说过需要两个类型
开始例子,可以选择下面的某一种实现方:
1. Scala 实现自定义 JSON template
Scala 的 Json 和 JsonFormat 类/对象 可以写在同一个文件中,比如说 JsonTemplate.scala 文件,内容如下:
2. Java 实现自定义 JSON template
Java 的实现则需要把 Json 和 JsonFormat 分到两个文件中去,因为它们必须都是 public 的,分别是
Json.java
JsonFormat.java
至此,自定义部分已经完成,开始应用 Json 模板了。
1. 书写 json 模板文件
模板文件必须以
假设在 models 包中已创建了 User(name: String) 类,如果 User 不在 models 包中就得写全路径,如 @(user: models.some.User),也可以在构建文件中用 templatesImport 加上默认引入包。
这时候一切正常的话,Play2 将为你生成源文件 target/scala-2.10/src_managed/main/views/json/user/userlist.template.scala 文件
2. 应用模板,在 controller 中渲染模板
如果你的 controller 是返回的
即使没有现成 F.Promise<User>,我们也可以 F.Promise.<String>pure("") 一个出来再 map。
这样可以想见模板中将要显示的内容。
附加内容, 可另立主题:view template 中调用外部 Java/Scala 方法
view template 的默认行为会把 null 显示为空字符串,这不是我们想要的,所以可以在模板中调用 Java/Scala 方法使用 Jackson 的手段来显示对象或对象属性
做法如下
1. JsonFormat 中稍作改动
把 escape 方法改成如下,此处不进行字符串转义,把任务交给后端代码去做
2. 创建 views/json/Helper 文件
3. 修改项目构建文件
4. 模板文件
上面完全是调用 Jackson 来输出 json 格式,所以字符串的双引号也省了,最终输出是
引入了 @jsonValue() 方法后,JSON 输出格式变得不可控制了,我们可以在 controller 中把 view 模板的输出重新美化成规整的 JSON 字符串。此是后话,非必要,随便便弄个浏览器就可以格式的很漂亮。
参考:
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
官方有相关的文档,参考:Custom formats on Scala, Custom formats on Java 和 模板定义参考.
在较新一些的 2.2 的 PlaySettings 中,可以看到
1templatesTypes := Map(
2 "html" -> "play.api.templates.HtmlFormat",
3 "txt" -> "play.api.templates.TxtFormat",
4 "xml" -> "play.api.templates.XmlFormat",
5 "js" -> "play.api.templates.JavaScriptFormat"
6)弄清了上面的原理后,开始我们的步骤
第一步:修改项目构建文件
在构建文件 build.sbt 或 Build.scala 中增加下面的内容作为项目的 setting
1templatesTypes += ("json" -> "utilities.templates.JsonFormat") //这是针对 Scala 写的 JsonFormat
2
3//templatesTypes += ("json" -> "utilities.templates.JsonFormat.instance") // Java 的 JsonFormat 还要加上 instance 静态属性, 下有具体例子Build.scala 中要加到下面的位置上
1val main = play.Project(......)
2 .settings(
3 templatesTypes += ("json" -> "utilities.templates.JsonFormat.instance"),
4 )第二步:实现 Json 和 JsonFormat 类
和相应的实现类,前面说过需要两个类型
class Json extends BufferedContent 和 class JsonFormat implements Format, 实现各自接口中要求的方法和指定 Content-Type 为 application/json, Format 的 escape() 方法是 view 模板中默认被调用的,比如需要字符串的双引号转议等。开始例子,可以选择下面的某一种实现方:
1. Scala 实现自定义 JSON template
Scala 的 Json 和 JsonFormat 类/对象 可以写在同一个文件中,比如说 JsonTemplate.scala 文件,内容如下:
1package utilities
2
3import org.apache.commons.lang.StringEscapeUtils
4import play.api.http.MimeTypes
5import play.api.templates.BufferedContent
6import play.templates.Format
7
8
9class Json(buffer: StringBuilder) extends BufferedContent[Json](buffer) {
10 val contentType = MimeTypes.JSON
11}
12
13object Json {
14
15 def apply(text: String): Json = {
16 new Json(new StringBuilder(text))
17 }
18
19 def empty: Json = new Json(new StringBuilder)
20}
21
22object JsonFormat extends Format[Json] {
23
24 def raw(text: String): Json = Json(text)
25
26 def escape(text: String): Json = Json(StringEscapeUtils.escapeJava(text))
27}2. Java 实现自定义 JSON template
Java 的实现则需要把 Json 和 JsonFormat 分到两个文件中去,因为它们必须都是 public 的,分别是
Json.java
1package utilities;
2
3import play.api.templates.BufferedContent;
4
5public class Json extends BufferedContent<Json> {
6
7 public Json(scala.collection.mutable.StringBuilder buffer) {
8 super(buffer);
9 }
10
11 public String contentType() {
12 return "application/json";
13 }
14}JsonFormat.java
1package utilities;
2
3import org.apache.commons.lang.StringEscapeUtils;
4
5import play.templates.Format;
6import scala.collection.mutable.StringBuilder;
7
8public class JsonFormat implements Format<Json> {
9
10 public Json raw(String text) {
11 return new Json(new StringBuilder(text));
12 }
13
14 public Json escape(String text) {
15 return new Json(new StringBuilder(StringEscapeUtils.escapeJava(text)));
16 }
17
18 public static final JsonFormat instance = new JsonFormat(); //对于 Java 版本需要这个静态实例
19}至此,自定义部分已经完成,开始应用 Json 模板了。
1. 书写 json 模板文件
模板文件必须以
.scala.json 结尾,比如创建文件 views/user/userlist.scala.json1@(user: User)
2{
3 "Username": "ruser.name",
4}假设在 models 包中已创建了 User(name: String) 类,如果 User 不在 models 包中就得写全路径,如 @(user: models.some.User),也可以在构建文件中用 templatesImport 加上默认引入包。
这时候一切正常的话,Play2 将为你生成源文件 target/scala-2.10/src_managed/main/views/json/user/userlist.template.scala 文件
2. 应用模板,在 controller 中渲染模板
1return ok((Json)views.json.user.userlist.render(user));如果你的 controller 是返回的
1public static F.Promise<Result> index() {
2 F.Promise<User> usersPromise = UserService.fetchAll();
3 return usersPromise.map(new F.Function<User, Result>() {
4 @Override
5 public Result apply(User user) throws Throwable {
6 return ok((Json)views.json.user.userlist.render(user));
7 }
8 });
9}即使没有现成 F.Promise<User>,我们也可以 F.Promise.<String>pure("") 一个出来再 map。
这样可以想见模板中将要显示的内容。
附加内容, 可另立主题:view template 中调用外部 Java/Scala 方法
view template 的默认行为会把 null 显示为空字符串,这不是我们想要的,所以可以在模板中调用 Java/Scala 方法使用 Jackson 的手段来显示对象或对象属性
做法如下
1. JsonFormat 中稍作改动
把 escape 方法改成如下,此处不进行字符串转义,把任务交给后端代码去做
1public Json escape(String text) {
2 return new Json(text);
3}2. 创建 views/json/Helper 文件
1package views.json;
2
3import com.fasterxml.jackson.core.JsonProcessingException;
4import com.fasterxml.jackson.databind.ObjectMapper;
5
6public class Helper {
7
8 private static ObjectMapper jsonSerializer = new ObjectMapper();
9
10 public static String jsonValue(Object data) throws JsonProcessingException {
11 return jsonSerializer.writeValueAsString(data);
12 }
13}3. 修改项目构建文件
1//模板默认引入了 models 下的类,下面同时引入了 models.some 包下的类,可以在编译出的模板源文件中看到相应引入
2templatesImport ++= Seq("views.json.Helper._", "models.some._") //默认再引入 views.json.Helper._ 到模板文件中,书写更方4. 模板文件
1@(user: User)
2{
3 "User": @jsonValue(user),
4 "Username": @jsonValue(user.name)
5}上面完全是调用 Jackson 来输出 json 格式,所以字符串的双引号也省了,最终输出是
1{
2 "User": {"name": "Unmi"},
3 "Username": "Unmi"
4}引入了 @jsonValue() 方法后,JSON 输出格式变得不可控制了,我们可以在 controller 中把 view 模板的输出重新美化成规整的 JSON 字符串。此是后话,非必要,随便便弄个浏览器就可以格式的很漂亮。
参考:
- https://searchcode.com/?q=play.api.templates.TxtFormat
- https://groups.google.com/forum/#!topic/play-framework/JKic1yVzgY0
- https://github.com/playframework/playframework/blob/2.2.x/framework/src/play/src/main/scala/play/api/templates/Templates.scala
- https://searchcode.com/codesearch/view/64071723/#l-217
- https://searchcode.com/codesearch/view/2451189/#l-210
- https://searchcode.com/codesearch/view/2451189/
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。