我正在开发一个 RESTful 接口(interface),用于为 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/下,因此/rs/sample/1 指向 ID 为 1 的 SampleDomain 对象
当我使用自定义 json 编码器(GET on/rs/sample/1)呈现资源时,我得到以下数据:
{
"someString" : "somevalue1",
"nest2" : {
"someField" : "someothervalue"
}
}
这正是我想要的。
现在问题来了:我尝试通过 PUT 将相同的数据发送到资源/rs/sample/1。
为了将 json 数据绑定(bind)到域对象,处理请求的 Controller 调用 def domain = SampleDomain.get(id) 和 domain.properties = data where data是未编码的对象。
“someString”字段的绑定(bind)工作正常,但嵌套对象未使用嵌套数据填充,因此我收到一个错误,即属性“nest2”为空,这是不允许的。
我已经尝试实现自定义 PropertyEditorSupport 以及 StructuredPropertyEditor 并为该类注册编辑器。
奇怪的是,只有在我提供非嵌套值时才会调用编辑器。因此,当我通过 PUT 将以下内容发送到服务器时(这没有任何意义;))
{
"someString" : "somevalue1",
"nest2" : "test"
}
至少调用了属性编辑器。
我查看了 GrailsDataBinder 的代码。我发现通过指定关联的路径而不是提供 map 来设置关联的属性似乎可以工作,因此以下内容也可以:
{
"someString" : "somevalue1",
"nest2.somefield" : "someothervalue"
}
但这对我没有帮助,因为我不想实现自定义 JavaScript 到 JSON 对象序列化器。
是否可以通过嵌套映射来使用 Grails 数据绑定(bind)?还是我真的要为每个域类手动实现它?
非常感谢,
马丁
最佳答案
由于这个问题被多次投票,我想分享一下我最后做了什么:
因为我有更多的要求要实现,比如安全等。我实现了一个服务层,它对 Controller 隐藏域对象。我介绍了一个“动态 DTO 层”,它将域对象转换为 Groovy 映射,可以使用标准序列化程序轻松序列化,并手动实现更新。我尝试实现的所有基于半自动/元编程/命令模式/...的解决方案在某些时候都失败了,主要是导致奇怪的 GORM 错误或大量配置代码(以及很多挫败感)。 DTO 的更新和序列化方法相当简单,可以非常快速地实现。它也不会引入大量重复代码,因为如果您不想发布内部域对象结构,则无论如何都必须指定域对象的序列化方式。也许这不是最优雅的解决方案,但它是唯一真正对我有用的解决方案。它还允许我实现批量更新,因为更新逻辑不再连接到 http 请求。
但是我必须说,我不认为 grails 是最适合此类应用程序的适当技术堆栈,因为它使您的应用程序非常笨重且不灵活。我的经验是,一旦你开始做框架默认不支持的事情,它就会开始变得困惑。此外,我不喜欢 grails 中的“存储库”层本质上仅作为域对象的一部分存在,这会带来很多问题并导致多个“代理服务”模拟存储库层。如果您开始使用 json REST 接口(interface)构建应用程序,我建议您选择像 node.js 这样非常轻量级的技术,或者,如果您想/必须坚持使用基于 java 的堆栈,请使用标准 spring 框架 + spring mvc + spring data 带有一个漂亮而干净的 dto 层(这是我迁移到的,它就像一个魅力)。您不必编写大量样板代码,您可以完全控制实际发生的事情。此外,您可以获得强大的类型,从而提高开发人员的生产力和可维护性,并使额外的 LOC 合法化。当然,强大的类型意味着强大的工具!
我开始写一篇博客文章来描述我提出的架构(当然还有一个示例项目),但是我现在没有太多时间来完成它。完成后,我将在此处链接到它以供引用。
希望这可以为遇到类似问题的人提供启发。
干杯!
关于json - 将 JSON 绑定(bind)到嵌套的 Grails 域对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7527331/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib
这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调