jackson时间格式解决方案

jackson时间格式解决方案

你遇到下面这个异常吗??

com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2021-01-23 22:02:17": not a valid representation (error: Failed to parse Date value '2021-01-23 22:02:17': Cannot parse date "2021-01-23 22:02:17": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null))

这个异常是jackson在处理json字符串 to Object类型的时候,json字符串中包含类似"yyyy-MM-dd HH:mm:ss""yyyy-MM-dd HH:mm"格式的时间字符串,这种格式是属于国内常用时间格式,jackson默认是不认识的。当你的字符串中一旦出现这种,jackson会直接给你报错。
好在jackson可以让用户能灵活的配置。那么接下来,我们就去探索解决方案。

看起来最简单的解决方案

我们遇到的格式问题,jackson开发者必然也能想到,所以它为我们提供了@JsonFormat注解,我们可以根据需要在属性上设置格式的转化,使用如下:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date date;
  • pattern指定序列化格式,timezone指定时区;
  • 这种方式满足我们解决异常的需求,但是如果有太多的日期类需要转化,这真是让人头大,不过别怕,且看下文处理。

最省心的解决方案

JSON序列化和反序列化工具类

/**
 * json工具类
 *
 * @author huaqi@liu
 * @since 2023-03-30 16:51:42
 */
public class JSON {

    private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        // 设置全局的TimeZone
        OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        // 全局处理时间 ,SimpleDateFormat的构造函数参数中是序列化需要滴!
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"){
			// 这个方法是反序列化需要滴!
            @Override
            public Date parse(String source) throws ParseException {
                return DateUtils.str2Data(source);
            }
        });
    }
    /**
     * 字符串转化成对象
     * @param json
     * @param <T>
     * @return
     */
    public static <T> T parser(String json, Class<T> clazz) throws JsonProcessingException {
        return OBJECT_MAPPER.readValue(json, clazz);
    }
    /**
     * 对象转化成字符串
     * @param object
     * @return
     */
    public static String stringify(Object object) throws JsonProcessingException {
        return OBJECT_MAPPER.writeValueAsString(object);
    }
}

时间工具类

/**
 * 时间格式类
 *
 * @author huaqi@liu
 * @since 2023-03-30 16:51:42
 */
public class DateUtils {
    private static List<String> fmtList = new ArrayList<String>() {{
        add("yyyy-MM-dd HH:mm:ss");
        add("yyyy-MM-dd HH:mm");
        add("yyyy-MM-dd HH");
        add("yyyy-MM-dd");
    }};

    /***
     * 转换字符串为日期date
     *
     * 自动匹配转化,支持fmtList中的几种格式
     * @param dateStr
     * @param fmtIndex
     * @return
     */
    public static Date str2Data(String dateStr, int... fmtIndex) {
        int index = 0;
        if (fmtIndex != null && fmtIndex.length > 0) {
            index = fmtIndex[0];
        }
        if (index > fmtList.size() - 1) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(fmtList.get(index));
        try {
            Date date = format.parse(dateStr);
            return date;
        } catch (ParseException e1) {
            return str2Data(dateStr, ++index);
        }
    }

    /***
     * date格式化字符串
     * @param date
     * @param fmt
     * @return
     */
    public static String date2str(Date date, String fmt) {
        SimpleDateFormat format = new SimpleDateFormat(fmt);
        return format.format(date);
    }
}

注意:属性上的注解配置优先级高于全局配置,可以根据自身需求进行搭配使用。

其他解决方案

网上搜索序列化问题,很多文章告诉你实现jackson提供的序列化和反序列化接口,代码如下:

/**
 * 自定义反序列化
 *
 * @author huaqi@liu
 * @since 2023-03-30 16:51:42
 */
public class CustomDateDeserializer extends JsonDeserializer<Date> {
    @Override
    public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        return DateUtils.str2Data(jsonParser.getText());
    }
}

/**
 * 自定义序列化
 *
 * @author huaqi@liu
 * @since 2023-03-30 16:51:42
 */
public class CustomDateSerializer extends JsonSerializer<Date> {

    @Override
    public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(DateUtils.date2str(date, "yyyy-MM-dd HH:mm:ss"));
    }
}

使用方式,只需要在需要处理的时间属性上增加序列化和反序列化注解,如下代码:

/**
 * 自定义序列化
 */
@JsonDeserialize(using = CustomDateDeserializer.class)
@JsonSerialize(using = CustomDateSerializer.class)
private Date goHomeTime;

这种实现其实和@JsonFormat处理方式差不多,都需要在每个字段上设置。

posted @ 2023-03-31 14:24  Little_Monster-lhq  阅读(183)  评论(0编辑  收藏  举报