先看一个最简单的例子,假如我有这样一个entity
case class Entity(var value: String)
在Servlet的一个请求下,响应一个entity的列表
get("/") {
List(Entity("foo"), Entity("bar"))
}
访问请求我们得到
List(Entity(foo), Entity(bar))
显然前端不习惯于解析这样奇怪的格式,如今的前端JSON已无处不在,如何使用json格式返回呢?
访问scalatra官网,右侧栏Formats下的JSON https://scalatra.org//guides/2.7/formats/json.html
官网建议我们使用json4s,导入json4s-jackson
、scalatra-json
包,然后在Servlet中定义一个隐式延迟常量jsonFormats
protected implicit lazy val jsonFormats: Formats = DefaultFormats
再实现一个ScalatraBase
下的before()
方法
before() {
contentType = formats("json")
}
正常情况下我们就可以得到预期结果了
[{
"value":"foo"},{
"value":"bar"}]
看上去很简单,但是坑并不少,下面盘点一些简单的问题
FAQ
为什么完全没有效果,仍然显示默认的输出,也没有报错?
没有成功导入scalatra-json
包,没有引入scalatra-json
包就不处理jsonFormats
和formats("json")
,所以不会报错,也不会提示你缺少引入,也可能是没有在servlet上with JacksonJsonSupport
如果需要响应的entity并非
case class
呢?
class Entity(var value: String)
get("/") {
new Entity("foo")
}
它的响应结果是Entity@xxx
,不会被自动解析,此时我们需要使用org.json4s.Serialization.write()
get("/") {
Serialization.write(new Entity("foo"))
}
它将响应正确的结果
{
"value":"foo"}
由于Serialization
的api比较简洁,建议将Serialization
整个导入,直接使用write()
import org.json4s.jackson.Serialization._
get("/") {
write(new Entity("foo")
}
- 需要响应的json内容十分灵活,field是动态的,所以我不想为返回的json单独写一个实体类,怎么做比较简单?
可以直接返回JObject
的,scalatra-json
是会自动解析的,所以按json4s的写就好了,可以用JsonDSL
的~
动态组装json
``` scala
import org.json4s.JsonDSL._
get("/") {
("foo" -> "1") ~ ("bar" -> "2")
}
得到
``` json
{"foo":"1","bar":"2"}
- 如何使用jsonp?
在servlet中定义一个
在parameter中加参数jsonp标注回调函数名称,例如http:/localhost/?jsonp=jsonpCallback ,就可以得到override def jsonpCallbackParameterNames = Seq("jsonp")
/**/jsonpCallback({"foo":"1","bar":"2"});
Suggest
建议把servlet看做mvc模式的controller,然后定义一个ControllerBase
,把jsonFormats
定义在里面,然后所有的controller去继承这个ControllerBase
,可以参考这个项目Uniliva/tcc-fatec-back-end-scala,他就是这么做的
如果要对一些类型做特殊处理,诸如date要使用自定义的SimpleDateFormat
之类,建议参考AgreementInput.scala
官方文档涉及的问题凤毛麟角,而且例子代码都有问题,我看到有的例子还在用java.util.Date
,这实在让人看不下去,建议在Stack Overflow和Github直接检索问题代码,关于scalatra的问题只有这两个大社区全面