解决全局的jackson日期转换和解析

解决全局的jackson日期转换和解析

因为项目有些特殊,需要解析各种格式的日期类型转换,后来发现jackson在日期转换上没法满足需要。
遂重写了com.fasterxml.jackson.databind.util.StdDateFormat 
和com.fasterxml.jackson.databind.DeserializationContext。
我的版本是jackson-databind-2.8.10



 
起初因为需要“yyyy-MM-dd HH:mm:ss”的日期格式直接显示,直接使用了@JsonFormat注解,设置“yyyy-MM-dd HH:mm:ss”,时区加八个小时。 
但是被注解后,不管是解析还是json串,都一律是这个格式。只要不是这个格式那就是六亲不认!比如别人的api中接收我的格式时报错“Can not parse date “xx”: not compatible with any of standard forms (xxxx,xxxx)”,我的格式接收别人的api报错 “Failed to parse Date value ‘xx’: yyyy-MM-dd HH:mm:ss”。 
于是我尝试在objectMapper中设置全局的DateFormat:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");
    }
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();

        //json中多余的参数不报错,不想要可以改掉
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //设置全局的时间转化
        SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(smt);
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));//解决时区差8小时问题


        //设置中文编码格式
        List<MediaType> list = new ArrayList<MediaType>();
        list.add(MediaType.APPLICATION_JSON_UTF8);
        jackson2HttpMessageConverter.setSupportedMediaTypes(list);


        //生成json时,将所有Long转换成String
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);

        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(0, jackson2HttpMessageConverter);
    }
}



没错,只有三句话: 

- SimpleDateFormat smt = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”); 
- objectMapper.setDateFormat(smt); 
- objectMapper.setTimeZone(TimeZone.getTimeZone(“GMT+8”)); 


剩下的全是废话。 
这样做只能起到微弱的卵用,仅仅只是让每一个date都带有JsonFormat的效果而已,于解析而言,没有任何益处。 
后经过我的不断试验,发现如果我不加任何Format的话,默认可以解析yyyy-MM-dd’T’HH:mm:ss.SSSZ、时间戳、EEE, dd MMM yyyy HH:mm:ss zzz等等一系列惨不忍睹的日期格式,经过我的不断寻找终于找到了,解析的代码所在。就是这个STDDateformat。这里我一共写了几项:

 

