将实数值绑定到Grails域属性(由Dojo小部件发送的值)

Binding real number values to Grails domain attributes (values sent by Dojo widgets)

本文关键字:小部 Dojo 绑定 实数 Grails 属性      更新时间:2023-09-26

我使用Dojo 1.9和Grails 2.3.9。

Dojo NumberTextBox小部件-我在我的表单中使用-以固定格式(JavaScript基础格式)将实数值(例如:12.56)设置到HTML表单输入字段中(但根据浏览器区域设置显示/编辑它们,因此用户总是看到正确格式化的数字)。

另一方面,Grails期望输入字段根据浏览器的语言环境进行格式化。

这会导致转换不匹配,结果是当浏览器语言环境不是英语时,Grails会丢失小数点,并错误地将记录保存到数据库中。

我试图通过实现一个自定义ValueConverter并在应用程序上下文中注册它来覆盖Grails中的值转换。

浏览器发送的请求包含正确的真实值("12.45")

主要问题是我的转换器似乎根本没有被使用。

如何注册它以覆盖默认的Double数据转换?


converter:

package gefc.dojo.binding
import org.grails.databinding.converters.ValueConverter
import java.text.NumberFormat
/**
 * Converter which allows that the doubles arrive 
 */
class DojoDoubleValueConverter implements ValueConverter {
  NumberFormat fmt
  DojoDoubleValueConverter() {
    // The number format sent by Dojo components
    // English locale for the decimal separator
    fmt = NumberFormat.getInstance(Locale.ENGLISH);
    // no grouping
    fmt.setGroupingUsed(false);
  }
  boolean canConvert(value) { value instanceof String }
  def convert(value) {
    Number n = fmt.parse(value)
    return n.doubleValue()
  }
  Class<?> getTargetType() {
    return Double.class
  }
}

我在应用程序上下文中的注册(resources.groovy)

beans = {
  // Dojo components send real values in a fixed, ISO format, while Grails
  // expects them to be formatted according to client/browser locale
  // So we need to override real value conversions
  doubleConverter gefc.dojo.binding.DojoDoubleValueConverter
}

此问题在Grails 2.4+中修复

我在Grails 2.3.8的Long和Integer转换器中遇到了类似的问题。Grails使用LocaleAwareNumberConverter将"123abc"这样的字符串转换为"123"。因此,我定义了自己的转换器,并在resources.groovy

中重写bean定义。
beans = {
    "defaultGrailsjava.lang.LongConverter"(LongValueConverter)
    "defaultGrailsjava.lang.IntegerConverter"(IntegerValueConverter) 
}
class LongValueConverter implements ValueConverter {

    public LongValueConverter() {
    }
    boolean canConvert(value) {
        value instanceof String
    }
    def convert(value) {
        return value?.toLong()
    }
    Class<?> getTargetType() {
        return Long.class
    }
}

我终于找到解决办法了。

主要问题是,转换器bean的命名是错误的。处理double/double的两个转换器必须按以下方式调用(在applicationContext中):

  • "defaultGrailsdoubleConverter" (for double)
  • defaultGrailsjava.lang
  • "。"Double econverter"

这有点令人困惑,因为"defaultDateConverter"是以一种更简单的方式命名的,我认为双转换器命名将与此一致。

第二个问题是,如果你想从插件(而不是应用程序项目)中覆盖这些,那么你必须从yourgrailplugin . dowithspring()中进行注册。Groovy不会打包在插件中。如果您想从应用程序项目本身进行覆盖,那么将它们放在资源中。Groovy很好。

你可能还想确保这个注册发生在DataBinding插件初始化之后,否则你的插件可能会先初始化,而DataBinding插件只是用默认值覆盖你的转换器注册。这可以通过宣布对yourgrailplugin .groovy中的DataBinding插件的软依赖来实现:

    def loadAfter = ['dataBinding']