【问题标题】:Grails JSON Marshaller Shows a Different Date value than Original DateGrails JSON Marshaller 显示的日期值与原始日期不同
【发布时间】:2016-05-30 20:26:16
【问题描述】:

在我的 Grails 应用中,从数据库中读取的原始日期等于:

{ endDate=2015-10-19 19:00:00.0}

虽然 JSON 结果是:

{"endDate": "2015-10-19T16:00:00Z"}

我认为这可能与时区转换有关。如何在 JSON 中显示没有任何时区转换的原始日期?

【问题讨论】:

    标签: json grails


    【解决方案1】:

    根据您所在的时区,2015-10-19 19:00:00.02015-10-19T16:00:00Z 可能不是不同的时间,它们可能只是同一时间的不同表示(瞬间)。

    就我而言,我使用自定义编组器来确保我的 API 的 JSON 响应中的时间始终使用 UTC 时区。我的自定义编组器如下所示:

    import org.springframework.stereotype.Component
    
    @Component
    class DateMarshaller implements CustomMarshaller {
    
        @Override
        def getSupportedTypes() {
            Date
        }
    
        @Override
        Closure getMarshaller() {
            { Date date ->
    
                TimeZone tz = TimeZone.getTimeZone('UTC')
                date?.format("yyyy-MM-dd'T'HH:mm:ss'Z'", tz)
            }
        }
    }
    

    请记住在Config.groovy 中注册此编组器所在的包以进行Spring bean 扫描。它实现的接口是:

    interface CustomMarshaller {
    
        /**
         * Indicates the type(s) of object that this marshaller supports
         * @return a {@link Class} or collection of {@link Class} 
         * if the marshaller supports multiple types
         */
        def getSupportedTypes()
    
        Closure getMarshaller()
    }
    

    然后我有一个服务可以为相关类型注册我的所有CustomMarshaller 实例:

    import grails.converters.JSON
    import org.springframework.context.ApplicationContext
    import org.springframework.context.ApplicationContextAware
    
    import javax.annotation.PostConstruct
    
    class MarshallerRegistrarService implements ApplicationContextAware {
    
        static transactional = false
    
        ApplicationContext applicationContext
    
        // a combination of eager bean initialization and @PostConstruct ensures that the marshallers are registered when
        // the app (or a test thereof) starts
        boolean lazyInit = false
    
        @PostConstruct
        void registerMarshallers() {
    
            Map<String, CustomMarshaller> marshallerBeans = applicationContext.getBeansOfType(CustomMarshaller)
    
            marshallerBeans.values().each { CustomMarshaller customMarshaller ->
    
                customMarshaller.supportedTypes.each { Class supportedType ->
                    JSON.registerObjectMarshaller supportedType, customMarshaller.marshaller
                }
            }
        }
    }
    

    这是一个相当复杂的解决方案,但就我而言,我使用的是 Grails 2.5.X。如果我使用的是 Grails 3.X,我会尝试使用 JSON 视图。

    【讨论】:

      【解决方案2】:

      如果我没记错的话,JSON 规范实际上并没有定义日期格式的格式。但是每个人都使用 ISO 8601,所以它是事实上的标准。而且大多数人总是使用祖鲁时区。

      我前段时间搜索了自己,关于强制 Grails JSON 在特定时区呈现日期的方法,但失败了。在我的 Grails Web 应用程序中,我只是将日期字段声明为文本,并在我自己的代码中将它们格式化为适当的时区和格式。从好的方面来说,它还有一个额外的好处,你可以保证它在未来保持这种状态。 (我从大约 1.1 开始就使用 Grails,并且确实看到过几次重大变化。)

      【讨论】:

        【解决方案3】:

        在使用 grails 2.3.11 构建的旧应用程序上工作,由于某些未知原因,@Dónal 的解决方案无法正常工作。幸运的是,我找到了一种更简单/更直接的方法来在 mrhaki's blog 上注册自定义编组器。

        因此,我复制了位于 org.codehaus.groovy.grails.web.converters.marshaller.json 中的默认 DateMarshaller,并在我的自定义 DateMarshaller 中修改了日期格式化程序,然后使用 sn-p 注册了编组器下面,取自 mrhaki 的帖子。

        dateMarshaller(ObjectMarshallerRegisterer) {
            // Assign custom marshaller instance.
            marshaller = new DateMarshaller()
        
            // Set converter class type.
            converterClass = JSON
        
            // Optional set priority. Default value is 0.
            priority = 1
        }
        

        只需确保您的自定义编组器的优先级高于默认设置即可。像魅力一样工作!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-28
          • 1970-01-01
          相关资源
          最近更新 更多