【问题标题】:Binding a Grails date from params in a controller从控制器中的参数绑定 Grails 日期
【发布时间】:2011-02-21 18:04:51
【问题描述】:

为什么通过 grails 控制器中的参数从视图中提取日期如此困难?

我不想像这样手动提取日期:

instance.dateX = parseDate(params["dateX_value"])//parseDate is from my helper class

我只想使用instance.properties = params

在模型中,类型是java.util.Date,在参数中是所有信息:[dateX_month: 'value', dateX_day: 'value', ...]

我在网上搜索并没有找到任何内容。我希望 Grails 1.3.0 可以提供帮助,但还是一样。

我不能也不会相信手动提取日期是必要的!

【问题讨论】:

  • 请注意,在最近的 (2.0.x) 版本的 Grails 中存在一个影响日期绑定的错误:jira.grails.org/browse/GRAILS-9165
  • 留给后代:注意 Joda Time 插件自动实现数据绑定。

标签: data-binding date grails groovy controller


【解决方案1】:

Grails 版本 >= 2.3

Config.groovy 中的设置定义了在将参数绑定到 Date 时将在应用程序范围内使用的日期格式

grails.databinding.dateFormats = [
        'MMddyyyy', 'yyyy-MM-dd HH:mm:ss.S', "yyyy-MM-dd'T'hh:mm:ss'Z'"
]

grails.databinding.dateFormats 中指定的格式将按照它们包含在列表中的顺序进行尝试。

您可以使用 @BindingFormat 为单个命令对象覆盖这些应用程序范围的格式

import org.grails.databinding.BindingFormat

class Person { 
    @BindingFormat('MMddyyyy') 
    Date birthDate 
}

Grails 版本

我不能也不会相信手动提取日期是必要的!

你的固执得到了回报,早在 Grails 1.3 之前就可以直接绑定日期。步骤是:

(1)创建一个为您的日期格式注册编辑器的类

import org.springframework.beans.PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistry
import org.springframework.beans.propertyeditors.CustomDateEditor
import java.text.SimpleDateFormat

public class CustomDateEditorRegistrar implements PropertyEditorRegistrar {

    public void registerCustomEditors(PropertyEditorRegistry registry) {

        String dateFormat = 'yyyy/MM/dd'
        registry.registerCustomEditor(Date, new CustomDateEditor(new SimpleDateFormat(dateFormat), true))
    }
}

(2)通过在grails-app/conf/spring/resources.groovy中注册以下bean,让Grails知道这个日期编辑器

beans = {
    customPropertyEditorRegistrar(CustomDateEditorRegistrar)
}

(3) 现在,当您以 yyyy/MM/dd 格式在名为 foo 的参数中发送日期时,它将自动绑定到名为 foo 的属性,使用以下任一方式:

myDomainObject.properties = params

new MyDomainClass(params)

