最近工作中使用到了JDK1.8 time包,逐步取代以前的Date类,相比以前,time包的API的确好用多了,相关内容在网上有很多,就不累赘了。
但是有点蛋疼的地方在于LocalDateTime支持ISO8601标准,即[2018-10-10T05:51:31.924Z]。在MVC中,习惯性用[yyyy-MM-dd HH:mm:ss]。
好在Spring带有注解。如:
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss)
private LocalDateTime ldt;
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date
参数在Param上,可以使用@DateTimeFormat在参数或者参数实体的属性上。对于参数在body上,则可以通过自定义拓展Formatter或者Converter<String, LocalDateTime>,网上也有很多,这里就提供一下代码
@Configuration
public class LocalDateTimeFormatConfig {
<span >@Bean</span>
<span >public</span> Formatter<span class="token generics function"><span ><</span>LocalDate<span >></span></span> <span >localDateFormatter</span><span >(</span><span >)</span> <span >{</span>
<span >return</span> <span >new</span> <span >Formatter</span><span class="token generics function"><span ><</span>LocalDate<span >></span></span><span >(</span><span >)</span> <span >{</span>
<span >@Override</span>
<span >public</span> <span >@Nullable</span> String <span >print</span><span >(</span><span >@Nullable</span> LocalDate object<span >,</span> <span >@Nullable</span> Locale locale<span >)</span> <span >{</span>
<span >if</span> <span >(</span>Objects<span >.</span><span >isNull</span><span >(</span>object<span >)</span><span >)</span><span >{</span>
<span >return</span> null<span >;</span>
<span >}</span>
<span >return</span> object<span >.</span><span >format</span><span >(</span>DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span><span >"yyyy-MM-dd"</span><span >)</span><span >)</span><span >;</span>
<span >}</span>
<span >@Override</span>
<span >public</span> <span >@Nullable</span> LocalDate <span >parse</span><span >(</span><span >@Nullable</span> String text<span >,</span> <span >@Nullable</span> Locale locale<span >)</span> <span >{</span>
<span >if</span> <span >(</span><span >!</span>StringUtils<span >.</span><span >hasText</span><span >(</span>text<span >)</span><span >)</span> <span >{</span>
<span >return</span> null<span >;</span>
<span >}</span>
<span >return</span> LocalDate<span >.</span><span >parse</span><span >(</span>text<span >,</span> DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span><span >"yyyy-MM-dd"</span><span >)</span><span >)</span><span >;</span>
<span >}</span>
<span >}</span><span >;</span>
<span >}</span>
<span >@Bean</span>
<span >public</span> Formatter<span class="token generics function"><span ><</span>LocalDateTime<span >></span></span> <span >localDateTimeFormatter</span><span >(</span><span >)</span> <span >{</span>
<span >return</span> <span >new</span> <span >Formatter</span><span class="token generics function"><span ><</span>LocalDateTime<span >></span></span><span >(</span><span >)</span> <span >{</span>
<span >@Override</span>
<span >public</span> <span >@Nullable</span> String <span >print</span><span >(</span><span >@Nullable</span> LocalDateTime object<span >,</span> <span >@Nullable</span> Locale locale<span >)</span> <span >{</span>
<span >if</span> <span >(</span>Objects<span >.</span><span >isNull</span><span >(</span>object<span >)</span><span >)</span><span >{</span>
<span >return</span> null<span >;</span>
<span >}</span>
<span >return</span> object<span >.</span><span >format</span><span >(</span>DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span><span >"yyyy-MM-dd HH:mm:ss"</span><span >)</span><span >)</span><span >;</span>
<span >}</span>
<span >@Override</span>
<span >public</span> <span >@Nullable</span> LocalDateTime <span >parse</span><span >(</span><span >@Nullable</span> String text<span >,</span> <span >@Nullable</span> Locale locale<span >)</span> <span >{</span>
<span >if</span> <span >(</span><span >!</span>StringUtils<span >.</span><span >hasText</span><span >(</span>text<span >)</span><span >)</span> <span >{</span>
<span >return</span> null<span >;</span>
<span >}</span>
<span >return</span> LocalDateTime<span >.</span><span >parse</span><span >(</span>text<span >,</span> DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span><span >"yyyy-MM-dd HH:mm:ss"</span><span >)</span><span >)</span><span >;</span>
<span >}</span>
<span >}</span><span >;</span>
<span >}</span>
<span >@Bean</span>
<span >public</span> Formatter<span class="token generics function"><span ><</span>LocalTime<span >></span></span> <span >localTimeFormatter</span><span >(</span><span >)</span> <span >{</span>
<span >return</span> <span >new</span> <span >Formatter</span><span class="token generics function"><span ><</span>LocalTime<span >></span></span><span >(</span><span >)</span> <span >{</span>
<span >@Override</span>
<span >public</span> <span >@Nullable</span> String <span >print</span><span >(</span><span >@Nullable</span> LocalTime object<span >,</span> <span >@Nullable</span> Locale locale<span >)</span> <span >{</span>
<span >if</span> <span >(</span>Objects<span >.</span><span >isNull</span><span >(</span>object<span >)</span><span >)</span><span >{</span>
<span >return</span> null<span >;</span>
<span >}</span>
<span >return</span> object<span >.</span><span >format</span><span >(</span>DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span><span >"HH:mm:ss"</span><span >)</span><span >)</span><span >;</span>
<span >}</span>
<span >@Override</span>
<span >public</span> <span >@Nullable</span> LocalTime <span >parse</span><span >(</span><span >@Nullable</span> String text<span >,</span> <span >@Nullable</span> Locale locale<span >)</span> <span >{</span>
<span >if</span> <span >(</span><span >!</span>StringUtils<span >.</span><span >hasText</span><span >(</span>text<span >)</span><span >)</span> <span >{</span>
<span >return</span> null<span >;</span>
<span >}</span>
<span >return</span> LocalTime<span >.</span><span >parse</span><span >(</span>text<span >,</span> DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span><span >"HH:mm:ss"</span><span >)</span><span >)</span><span >;</span>
<span >}</span>
<span >}</span><span >;</span>
<span >}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
public class LocalDateTimeConvertConfig {
<span >private</span> String dateTimePattern <span >=</span> <span >"yyyy-MM-dd HH:mm:ss"</span><span >;</span>
<span >private</span> String datePattern <span >=</span> <span >"yyyy-MM-dd"</span><span >;</span>
<span >@Bean</span>
<span >public</span> Converter<span class="token generics function"><span ><</span>String<span >,</span> LocalDateTime<span >></span></span> <span >LocalDateTimeConvert</span><span >(</span><span >)</span> <span >{</span>
<span >return</span> source <span >-</span><span >></span> <span >{</span>
DateTimeFormatter df <span >=</span> DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span>dateTimePattern<span >)</span><span >;</span>
LocalDateTime date <span >=</span> null<span >;</span>
<span >try</span> <span >{</span>
date <span >=</span> LocalDateTime<span >.</span><span >parse</span><span >(</span>source<span >,</span> df<span >)</span><span >;</span>
<span >}</span> <span >catch</span> <span >(</span><span >Exception</span> e<span >)</span> <span >{</span>
e<span >.</span><span >printStackTrace</span><span >(</span><span >)</span><span >;</span>
<span >}</span>
<span >return</span> date<span >;</span>
<span >}</span><span >;</span>
<span >}</span>
<span >@Bean</span>
<span >public</span> Converter<span class="token generics function"><span ><</span>String<span >,</span> LocalDate<span >></span></span> <span >localDateConverter</span><span >(</span><span >)</span> <span >{</span>
<span >return</span> source <span >-</span><span >></span> <span >{</span>
DateTimeFormatter df <span >=</span> DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span>datePattern<span >)</span><span >;</span>
LocalDate date <span >=</span> null<span >;</span>
<span >try</span> <span >{</span>
date <span >=</span> LocalDate<span >.</span><span >parse</span><span >(</span>source<span >,</span>df<span >)</span><span >;</span>
<span >}</span><span >catch</span> <span >(</span><span >Exception</span> e<span >)</span><span >{</span>
e<span >.</span><span >printStackTrace</span><span >(</span><span >)</span><span >;</span>
<span >}</span>
<span >return</span> date<span >;</span>
<span >}</span><span >;</span>
<span >}</span>
<span >// 这里是使用JackSon全局序列化LocalDateTime,而我使用是FastJso,蛋疼</span>
<span >@Bean</span>
<span >public</span> LocalDateTimeSerializer <span >localDateTimeDeserializer</span><span >(</span><span >)</span> <span >{</span>
<span >return</span> <span >new</span> <span >LocalDateTimeSerializer</span><span >(</span>DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span>dateTimePattern<span >)</span><span >)</span><span >;</span>
<span >}</span>
<span >@Bean</span>
<span >public</span> Jackson2ObjectMapperBuilderCustomizer <span >jackson2ObjectMapperBuilderCustomizer</span><span >(</span><span >)</span> <span >{</span>
<span >return</span> builder <span >-</span><span >></span> builder<span >.</span><span >serializerByType</span><span >(</span>LocalDateTime<span >.</span><span >class</span><span >,</span> <span >localDateTimeDeserializer</span><span >(</span><span >)</span><span >)</span><span >;</span>
<span >}</span>
}
这里要说的问题就是现在工作项目中遇到的问题,使用的FastJson,而不是MVC默认的JackSon,在序列化LocalDateTime输出到前端时候,是[2018-10-10T05:51:31.924Z],而想要输出的是yyyy-MM-dd HH:mm:ss格式,至此我们需要定制LocalDateTime类的序列化。我们一样可以使用注解解决,使用FastJson的@JSONField(format = “yyyy-MM-dd HH:mm:ss”),在需要特殊序列化的成员属性上。
为了减少注解的使用,尝试是否可以让FastJson默认根据我们的规则去序列化LocalDateTime类。
首先祭出常规的FastJsonConfig:
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteMapNullValue,
...
SerializerFeature.WriteNullStringAsEmpty);
fastJsonConfig.setCharset(Charset.forName("utf-8"));
...
使用ValueFilter:
ValueFilter valueFilter = (o, s, o1) -> {
if (null == o1) {
o1 = "";
}
if (o1 instanceof LocalDateTime){
o1 = ((LocalDateTime) o1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
return o1;
};
fastJsonConfig.setSerializeFilters(valueFilter);
// 缺点,这是过滤级别的序列化,序列化的结果取决于o1的值,如将LocalDateTime类型的o1转换为String类型的o1,后续将不会调用LocalDateTime的序列化器,因为已经不是LocalDateTime类型了
指定fastJsonConfig的DateFormat:
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
...
// 缺点,指定后,将不会使用@JSONField注解上的format属性,包括并不限于Date类,LocalDateTime类,LocalDate类。(慎用)
自定义LocalDateTimeSerializer实现ObjectSerializer接口,重写write方法:
public class LocalDateTimeSerializer implements ObjectSerializer {
<span >public</span> <span >static</span> <span >final</span> LocalDateTimeSerializer instance <span >=</span> <span >new</span> <span >LocalDateTimeSerializer</span><span >(</span><span >)</span><span >;</span>
<span >private</span> <span >static</span> <span >final</span> String defaultPattern <span >=</span> <span >"yyyy-MM-dd HH:mm:ss"</span><span >;</span>
<span >public</span> <span >LocalDateTimeSerializer</span><span >(</span><span >)</span> <span >{</span>
<span >}</span>
<span >@Override</span>
<span >public</span> <span >void</span> <span >write</span><span >(</span>JSONSerializer serializer<span >,</span> Object object<span >,</span> Object fieldName<span >,</span> Type fieldType<span >,</span> <span >int</span> features<span >)</span> <span >throws</span> IOException <span >{</span>
SerializeWriter out <span >=</span> serializer<span >.</span>out<span >;</span>
<span >if</span> <span >(</span>object <span >==</span> null<span >)</span> <span >{</span>
out<span >.</span><span >writeNull</span><span >(</span><span >)</span><span >;</span>
<span >}</span> <span >else</span> <span >{</span>
LocalDateTime result <span >=</span> <span >(</span>LocalDateTime<span >)</span> object<span >;</span>
out<span >.</span><span >writeString</span><span >(</span>result<span >.</span><span >format</span><span >(</span>DateTimeFormatter<span >.</span><span >ofPattern</span><span >(</span>defaultPattern<span >)</span><span >)</span><span >)</span><span >;</span>
<span >}</span>
<span >}</span>
}
SerializeConfig serializeConfig = SerializeConfig.globalInstance;
serializeConfig.put(LocalDateTime.class, LocalDateTimeSerializer.instance);
fastJsonConfig.setSerializeConfig(serializeConfig);
// 缺点,@JSONField注解一样会失效,仅限于LocalDateTime类
...
如果使用的是JackSon,只需要在实例化LocalDateTimeSerializer的时候,指定一个DateTimeFormatter即可,方便很多,FastJson完败,有可能是我学艺不精,毕竟我是菜鸡。