10

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

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

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

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

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

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

使用:Grails:2.2.0 浏览器:Google Chrome(区域设置 fr_CA)

非常感谢!

4

3 回答 3

16

我一直在寻找和尝试 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 验证。请注意,您必须删除在初始帖子和 EDIT 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
    }
}
于 2013-02-15T17:09:14.673 回答
1

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

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

于 2014-06-18T21:29:57.363 回答
0

我在这里有同样的问题。例如,德国的用户通常会输入 ,(逗号)作为小数分隔符,但显然您不能阻止他输入点;)此外,如果您从 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"])
    ...
于 2013-05-05T18:33:50.180 回答