我正在将一个真正旧的Grails应用程序转换为最新版本(3.3.0)。事情有些令人沮丧,但是我几乎要迁移所有东西,除了以前在我的BootStrap初始化中注册的JSON和XML编码器。

以前的编码注册看起来像这样:

// register JSON marshallers at startup in all environments 
MarshallerUtils.registerMarshallers() 

定义如下:
class MarshallerUtils { 
 
    // Registers marshaller logic for various types that 
    // aren't supported out of the box or that we want to customize. 
    // These are used whenever the JSON or XML converters are called, 
    // e.g. return model as JSON 
    static registerMarshallers() { 
 
        final dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis() 
        final isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") 
 
        // register marshalling logic for both XML and JSON converters 
        [XML, JSON].each { converter -> 
 
            // This overrides the marshaller from the joda time plugin to 
            // force all DateTime instances to use the UTC time zone 
            // and the ISO standard "yyyy-mm-ddThh:mm:ssZ" format 
            converter.registerObjectMarshaller(DateTime, 10) { DateTime it -> 
                return it == null ? null : it.toString(dateTimeFormatter.withZone(org.joda.time.DateTimeZone.UTC)) 
            } 
 
            converter.registerObjectMarshaller(Date, 10) { Date it -> 
                return it == null ? null : isoDateFormat.format(it) 
            } 
 
            converter.registerObjectMarshaller(TIMESTAMP, 10) { TIMESTAMP it -> 
                return it == null ? null : isoDateFormat.format(it.dateValue()) 
            } 
        } 
    } 
} 

在迁移期间,我最终将org.joda.time.DateTime的所有实例转换为java.time.ZonedDateTime:
class MarshallerUtils { 
 
    // Registers marshaller logic for various types that 
    // aren't supported out of the box or that we want to customize. 
    // These are used whenever the JSON or XML converters are called, 
    // e.g. return model as JSON 
    static registerMarshallers() { 
 
        final dateTimeFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME 
        final isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") 
 
        // register marshalling logic for both XML and JSON converters 
        [XML, JSON].each { converter -> 
 
            // This overrides the marshaller from the java.time to 
            // force all DateTime instances to use the UTC time zone 
            // and the ISO standard "yyyy-mm-ddThh:mm:ssZ" format 
            converter.registerObjectMarshaller(ZonedDateTime, 10) { ZonedDateTime it -> 
 
                return it == null ? null : it.toString(dateTimeFormatter.withZone(ZoneId.of("UTC"))) 
            } 
 
            converter.registerObjectMarshaller(Date, 10) { Date it -> 
                return it == null ? null : isoDateFormat.format(it) 
            } 
 
            converter.registerObjectMarshaller(TIMESTAMP, 10) { TIMESTAMP it -> 
                return it == null ? null : isoDateFormat.format(it.dateValue()) 
            } 
        } 
    } 
} 

不幸的是,在升级到Grails 3.3.0之后,无论我尝试做什么,似乎都没有使用此编码器注册。

我确实知道有一种新的“JSON View ”处理方式,但是该特定服务具有许多终结点,并且如果一切都已经准备就绪,我不想为所有这些终结点编写自定义转换器和“.gson”模板以我需要的格式。我只需要响应以JSON格式和日期来表现属性(格式为字符串)。

相反,我发现(与以前的行为相比,利用ZonedDateTime的属性已在我的JSON输出中“爆炸”。不需要大量的垃圾日期对象信息,并且未将其格式化为我期望的一个简单的字符串。

我已经尝试了一些方法(主要是根据最新的官方Grails文档中的建议)-

Custom Converters
Default Date Format

在application.yml中为grails View 添加配置:
views: 
    json: 
        generator: 
            dateFormat: "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 
            locale: "en/US" 
            timeZone: "GMT" 

在“src”下创建此路径:
src/main/resources/META-INF/services/grails.plugin.json.builder.JsonGenerator$Converter
并在上面的文件^中将转换器添加到我的域类中:
class MultibeamFileConverter implements JsonGenerator.Converter { 
 
    final DateTimeFormatter isoDateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(ZoneId.of("UTC")); 
 
    @Override 
    boolean handles(Class<?> type) { 
        MultibeamFile.isAssignableFrom(type) 
    } 
 
    @Override 
    Object convert(Object value, String key) { 
        MultibeamFile multibeamFile = (MultibeamFile)value 
        multibeamFile.startTime.format(isoDateFormat) 
        multibeamFile.endTime.format(isoDateFormat) 
        return multibeamFile 
    } 
} 

在 Controller 中,我进行了更改:
return multibeamCatalogService.findFiles(cmd, params)
为此(为了像以前一样在浏览器中获取JSON输出):
respond multibeamCatalogService.findFiles(cmd, params), formats: ['json', 'xml']
不幸的是,我可以想到的大多数排列都导致了诸如“无法解析 View ”之类的错误。否则,当我得到答复时,主要问题是日期未格式化为字符串。该功能先前由Marshaller执行。

我感到非常沮丧。有人可以告诉我如何在我的JSON输出中而不是像这样的巨型对象将ZonedDateTime格式化为简单字符串(例如-“2009-06-21T00:00:00Z”)吗?简单地转换为java.util.Date会导致再次出现“无法解析 View ”错误;因此,期望我创建一个“.gson” View ,该 View 永远不会显示我期望的格式或为空。
"startTime": { 
"dayOfMonth": 26, 
"dayOfWeek": { 
"enumType": "java.time.DayOfWeek", 
"name": "FRIDAY" 
}, 
"dayOfYear": 207, 
"hour": 0, 
"minute": 0, 
"month": { 
"enumType": "java.time.Month", 
"name": "JULY" 
}, 
"monthValue": 7, 
"nano": 0, 
"offset": { 
"id": "-06:00", 
"rules": { 
"fixedOffset": true, 
"transitionRules": [], 
"transitions": [] 
}, 
"totalSeconds": -21600 
}, ... // AND SO ON FOR_EVAH 

请您参考如下方法:

简单的答案是格式化称为.format(DateTimeFormatter)的ZonedDateTime对象。这取决于您想要的格式。您可以指定自己的名称,也可以在DateTimeFormatter中使用一些预定义的名称。

我也很想知道是否有一种简单的方式说“对于每个端点将其显示为json”。到目前为止,我发现的唯一方法是在每个 Controller 类中都使用它,虽然还算不错,但是看起来很愚蠢。我在 Controller 方法中使用响应,然后返回。

static responseFormats = ['json'] // This is needed for grails to indicate what format to use for respond. 

虽然我仍然看到错误记录,但是rest api仍然可以正常工作,对于我命中的任何端点,“无法解析 View ”。


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!