如何解决Grails命令对象数据绑定
| Grails对将请求参数绑定到域对象及其关联提供了很好的支持。这在很大程度上取决于检测以“ 0”结尾的请求参数,并自动从数据库中加载这些参数。 但是,尚不清楚如何填充命令对象的关联。请看以下示例:class ProductCommand {
String name
Collection<AttributeTypeCommand> attributeTypes
ProductTypeCommand productType
}
该对象与ProductTypeCommand
具有单端关联,与AttributeTypeCommand
具有多端关联。所有属性类型和产品类型的列表可从此接口的实现中获得
interface ProductAdminService {
Collection<AttributeTypeCommand> listAttributeTypes();
Collection<ProductTypeCommand> getProductTypes();
}
我使用此界面在GSP中填充产品和属性类型选择列表。我还将这个接口依赖注入到命令对象中,并使用它来“模拟”命令对象上的“ 5”和“ 6”属性
class ProductCommand {
ProductAdminService productAdminService
String name
List<Integer> attributeTypeIds = []
Integer productTypeId
void setProductType(ProductTypeCommand productType) {
this.productTypeId = productType.id
}
ProductTypeCommand getProductType() {
productAdminService.productTypes.find {it.id == productTypeId}
}
Collection<AttributeTypeCommand> getAttributeTypes() {
attributeTypeIds.collect {id ->
productAdminService.getAttributeType(id)
}
}
void setAttributeTypes(Collection<AttributeTypeCommand> attributeTypes) {
this.attributeTypeIds = attributeTypes.collect {it.id}
}
}
实际上发生的是attributeTypeIds
和productTypeId
属性绑定到相关的请求参数,并且getters / setters“ simulate”productType
和attributeTypes
属性。有没有更简单的方法来填充命令对象的关联?
解决方法
您实际上是否需要具有attributeTypes和productType属性的子命令?您不使用PropertyEditorSupport绑定的任何原因是什么?例如。:
public class ProductTypeEditor extends PropertyEditorSupport
{
ProductAdminService productAdminService // inject somewhow
void setAsText(String s)
{
if (s) value = productAdminService.productTypes.find { it.id == s.toLong() }
}
public String getAsText()
{
value?.id
}
}
(和attributeType对象类似),并在编辑器注册表中注册它们:
import java.beans.PropertyEditorSupport
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry reg) {
reg.registerCustomEditor(ProductType,new ProductTypeEditor())
reg.registerCustomEditor(AttributeType,new AttributeTypeEditor())
}
}
并在您的resources.groovy中注册:
beans =
{
customEditorRegistrar(CustomEditorRegistrar)
}
然后在您的Cmd中,您只有:
class ProductCommand {
String name
List<AttributeType> attributeTypes = []
ProductType productType
}
如果确实需要实际的子命令关联,那么结合PropertyEditorSupport绑定,我可以完成类似于@Andre Steingress所建议的操作:
// parent cmd
import org.apache.commons.collections.ListUtils
import org.apache.commons.collections.FactoryUtils
public class DefineItemConstraintsCmd implements Serializable
{
List allItemConstraints = ListUtils.lazyList([],FactoryUtils.instantiateFactory(ItemConstraintsCmd))
//...
}
// sub cmd
@Validateable
class ItemConstraintsCmd implements Serializable
{
Item item // this has an ItemEditor for binding
//...
}
希望我不会误解您想要实现的目标:)
,我在某些项目中看到的是使用Apache Commons Collections中的Lazy *集合类。它使用如下代码懒惰地初始化命令关联:
class ProductCommand {
String name
String type
List<AttributeTypeCommand> attributes = org.apache.commons.collections.list.LazyList.decorate(new ArrayList(),new org.apache.commons.collections.functors.InstantiateFactory(AttributeTypeCommand.class))
}
class AttributeTypeCommand {
// ...
}
对于上面给出的示例,GSP可以引用关联索引
<g:textField name=\"attributes[0].someProperty\" ...
即使对于不存在的索引,此方法也适用,因为LazyList上的每个get(index)调用都会评估列表在该位置上是否已经有元素,如果没有,列表将自动增大大小并从指定的工厂返回一个新对象。
请注意,您也可以使用LazyMap来创建与惰性地图相似的代码:
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/LazyMap.html
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/list/LazyList.html
更新:
Groovy 2.0(尚未包括在Grails发行版中)将为懒惰和渴望的列表提供嵌入式支持。我写了一篇有关该主题的博客文章:
http://blog.andresteingress.com/2012/06/29/groovy-2-0-love-for-grails-command-objects/
更新:
随着Grails 2.2.0的发布,Groovy 2.0已成为发行版的一部分。
http://blog.andresteingress.com/2012/06/29/groovy-2-0-love-for-grails-command-objects/
,我在使用嵌套命令对象时遇到了同样的问题,因此我做了以下解决方法:
我明确将其他域对象作为参数添加到我的
控制器动作
另外,为嵌套命令对象显式调用bindData()
(通常,包装其他命令对象的命令对象
将成功绑定其数据,而无需绑定它
明确地,这取决于您的视图命名约定)
然后我在这些命令对象上调用.Validate()
使用这些对象使用.hasErrors()检查错误。
要保存您的Domain对象,还应显式分配每个嵌套对象
属性及其相应的命令对象
为了说明这一点,下面是一个示例伪代码:
class CommandObjectBig{
String name
CommandObjectSmall details
static constraints = {
name (blank: false)
}
}
class CommandObjectSmall{
String address
static constraints = {
address (blank: false)
}
}
在控制器中:
.
.
.
def save = { CommandObjectBig cob,CommandObjectSmall cos ->
//assuming cob is bounded successfully by grails,and we only need to handle cos
bindData(cos,params.details)
cos.validate()
//then do you code logic depending on if cos or cob has errors
if(cob.hasErrors() || cos.hasErrors())
render(view: \"create\",model: [bigInstance: cob,smallInstance: cos])
}
else
{
//create the Domain object using your wrapper command object,and assign its details
//property it\'s value using cos command object instance,and call the save on you
//command object and every thing should go smoothly from there
.
.
.
}
.
.
.
希望grails的将来版本能够解决此问题,并且可能允许开发人员添加可选的params或params范围,并将其分配给每个命令对象,这可能很有用:)
,Grails中的命令对象
在Grails中,命令对象就像域类,但不保留数据。在不需要创建域对象的情况下,在Grails中使用命令对象是执行数据绑定和验证的简单方法。
您需要做的第一件事就是描述您的命令对象。最好在包含将使用它的控制器的同一文件中进行操作。如果命令对象将被多个控制器使用,请在groovy源目录中对其进行描述。
声明命令对象
@Validateable
class UserProfileInfoCO {
String name
String addressLine1
String addressLine2
String city
String state
String zip
String contactNo
static constraints = {
name(nullable: false,blank: false)
addressLine1(nullable: true,blank: true)
addressLine2(nullable: true,blank: true)
city(nullable: true,blank: true)
state(nullable: true,blank: true)
zip(nullable: true,blank: true,maxSize: 6,matches: \"[0-9]+\")
contactNo(blank: true,nullable: true)
}
}
使用命令对象
接下来,您可能需要做的是将控制器中的动作接收到的数据绑定到命令对象并进行验证。
def updateUserProfile(UserProfileInfoCO userProfileInfo) {
// data binding and validation
if (!userProfileInfo.hasErrors()) {
//do something
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。