/**
     * TODO 自己加入,想加多少加多少
     */
    protected final static String DATE_FORMAT_STR_FIRST= "yyyy-MM-dd HH:mm:ss";
    protected final static String DATE_FORMAT_STR_SECOND= "EEE MMM dd hh:mm:ss z yyyy";`


 

/**
     * For error messages we'll also need a list of all formats.
     */
    protected final static String[] ALL_FORMATS = new String[] {
        DATE_FORMAT_STR_ISO8601,
        DATE_FORMAT_STR_ISO8601_Z,
        DATE_FORMAT_STR_ISO8601_NO_TZ,
        DATE_FORMAT_STR_RFC1123,
        DATE_FORMAT_STR_PLAIN,
            DATE_FORMAT_STR_FIRST,//把刚写的两个转换格式加入
            DATE_FORMAT_STR_SECOND
    };



 

        protected final static DateFormat DATE_FORMAT_FIRST;//也是同理,照葫芦画瓢
        protected final static DateFormat DATE_FORMAT_SECOND;
        DATE_FORMAT_FIRST = new SimpleDateFormat(DATE_FORMAT_STR_FIRST, DEFAULT_LOCALE);
        DATE_FORMAT_FIRST.setTimeZone(DEFAULT_TIMEZONE);
        DATE_FORMAT_SECOND = new SimpleDateFormat(DATE_FORMAT_STR_SECOND, DEFAULT_LOCALE);
        DATE_FORMAT_SECOND.setTimeZone(DEFAULT_TIMEZONE);
 @Override
    public Date parse(String dateStr) throws ParseException
    {
        dateStr = dateStr.trim();
        ParsePosition pos = new ParsePosition(0);

        Date dt;

        if (looksLikeISO8601(dateStr)) { // also includes "plain"
            dt = parseAsISO8601(dateStr, pos, true);
        } else {
            // Also consider "stringified" simple time stamp
            int i = dateStr.length();
            while (--i >= 0) {
                char ch = dateStr.charAt(i);
                if (ch < '0' || ch > '9') {
                    // 07-Aug-2013, tatu: And [databind#267] points out that negative numbers should also work
                    if (i > 0 || ch != '-') {
                        break;
                    }
                }
            }
            if ((i < 0)
                // let's just assume negative numbers are fine (can't be RFC-1123 anyway); check length for positive
                    && (dateStr.charAt(0) == '-' || NumberInput.inLongRange(dateStr, false))) {
                dt = new Date(Long.parseLong(dateStr));
            } else {
                // Otherwise, fall back to using RFC 1123
                dt = parseAsRFC1123(dateStr, pos);
            }
        }
        if (dt != null) {
            return dt;
        }
        /
        //这里加入解析是非常重要的一步,这个类有两个parse()方法,写在一个参数的那个parse()方法里面,
        //parseDate()建议大家直接引入别人的jar包里封装好的方法,我这里自己写是因为EEE MMM dd hh:mm:ss z yyyy
        //的格式必须要设置正确的locale才可以解析
            String [] s={DATE_FORMAT_STR_SECOND,DATE_FORMAT_STR_FIRST};
            dt = parseDate(dateStr, s,_locale);
            if (dt != null) {
                return dt;
            }
        /        StringBuilder sb = new StringBuilder();
        for (String f : ALL_FORMATS) {
            if (sb.length() > 0) {
                sb.append("\", \"");
            } else {
                sb.append('"');
            }
            sb.append(f);
        }
        sb.append('"');
        throw new ParseException
            (String.format("Can not parse date \"%s\": not compatible with any of standard forms (%s)",
                           dateStr, sb.toString()), pos.getErrorIndex());
    }


 

//虽然不是必要的,但还是将这个方法贴出来
private static Date parseDate(String str, String[] parsePatterns, Locale _locale)
            throws ParseException
    {
        if ((str == null) || (parsePatterns == null)) {
            throw new IllegalArgumentException("Date and Patterns must not be null");
        }

        SimpleDateFormat parser = null;
        ParsePosition pos = new ParsePosition(0);
        for (int i = 0; i < parsePatterns.length; i++) {
            if (i == 0)
                parser = new SimpleDateFormat(parsePatterns[0],_locale);
            else {
                parser.applyPattern(parsePatterns[i]);
            }
            pos.setIndex(0);
            Date date = parser.parse(str, pos);
            if ((date != null) && (pos.getIndex() == str.length())) {
                return date;
            }
        }
        throw new ParseException("Unable to parse the date: " + str, -1);
    }



这个时候发现不对劲
加入全局格式转换后 

Failed to parse Date value ‘xx’: yyyy-MM-dd HH:mm:ss 


明显和 

throw new ParseException (String.format(“Can not parse date \”%s\”: not compatible with any of standard forms (%s)”, 
dateStr, sb.toString()), pos.getErrorIndex()); 


报的错不一样!, 
不加类型转换,报下面这个。加了就调皮。 
鉴于我人傻头铁时间多,接着找。找到了DeserializationContext。这个类 
他的报错是

throw new IllegalArgumentException(String.format(
                    "Failed to parse Date value '%s': %s", dateStr, e.getMessage()));



这么看来应该是他没跑儿了

//修改parseDate
 public Date parseDate(String dateStr) throws IllegalArgumentException
    {
        try {
            DateFormat df = getDateFormat();
            return df.parse(dateStr);
        } catch (ParseException e) {
        //
            try {//这里加入了StdDateFormat的parse
                return new StdDateFormat().parse(dateStr);
            } catch (ParseException e1) {
                throw new IllegalArgumentException(String.format(
                    "Failed to parse Date value '%s': %s", dateStr, e.getMessage()));
            }
        //
        }
    }

 

转至:https://blog.csdn.net/qq_18493025/article/details/82227382

感谢大哥的好文章!!

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JsonFormat注解和@DateTimeFormat注解都是用于处理日期时间格式的注解。它们的主要区别在于应用的场景和使用方式。 @JsonFormat注解是在Jackson库中使用的,用于在序列化和反序列化过程中自定义日期时间的格式。通过@JsonFormat注解,我们可以指定日期时间的显示格式,例如"yyyy-MM-dd HH:mm:ss"。这个注解可以应用在类级别或属性级别上,作用于全局或特定字段。它可以用于将日期时间转换为特定的字符串格式,以及将特定的字符串格式转换日期时间对象。 @DateTimeFormat注解是Spring框架中使用的,用于绑定请求参数或表单数据到Java对象时解析日期时间。通过@DateTimeFormat注解,我们可以指定接收的日期时间的格式,例如"yyyy-MM-dd"。这个注解通常用于Controller层的方法参数上,用于将请求中的字符串日期时间解析JavaDate或LocalDateTime对象。 综上所述,JsonFormat注解主要用于序列化和反序列化过程中的日期时间格式处理,而@DateTimeFormat注解主要用于接收请求参数或表单数据时的日期时间解析。它们在不同的场景下发挥着不同的作用,但都可以帮助我们灵活地处理日期时间格式的转换。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [@JsonFormat 和 @DateTimeFormat 时间格式化注解详解(不看血亏)](https://blog.csdn.net/zhuzicc/article/details/106529485)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [@DateTimeFormat与@JsonFormat详解](https://blog.csdn.net/imVainiycos/article/details/102712056)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [JsonFormat与@DateTimeFormat注解实例解析](https://download.csdn.net/download/weixin_38691220/12930475)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值