我正在开发一个RESTful接口,用于为JavaScript应用程序提供JSON数据。
在服务器端,我使用Grails 1.3.7并使用GORM域对象进行持久化。我实现了一个自定义JSON Marshaller来支持编组嵌套域对象
以下是示例域对象:
class SampleDomain {
static mapping = { nest2 cascade: 'all' }
String someString
SampleDomainNested nest2
}
和
class SampleDomainNested {
String someField
}
SampleDomain资源在URL / rs / sample / so / rs / sample / 1下发布,指向ID为1的SampleDomain对象
当我使用自定义json marshaller(/ rs / sample / 1上的GET)渲染资源时,我得到以下数据:
{
"someString" : "somevalue1",
"nest2" : {
"someField" : "someothervalue"
}
}
这正是我想要的。
现在出现了问题:我尝试通过PUT将相同的数据发送到资源/ rs / sample / 1.
要将json数据绑定到域对象,处理请求的控制器会调用def domain = SampleDomain.get(id)
和domain.properties = data
,其中data是未编组的对象。
“someString”字段的绑定工作得很好,但是嵌套对象没有使用嵌套数据填充,因此我得到一个错误,即属性“nest2”为空,这是不允许的。
我已尝试实现自定义PropertyEditorSupport
以及StructuredPropertyEditor
并注册该类的编辑器。
奇怪的是,当我提供非嵌套值时,编辑器才会被调用。所以当我通过PUT将以下内容发送到服务器时(这没有任何意义;))
{
"someString" : "somevalue1",
"nest2" : "test"
}
至少会调用属性编辑器。
我查看了GrailsDataBinder
的代码。我发现设置关联的属性似乎可以通过指定关联的路径而不是提供地图来工作,所以以下工作原理:
{
"someString" : "somevalue1",
"nest2.somefield" : "someothervalue"
}
但这对我没有帮助,因为我不想为JSON对象序列化器实现自定义JavaScript。
是否可以使用嵌套地图使用Grails数据绑定?或者我是否真的要为每个域类手动实现它?
非常感谢,
马丁
答案 0 :(得分:7)
由于这个问题多次被提出,我想分享我最后所做的事情:
由于我有更多的要求要像安全性等那样实现。我实现了一个服务层,它隐藏了控制器中的域对象。我介绍了一个“动态DTO层”,它将域对象转换为Groovy映射,可以使用标准序列化器轻松序列化并手动实现更新。我尝试实现的所有基于半自动/元编程/命令模式/ ...的解决方案在某些时候都失败了,主要是导致奇怪的GORM错误或许多配置代码(以及很多挫折)。 DTO的更新和序列化方法相当简单,可以非常快速地实现。它不会引入大量重复代码,因为如果您不想发布内部域对象结构,则必须指定域对象的序列化方式。也许这不是最优雅的解决方案,但它是唯一真正适合我的解决方案。它还允许我实现批量更新,因为更新逻辑不再连接到http请求。
但是我必须说,我不认为grails是最适合这种应用的技术堆栈,因为它使你的应用程序非常重量和不透明。我的经验是,一旦你开始做一些默认情况下框架不支持的事情,它就开始变得凌乱。此外,我不喜欢grails中的“repository”层实际上只作为域对象的一部分存在,这引入了许多问题并导致几个“代理服务”模拟存储库层。如果您使用json rest接口开始构建应用程序,我建议您选择像node.js这样的轻量级技术,或者,如果您想/必须坚持使用基于Java的堆栈,请使用标准spring框架+ spring mvc + spring数据有一个漂亮干净的dto层(这是我迁移到的,它就像一个魅力)。您不必编写大量的样板代码,而是完全控制实际发生的事情。此外,您可以获得强大的打字,从而提高开发人员的工作效率和可维护性,并使其他LOC合法化。当然,强力打字意味着强大的工具!
我开始写一篇描述我想出的架构的博客文章(当然是一个示例项目),但是我现在没有很多时间来完成它。当它完成后,我将在这里链接到它以供参考。
希望这可以成为遇到类似问题的人的灵感。
干杯!
答案 1 :(得分:1)
它要求您提供类名:
{ class:"SampleDomain", someString: "abc",
nest2: { class: "SampleDomainNested", someField:"def" }
}
我知道,它产生的输出需要不同的输入。
正如我之前在评论中提到的,你可能最好使用gson库。
答案 2 :(得分:1)
不确定为什么你用xstream编写了自己的json marshaller。
请参阅http://x-stream.github.io/json-tutorial.html
我们对xstream的后端(基于grails)服务非常满意,这样你就可以在xml或json中渲染marshall,或者如果你愿意,可以覆盖特定对象的默认编组。
Jettison似乎生成了一个更紧凑,人性化程度更低的JSON,你可以遇到一些库碰撞的东西,但默认的内部json流渲染器是不错的。
如果您要向公众发布该服务,您将需要花时间为错误等返回适当的HTTP协议响应...($ .02)