【问题标题】:Grails databinding with decimal delimiter带十进制分隔符的 Grails 数据绑定
【发布时间】:2013-02-14 14:56:54
【问题描述】:

当我在 Double 表单字段上使用带有小数分隔符的 grail 自动数据绑定“例如:Test t = new Test(params)”时遇到问题。经过几次搜索,我发现它与浏览器区域设置有关。

示例: 如果我输入用点“3.45”分隔的小数点数字,则它不起作用(数字的小数部分被忽略)。它在我的数据库中存储 3.0

如果我进行相同的测试,但使用逗号“3,45”作为小数分隔符,则一切正常。 Grails 将 3.45 存储在数据库中。

问题是没有人输入带有逗号分隔符的数字。 (即使设置为 fr_CA 时,小键盘也会输入一个点 '.')

我已经找到了一些解决方案,例如注册自定义数字编辑器(当您有很多应用程序时有点痛苦)或将全局 localeResolver 设置为 en_US(最后一个不起作用,因为我失去了我的所有国际化功能应用程序)。

那么,有人有一个简单的解决方案来解决这个问题吗?

使用: 圣杯:2.2.0 浏览器:谷歌浏览器(语言环境 fr_CA)

非常感谢!

【问题讨论】:

    标签: grails


    【解决方案1】:

    我已经搜索和尝试了 2 天。我最终选择定义一个自定义的 PropertyEditorRegistar。这样,我可以仅修复双字段格式的区域设置。但是,我认为这不是最好的解决方案,因为它将应用于我的所有 Double 字段。但与此同时,它的工作做得很好。因此,如果有人有更好的解决方案,我会很乐意对其进行测试并更新我的代码。

    所以我就是这样设置的:

    1 - 创建一个新的实现 PropertyEditorRegistrar 的 groovy 类(如果您已经有,只需在现有的方法中添加该方法包含的部分代码)

    import java.text.DecimalFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import org.springframework.beans.PropertyEditorRegistrar;
    import org.springframework.beans.PropertyEditorRegistry;
    import org.springframework.beans.propertyeditors.CustomNumberEditor;
    
    public class CustomDoubleRegistrar implements PropertyEditorRegistrar {
    
        @Override
        public void registerCustomEditors(PropertyEditorRegistry registry) {
                //define new Double format with hardcoded Locale.ENGLISH
            registry.registerCustomEditor(Double.class, 
                     new CustomNumberEditor(Double.class, 
                               DecimalFormat.getInstance(Locale.ENGLISH),true))
        }
    
    }
    

    2- 将自定义注册器定义到 conf/spring/resources.goovy 中(当然如果它还没有的话)

    beans = {
        customPropertyEditorRegistrar(CustomDoubleRegistrar)
    }
    

    3- 就是这样,Grails 自动数据绑定可以正常工作

    Test t = new Test(params); 
    //params contains many Double fields with dot '.' as decimal delimiter
    

    不要犹豫,发布更好的解决方案... 谢谢

    编辑 1

    自 Grails 2.3 以来,此解决方案不再有效。如果你仍然想使用这个方案,你必须把这个配置添加到 Config.groovy 文件中

    grails.databinding.useSpringBinder = true

    或者实现一个新的DataBinding。我已经尝试了其中的一些,但似乎没有任何东西可以解决小数分隔符问题。感谢您发布答案,如果您知道如何...

    编辑 2

    从 Grails 2.4+ 开始,您可以定义自己的 ValueConverter 来绕过基本的 Locale 验证。请注意,您必须删除在初始帖子和编辑 1 中所做的更改。以下是自定义 ValueConverter 的实现方法:

    conf/spring/resources.groovy

    // Place your Spring DSL code here
    beans = {
        "defaultGrailsjava.lang.DoubleConverter"(DoubleValueConverter)
    }
    
    class DoubleValueConverter implements ValueConverter {
    
        public LongValueConverter() {
        }
    
        boolean canConvert(value) {
            value instanceof Double
        }
    
        def convert(value) {
            //In my case returning the same value did the trick but you can define 
            //custom code that takes care about comma and point delimiter...
            return value
        }
    
        Class<?> getTargetType() {
            return Double.class
        }
    }
    

    【讨论】:

    • 我正在使用 grails 3.3.1,这个解决方案不适用于我的命令对象。 @BingUsing 也不起作用。我不知道他们为什么改变旧的行为。新的真恶心:/
    【解决方案2】:

    对于 Grails 2.3+,您可以正确地覆盖默认的活页夹/转换器,尽管它并不简单或直观。

    在这里查看我的答案:Binding real number values to Grails domain attributes (values sent by Dojo widgets)

    【讨论】:

      【解决方案3】:

      我在这里也有同样的问题。例如,德国的用户通常会输入 ,(逗号)作为小数分隔符,但显然您不能阻止他输入点;)此外,如果您从 Javascript 填充值,则很难获得本地化数字。所以我为控制器写了这个小助手方法。它可能无法涵盖所有​​可能的情况,但我需要它来输入 GPS 坐标。欢迎提出改进建议。

          /**
           * Replaces , in the param with . an converts it to a Double.
           * @param paramName an array of paramater names
           */
          private convertDicimalParamsToDouble(paramName) {
              paramName.each { it
                  def val = params[it]
                  if(val) {
                      val = val.replace(",", ".")
                      try {
                          params[it] = Double.parseDouble(val)
                      } catch (NumberFormatException) {
                          //ignore
                      }
                      log.debug("Converted decimal param ${it} with value '${params[it]}' to new value '${val}'")
                  }
              }
          }
      

      然后像这样调用它,例如:

      def save() {        
          convertDicimalParamsToDouble(["lat", "lng"])
          ...
      

      【讨论】:

        猜你喜欢
        • 2020-03-29
        • 2015-12-17
        • 2016-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多