SpringBoot中使用@RequestBody时如何自定义需要转换的日期格式

狂风中的少年 提交于 2019-11-27 05:06:38

SpringBoot(SpringMVC)序列化和反序列化Json时默认使用的是Jackson(例如使用@RequestBody反序列化前端传递过来的Json字符串时),

当我们前端使用Json字符串传递到后台时日期格式可能是时间戳(即long类型的数字),也有可能是日期字符串(如:"yyyy-MM-dd", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss")等等。

如果是时间戳或者是yyyy-MM-dd格式的日期,Jackson会自动识别并且转换成功,若是yyyy-MM-dd HH:mm:ss这种格式的日期字符串的话,Jackson无法自动转换成Date类型。

这里有几种解决方案,如下:

一.

我们可以在需要被反序列化的日期属性上添加com.fasterxml.jackson.annotation.JsonFormat注解,如下:

这个注解对于Jackson序列化以及反序列化均起作用(即将日期对象序列化成Json时格式为以上指定的格式,将Json反序列化成日期时会按照以上指定的日期格式进行解析,若日期字符串的格式不满足以上指定的格式将会直接报错)

二.

方法一我们只能指定一种日期的格式,但是我们前端可能传递各种类型的日期格式,这个时候我们需要自定义Json日期转换器,如下在日期类型的属性上添加com.fasterxml.jackson.databind.annotation.JsonDeserialize注解,如下:

其中DateJacksonConverter类是我们自定义的日期转换类,这时在反序列化时我们可以转换多种格式的日期,DateJacksonConverter类定义如下:

package com.flying.eurekaclient;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.ParseException;
import java.util.Date;

/**
 * 自定义Jackson反序列化日期类型时应用的类型转换器,一般用于@RequestBody接受参数时使用
 */
public class DateJacksonConverter extends JsonDeserializer<Date> {
    private static String[] pattern =
            new String[]{"yyyy-MM-dd", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.S",
                    "yyyy.MM.dd", "yyyy.MM.dd HH:mm", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm:ss.S",
                    "yyyy/MM/dd", "yyyy/MM/dd HH:mm", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss.S"};

    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {

        Date targetDate = null;
        String originDate = p.getText();
        if (StringUtils.isNotEmpty(originDate)) {
            try {
                long longDate = Long.valueOf(originDate.trim());
                targetDate = new Date(longDate);
            } catch (NumberFormatException e) {
                try {
                    targetDate = DateUtils.parseDate(originDate, DateJacksonConverter.pattern);
                } catch (ParseException pe) {
                    throw new IOException(String.format(
                            "'%s' can not convert to type 'java.util.Date',just support timestamp(type of long) and following date format(%s)",
                            originDate,
                            StringUtils.join(pattern, ",")));
                }
            }
        }


        return targetDate;
    }

    @Override
    public Class<?> handledType() {
        return Date.class;
    }
}

在该方法中handledType()方法可以不用重写。

三.

以上两种方法都需要在实体类上添加注解,这种方式污染了实体类,并且要是类太多的话,添加注解是一个麻烦事,这时我们可以配置全局的日期类型转换器,如下:

package com.flying.eurekaclient;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

@Configuration
public class ConverterConfig {
    @Bean
    public DateJacksonConverter dateJacksonConverter() {
        return new DateJacksonConverter();
    }

    @Bean
    public Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean(
            @Autowired
                    DateJacksonConverter dateJacksonConverter) {
        Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean();

        jackson2ObjectMapperFactoryBean.setDeserializers(dateJacksonConverter);
        return jackson2ObjectMapperFactoryBean;
    }

    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
            @Autowired
                    ObjectMapper objectMapper) {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter =
                new MappingJackson2HttpMessageConverter();
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        return mappingJackson2HttpMessageConverter;
    }
}

采用这种方式我们自定义的DateJacksonConverter必须重写handledType()方法。

本人推荐采用方式三,这样不用污染实体类。

以下附上方式三的xml文件配置(若没有使用SpringBoot的话):

Tips:

1.关于使用SpringMVC接受前端传递过来的QueryParameter数据(即后台使用@RequestParam接收)或者formdata数据(后台采用@RequestParam或者直接用对象接收),

若其中存在日期数据,则可以采用以下博客提到的方式进行日期类型的正确转换:

https://my.oschina.net/u/2608182/blog/713435

2.关于Jackson的基本用法参考:https://my.oschina.net/u/2608182/blog/731403

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!