我正在将一个非常老的Grails应用程序转换为最新版本(3.3.0)。事情有点让人沮丧,但除了先前在我的BootStrap init中注册的JSON和XML marshallers之外,我非常接近迁移所有内容。
以前的marshaller注册看起来像这样:
// 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之后,无论我尝试做什么,这个marshaller注册似乎都没有被使用。
我知道有一种新的“JSON Views”处理方式,但是这个特定的服务有很多端点,我不想为所有这些端点编写自定义转换器和“.gson”模板,如果一切都已经是我需要的格式。我只需要使用JSON中的响应和表现属性的日期(格式化字符串)。
相反,我发现的(与之前的行为相比,使用ZonedDateTime的属性在我的JSON输出中“爆炸”。有一大堆垃圾日期对象信息是不需要的,它是没有像我期望的那样格式化为简单的字符串。
我尝试过一些事情(主要是根据最新的Grails文档中的建议)---
Custom Converters Default Date Format
在application.yml中添加grails视图的配置:
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
将一个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
}
}
在我的控制器中,我改变了:
return multibeamCatalogService.findFiles(cmd, params)
为此(为了像以前一样在浏览器中获得JSON输出):
respond multibeamCatalogService.findFiles(cmd, params), formats: ['json', 'xml']
不幸的是,我可以考虑尝试上述的大多数排列导致了诸如“无法解析视图”之类的错误。否则,当我收到回复时,主要问题是日期没有格式化为字符串。此功能以前由Marshaller执行。
我很沮丧。有人可以告诉我如何在我的JSON输出中将ZonedDateTime格式化为一个简单的字符串(例如 - “2009-06-21T00:00:00Z”)而不是像这样的巨型对象吗?简单地转换为java.util.Date会导致“无法解析视图”错误再次出现;因此,我希望我制作一个“.gson”视图,它永远不会显示我期望的格式或者是空的。
"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
答案 0 :(得分:0)
简单的答案是格式化一个调用.format(DateTimeFormatter)的ZonedDateTime对象。这取决于你想要的格式。您可以在DateTimeFormatter中指定自己的或使用一些预定义的。
我也很想知道是否有一种简单的说法,因为每个端点都显示为json&#34;。我到目前为止找到的唯一方法是在每个控制器类中都有这个,这不是太糟糕但是看起来很傻。我使用了响应,然后在我的控制器方法中返回。
static responseFormats = ['json'] // This is needed for grails to indicate what format to use for respond.
虽然我仍然看到记录错误,但是其他api似乎仍然有效,&#34;无法解析视图&#34;对于我点击的任何端点。