FastJson配置全局LocalDateTime序列化

最近工作中使用到了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 class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> Formatter<span class="token generics function"><span class="token punctuation">&lt;</span>LocalDate<span class="token punctuation">&gt;</span></span> <span class="token function">localDateFormatter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Formatter</span><span class="token generics function"><span class="token punctuation">&lt;</span>LocalDate<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token annotation punctuation">@Nullable</span> String <span class="token function">print</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Nullable</span> LocalDate object<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> Locale locale<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>Objects<span class="token punctuation">.</span><span class="token function">isNull</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
                <span class="token keyword">return</span> null<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> object<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span><span class="token string">"yyyy-MM-dd"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token annotation punctuation">@Nullable</span> LocalDate <span class="token function">parse</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Nullable</span> String text<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> Locale locale<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>StringUtils<span class="token punctuation">.</span><span class="token function">hasText</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">return</span> null<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> LocalDate<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>text<span class="token punctuation">,</span> DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span><span class="token string">"yyyy-MM-dd"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> Formatter<span class="token generics function"><span class="token punctuation">&lt;</span>LocalDateTime<span class="token punctuation">&gt;</span></span> <span class="token function">localDateTimeFormatter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Formatter</span><span class="token generics function"><span class="token punctuation">&lt;</span>LocalDateTime<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token annotation punctuation">@Nullable</span> String <span class="token function">print</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Nullable</span> LocalDateTime object<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> Locale locale<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>Objects<span class="token punctuation">.</span><span class="token function">isNull</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
                <span class="token keyword">return</span> null<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> object<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span><span class="token string">"yyyy-MM-dd HH:mm:ss"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token annotation punctuation">@Nullable</span> LocalDateTime <span class="token function">parse</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Nullable</span> String text<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> Locale locale<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>StringUtils<span class="token punctuation">.</span><span class="token function">hasText</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">return</span> null<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> LocalDateTime<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>text<span class="token punctuation">,</span> DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span><span class="token string">"yyyy-MM-dd HH:mm:ss"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> Formatter<span class="token generics function"><span class="token punctuation">&lt;</span>LocalTime<span class="token punctuation">&gt;</span></span> <span class="token function">localTimeFormatter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Formatter</span><span class="token generics function"><span class="token punctuation">&lt;</span>LocalTime<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token annotation punctuation">@Nullable</span> String <span class="token function">print</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Nullable</span> LocalTime object<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> Locale locale<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>Objects<span class="token punctuation">.</span><span class="token function">isNull</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
                <span class="token keyword">return</span> null<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> object<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span><span class="token string">"HH:mm:ss"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token annotation punctuation">@Nullable</span> LocalTime <span class="token function">parse</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Nullable</span> String text<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> Locale locale<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>StringUtils<span class="token punctuation">.</span><span class="token function">hasText</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">return</span> null<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> LocalTime<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>text<span class="token punctuation">,</span> DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span><span class="token string">"HH:mm:ss"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</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 class="token keyword">private</span> String dateTimePattern <span class="token operator">=</span> <span class="token string">"yyyy-MM-dd HH:mm:ss"</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> String datePattern <span class="token operator">=</span> <span class="token string">"yyyy-MM-dd"</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> Converter<span class="token generics function"><span class="token punctuation">&lt;</span>String<span class="token punctuation">,</span> LocalDateTime<span class="token punctuation">&gt;</span></span> <span class="token function">LocalDateTimeConvert</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> source <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
        DateTimeFormatter df <span class="token operator">=</span> DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span>dateTimePattern<span class="token punctuation">)</span><span class="token punctuation">;</span>
        LocalDateTime date <span class="token operator">=</span> null<span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            date <span class="token operator">=</span> LocalDateTime<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>source<span class="token punctuation">,</span> df<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> date<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> Converter<span class="token generics function"><span class="token punctuation">&lt;</span>String<span class="token punctuation">,</span> LocalDate<span class="token punctuation">&gt;</span></span> <span class="token function">localDateConverter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> source <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
        DateTimeFormatter df <span class="token operator">=</span> DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span>datePattern<span class="token punctuation">)</span><span class="token punctuation">;</span>
        LocalDate date <span class="token operator">=</span> null<span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            date <span class="token operator">=</span> LocalDate<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>source<span class="token punctuation">,</span>df<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span><span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> date<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// 这里是使用JackSon全局序列化LocalDateTime,而我使用是FastJso,蛋疼</span>
<span class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> LocalDateTimeSerializer <span class="token function">localDateTimeDeserializer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">LocalDateTimeSerializer</span><span class="token punctuation">(</span>DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span>dateTimePattern<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> Jackson2ObjectMapperBuilderCustomizer <span class="token function">jackson2ObjectMapperBuilderCustomizer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> builder <span class="token operator">-</span><span class="token operator">&gt;</span> builder<span class="token punctuation">.</span><span class="token function">serializerByType</span><span class="token punctuation">(</span>LocalDateTime<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token function">localDateTimeDeserializer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</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 class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> LocalDateTimeSerializer instance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LocalDateTimeSerializer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> String defaultPattern <span class="token operator">=</span> <span class="token string">"yyyy-MM-dd HH:mm:ss"</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token function">LocalDateTimeSerializer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">write</span><span class="token punctuation">(</span>JSONSerializer serializer<span class="token punctuation">,</span> Object object<span class="token punctuation">,</span> Object fieldName<span class="token punctuation">,</span> Type fieldType<span class="token punctuation">,</span> <span class="token keyword">int</span> features<span class="token punctuation">)</span> <span class="token keyword">throws</span> IOException <span class="token punctuation">{</span>
    SerializeWriter out <span class="token operator">=</span> serializer<span class="token punctuation">.</span>out<span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>object <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        out<span class="token punctuation">.</span><span class="token function">writeNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        LocalDateTime result <span class="token operator">=</span> <span class="token punctuation">(</span>LocalDateTime<span class="token punctuation">)</span> object<span class="token punctuation">;</span>
        out<span class="token punctuation">.</span><span class="token function">writeString</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span>defaultPattern<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

SerializeConfig serializeConfig = SerializeConfig.globalInstance;
serializeConfig.put(LocalDateTime.class, LocalDateTimeSerializer.instance);
fastJsonConfig.setSerializeConfig(serializeConfig);

// 缺点,@JSONField注解一样会失效,仅限于LocalDateTime类
...

如果使用的是JackSon,只需要在实例化LocalDateTimeSerializer的时候,指定一个DateTimeFormatter即可,方便很多,FastJson完败,有可能是我学艺不精,毕竟我是菜鸡。

原文地址:https://blog.csdn.net/luomin369433047/article/details/88972543
posted @ 2020-01-06 14:20  星朝  阅读(5925)  评论(0编辑  收藏  举报