【讨论】:

  • 感谢快速回答,我之前尝试过这个(我的 spring 资源中已经有 customPropertyEditorRegistrar,我看到了你上面提到的旧 stackoverflow 问题)但这对我不起作用。我的课程如下所示: class CustomDateEditorRegistrar implements PropertyEditorRegistrar { public void registerCustomEditors(PropertyEditorRegistry registry) { String dateFormat = 'dd.MM.yyyy' registry.registerCustomEditor(Date, new CustomDateEditor(new SimpleDateFormat(dateFormat), true)) } } 和调试器正在正确地拾取它。
  • 我的日期格式(点)可能有问题吗?还是什么?
  • 我收到以下警告:project/src/java/CustomEditorRegistrar.java uses or overrides a deprecated API。有这样做的“新”方法吗?
  • @zoran119 我不知道。如果您要使用 Java 而不是 Groovy,则需要对上面的代码进行一些小改动
  • 对不起,我在错误的问题中发表了评论 :( 我的评论是针对这个问题的:stackoverflow.com/questions/963922/grails-date-unmarshalling
【解决方案2】:

Grails 2.1.1 在 params 中有一个新方法,可以轻松进行 null 安全解析。

def val = params.date('myDate', 'dd-MM-yyyy')
// or a list for formats
def val = params.date('myDate', ['yyyy-MM-dd', 'yyyyMMdd', 'yyMMdd']) 
// or the format read from messages.properties via the key 'date.myDate.format'
def val = params.date('myDate')

在文档here中找到它

【讨论】:

  • 我认为这是从params 读取日期而不是“绑定日期”
  • 似乎是最好的答案。但是我测试了它,发现了一个问题。如果我的 messages.properties 中没有代码,Grails 会引发“在代码 date.myDate.format 下找不到消息”异常。我认为引擎应该在引发此类异常之前搜索通用格式(default.date.format)。
【解决方案3】:

Grails 版本 >= 3.x

您可以在 application.yml 中按照以下语法设置日期格式:

grails:
  databinding:
    dateFormats:
      - 'dd/MM/yyyy'
      - 'dd/MM/yyyy HH:mm:ss'
      - 'yyyy-MM-dd HH:mm:ss.S'
      - "yyyy-MM-dd'T'hh:mm:ss'Z'"
      - "yyyy-MM-dd HH:mm:ss.S z"
      - "yyyy-MM-dd'T'HH:mm:ssX"

【讨论】:

    【解决方案4】:

    您是否尝试过使用任何 Grails 日期选择器插件?

    我对@9​​87654321@ 有很好的体验。

    (使用日历插件时)当您提交日期选择请求时,您可以自动将查询参数绑定到您要使用请求填充的域对象。

    例如

    new DomainObject(params)
    

    您还可以像这样解析“yyyy/MM/dd”日期字符串...

    new Date().parse("yyyy/MM/dd", "2010/03/18")
    

    【讨论】:

    • 我认为明确地调用new Date.parse() 正是他想要避免的。 AFAIK,如果您直接绑定参数,您仍然需要注册一个自定义日期编辑器(如我的回复中所述)。否则,数据绑定器怎么可能知道哪个字段是月份,哪个是年份(例如)。我同意日历插件是可用的日期选择器插件中最好的。
    • 是的,一定要使用参数绑定方法。不过,new Date().parse() 在其他地方可能非常有用。
    • 我认为我现在的方法非常糟糕。我首先从这样的参数中删除日期值:(params.remove(“datefield”))而不是我做这样的事情:instance.datefield = hlpr.exDate(params [“datefield_value”] as String)我知道这听起来很奇怪,但不知何故,这是它现在起作用的唯一方式......
    【解决方案5】:

    @Don 感谢上面的回答。

    这是自定义编辑器的替代方法,它先检查日期时间,然后检查日期格式。

    Groovy,只需为 java 添加分号

    import java.text.DateFormat
    import java.text.ParseException
    import org.springframework.util.StringUtils
    import java.beans.PropertyEditorSupport
    
    class CustomDateTimeEditor extends PropertyEditorSupport {
        private final java.text.DateFormat dateTimeFormat
        private final java.text.DateFormat dateFormat
        private final boolean allowEmpty
    
        public CustomDateTimeEditor(DateFormat dateTimeFormat, DateFormat dateFormat, boolean allowEmpty) {
            this.dateTimeFormat = dateTimeFormat
            this.dateFormat = dateFormat
            this.allowEmpty = allowEmpty
        }
    
        /**
         * Parse the Date from the given text, using the specified DateFormat.
         */
        public void setAsText(String   text) throws IllegalArgumentException   {
            if (this.allowEmpty && !StringUtils.hasText(text)) {
                // Treat empty String as null value.
                setValue(null)
            }
            else {
                try {
                    setValue(this.dateTimeFormat.parse(text))
                }
                catch (ParseException dtex) {
                    try {
                        setValue(this.dateFormat.parse(text))
                    }
                    catch ( ParseException dex ) {
                        throw new IllegalArgumentException  ("Could not parse date: " + dex.getMessage() + " " + dtex.getMessage() )
                    }
                }
            }
        }
    
        /**
         * Format the Date as String, using the specified DateFormat.
         */
        public String   getAsText() {
            Date   value = (Date) getValue()
            return (value != null ? this.dateFormat.format(value) : "")
        }
    }
    

    【讨论】:

      【解决方案6】:

      Grails 版本 >= 2.3

      将字符串转换为日期的localeAware版本

      在 src/groovy 中:

      package test
      
      import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
      import org.grails.databinding.converters.ValueConverter
      import org.springframework.context.MessageSource
      import org.springframework.web.servlet.LocaleResolver
      
      import javax.servlet.http.HttpServletRequest
      import java.text.SimpleDateFormat
      
      class StringToDateConverter implements ValueConverter {
          MessageSource messageSource
          LocaleResolver localeResolver
      
          @Override
          boolean canConvert(Object value) {
              return value instanceof String
          }
      
          @Override
          Object convert(Object value) {
              String format = messageSource.getMessage('default.date.format', null, "dd/MM/yyyy", getLocale())
              SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format)
              return simpleDateFormat.parse(value)
          }
      
          @Override
          Class<?> getTargetType() {
              return Date.class
          }
      
          protected Locale getLocale() {
              def locale
              def request = GrailsWebRequest.lookup()?.currentRequest
              if(request instanceof HttpServletRequest) {
                  locale = localeResolver?.resolveLocale(request)
              }
              if(locale == null) {
                  locale = Locale.default
              }
              return locale
          }
      }
      

      在 conf/spring/resources.groovy 中:

      beans = {
          defaultDateConverter(StringToDateConverter){
              messageSource = ref('messageSource')
              localeResolver = ref('localeResolver')
          }
      }
      

      bean 的名称“defaultDateConverter”非常重要(覆盖默认日期转换器)

      【讨论】:

      • 很好的解决方案,可以更改应用程序中的所有数据绑定,并且可以识别区域设置。我很惊讶 Grails 默认不这样做,因为它符合约定优于配置。
      猜你喜欢
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多