【问题标题】:Grails Command Object binding failing for a Map of Lists列表映射的 Grails 命令对象绑定失败
【发布时间】:2015-01-07 06:58:20
【问题描述】:

(Grails 版本:2.3.11,Groovy 版本:2.2.2)

我是 Groovy 和 Grails 的新手,所以如果我遗漏了一些明显的东西,请原谅我。我有一个包含 Map 的命令对象,键是整数(尽管我尝试过字符串,但它们也不起作用),值是 Details 对象的列表:

class Details {
  Integer volume
  Double price
}
class TheCommand {
  Map<Integer, List<Details>> details = [:].withDefault { [].withLazyDefault { new Details() } }
  String location
}

我的 GSP 中有这个:

<g:form controller="mapOfLists" action="create">
  <g:textField name="location" size="7"/>
    <table>
      <g:each in="${(1..24)}" var="hour">
        <tr>
          <td>${hour}</td>
          <g:each in="${(0..4)}" var="column">
            <td><g:textField name="details[${hour}][${column}].price" size="4"/></td>
            <td><g:textField name="details[${hour}][${column}].volume" size="3"/></td>
          </g:each>
        </tr>
      </g:each>
    </table>
  <g:submitButton name="Submit" value="Submit"/>
</g:form>

以及行动:

// trying the different binding approaches, none work
def create(TheCommand theCommand) {
  // theCommand.hasErrors() -> false
  // at this point theCommand's details is an empty map, I can see the details[x][y] values in the params object
  bindData(theCommand, params)
  // the bindData above didn't work, details is still an empty map
  theCommand.properties['details'] = params
  // the setting via properties above didn't work, details is still an empty map
}

两个问题: 1)关于尝试什么的任何想法?我已经看到有一种使用自定义活页夹的方法,但这似乎是 grails 应该处理的情况,所以我在走这条路之前先试一试。

2) 是否有更强大的数据绑定器?我已经浏览了相关的 SimpleDataBinder 代码,它似乎只支持单索引属性

非常感谢, 赛斯

【问题讨论】:

    标签: grails


    【解决方案1】:

    如果不使用自定义活页夹,我无法让它工作:(

    至于更强大的数据绑定器,@BindUsing 允许您定义一个闭包或实现BindingHelper 接口以将您的输入格式化为您需要的任何内容。您甚至可以在其中使用 GORM 查找器来使用域实例填充属性。

    我设法得到了这么多:

    class TheCommand {
        @BindUsing({ obj, source ->
            def details = new HashMap<Integer, List<Details>>().withDefault { [].withLazyDefault { new Details() } }
            source['details']?.collect { mapKey, mapValue ->
                if (mapKey.integer) {
                    mapValue.collect { arrayKey, arrayValue ->
                        if (arrayKey.integer) {
                            def detailsObj = new Details(volume:new Integer(arrayValue.volume), price: new Double(arrayValue.price))
                            details[new Integer(mapKey)].add(new Integer(arrayKey), detailsObj)
                        }
                    }
                }
            }
            return details
        })
        Map<Integer, List<Details>> details
    
        String location
    }
    

    它适用于以下请求curl http://localhost:8080/test/test/index --data "location=here&amp;details.0.0.volume=20&amp;details.0.0.price=2.2&amp;details.0.1.volume=30&amp;details.0.1.price=2"

    它很强大,但很丑(虽然我的代码有一些可以更好地实现的部分)。我不知道为什么一个简单的new Details(arrayValue) 在那里不起作用,但我可能遗漏了一些明显的东西。

    【讨论】:

    • 非常感谢格雷戈尔!我没有听说过BindUsing。我将使用您提供的 sn-p,并且可能会尝试自定义活页夹,因为我是新手并正在努力学习。再次感谢您抽出宝贵时间。
    猜你喜欢
    • 1970-01-01
    • 2012-03-31
    • 2015-12-12
    • 2011-08-06
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多