SpringBoot JSON全局日期格式转换器如何实现

发布时间:2023-04-17 15:16:03 作者:iii
来源:亿速云 阅读:186

这篇文章主要讲解了“SpringBoot JSON全局日期格式转换器如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot JSON全局日期格式转换器如何实现”吧!

需求

前台有日期字符串的数据,提交到后台。后台实体类使用Date属性接收。
日期字符串有多种格式,需要用一个转换器将合法的日期字符串格式转换为Date类型。

分析

当前台的提交数据的Content-Typeapplication/json;charset=utf-8,后台使用@RequestBody来接收数据的时候,使用此转换方式。

一. 前期准备

1.1 日期正则注解

用来标记日期字符串所对应的正则表达式

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface DatePattern {
	
    String value();
}

1.2 日期格式定数

指定所有支持的日期格式

public final class DateFormatPart {

	@DatePattern("^\\d{4}$")
	public static final String YYYY = "yyyy";

	@DatePattern("^\\d{4}\\d{2}$")
	public static final String YYYYMM = "yyyyMM";

	@DatePattern("^\\d{4}/\\d{2}$")
	public static final String YYYYMM_SLASH = "yyyy/MM";

	@DatePattern("^\\d{4}\\d{1,2}\\d{1,2}$")
	public static final String YYYYMMDD = "yyyyMMdd";

	@DatePattern("^\\d{4}/\\d{2}/\\d{2}$")
	public static final String YYYYMMDD_SLASH = "yyyy/MM/dd";

	@DatePattern("[0-9]+\\u5e74[0-9]+\\u6708[0-9]+\\u65e5$")
	public static final String YYYYMMDD_JP = "yyyy年MM月dd日";

    @DatePattern("^\\d{4}\\d{1,2}\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}$")
	public static final String YYYYMMDD_HHMMSS = "yyyyMMdd HH:mm:ss";

    @DatePattern("^\\d{4}/\\d{2}/\\d{2} \\d{1,2}:\\d{1,2}:\\d{1,2}$")
	public static final String YYYYMMDD_HHMMSS_SLASH = "yyyy/MM/dd HH:mm:ss";
}

1.3 日期转换工具类

import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public final class DateUtil {

    // 日期格式 <==> 正则的map,使用LinkedHashMap可以避免按照顺序匹配正则表达式
    private static final Map<String, String> datePatternMap = new LinkedHashMap<>();

    // 日期格式List
    private static final List<String> dateFormatList = new ArrayList<>();

    // 使用静态代码块,可以保证只初始化一次
    static {

        Class<DateFormatPart> dateFormatClass = DateFormatPart.class;
        // 获取所有的属性
        Field[] fields = dateFormatClass.getFields();
        for (Field field : fields) {

            // 获取属性上的注解
            DatePattern annotation = field.getAnnotation(DatePattern.class);
            if (ObjectUtils.isEmpty(annotation)) {
                continue;
            }

            //  强制让属性可以访问
            ReflectionUtils.makeAccessible(field);

            // 日期格式化字符串
            String dateFormatStr = "";
            try {
                // 获取当前属性所对应的属性值
                dateFormatStr = (String)field.get(dateFormatClass);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

            dateFormatList.add(dateFormatStr);

            // 将该属性的属性值和属性上的正则表达式放到map中
            datePatternMap.put(dateFormatStr, annotation.value());
        }
    }
	
	// 用所有可能支持的格式将日期字符串转换为Date格式
    public static Date formatDateStrToDateAllFormat(String dateStr) {

        if (ObjectUtils.isEmpty(dateStr)) {
            return null;
        }

        try {
            for (Map.Entry<String, String> mapEntry : datePatternMap.entrySet()) {
				
				// 如果当前日期字符串不符合当前正则的话
                if (!dateStr.matches(mapEntry.getValue())) {
                    continue;
                }

                return DateUtil.formatStringToDate(dateStr, mapEntry.getKey());
            }
        } catch (ParseException e) {
            return null;
        }

        return null;
    }
	
	// 通过指定的格式将日期字符串转换为Date类型
    public static Date formatStringToDate(String dateStr, String format) throws ParseException {

        if (ObjectUtils.isEmpty(dateStr) || !dateFormatList.contains(format)) {
            return null;
        }

        SimpleDateFormat time = new SimpleDateFormat(format);
        return time.parse(dateStr);
    }
}

二. 方式1-继承DateDeserializer类,重写_parseDate方法

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.json.PackageVersion;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.deser.std.DateDeserializers.DateDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

@Configuration
public class CustomConfig {

    /*
     * 自定义的全局的日期转换解析类,需要继承jackson包中的DateDeserializer
     * 因为此类不会在别的地方使用了,因此直接使用内部类聚合到自定义的配置文件中
     */
    private static final class GlobalDateDeserializer extends DateDeserializer {

        @Override
        protected Date _parseDate(JsonParser jp, DeserializationContext context) throws IOException {

            return DateUtil.formatDateStrToDateAllFormat(jp.getText());
        }
    }

    @Bean("objectMapper")
    @Primary
    @ConditionalOnMissingBean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {

        // 创建jackson对象
        ObjectMapper jackson = builder.createXmlMapper(false).build();

        /*
         * DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
         * 在进行序列化或者反序列化的时候,
         * JSON字符串中有一个字段,但是我们的对象没有这个字段的时候,该怎么处理
         * 设置为true的时候,会抛出异常
         * 设置为false,忽略异常继续处理
         */
        jackson.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 禁用默认的「yyyy-MM-dd'T'HH:mm:ss.SSS」UTC类型
        jackson.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

         /*
         * 设置序列化时的默认格式,即后台返回数据到前台的时候,
         * Date类型数据需要转换为的字符串格式
         * 如果不进行指定的话,默认使用 yyyy-MM-dd'T'HH:mm:ss.SSS 格式
         */
        DateFormat dateFormat = new SimpleDateFormat(DateFormatPart.YYYYMMDD_HHMMSS_SLASH);
        jackson.setDateFormat(dateFormat);

        // 创建一个模块,指定该模块是用来解析 Date.class 类型数据的
        SimpleModule newModule = new SimpleModule("GlobalDateDeserializer", PackageVersion.VERSION);
        // 将我们创建的全局日期转换类添加到模块中,指定转换Date类型
        newModule.addDeserializer(Date.class, new CustomConfig.GlobalDateDeserializer());
        // 将该模块添加到jackson中
        jackson.registerModule(newModule);

        return jackson;
    }
}

三. 方式2-继承StdDateFormat类,重写方法

import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.fasterxml.jackson.databind.util.StdDateFormat;

public class GlobalJsonDateConvert extends StdDateFormat {

    // 静态初始化final,共享
    public static final GlobalJsonDateConvert instance = new GlobalJsonDateConvert();

    // 日期字符串解析为日期
    @Override
    public Date parse(String dateStr, ParsePosition pos) {
        return getDate(dateStr);
    }

    @Override
    public Date parse(String dateStr) {
        return getDate(dateStr);
    }
	
	// 使用自定义的日期转换工具类将所有可能支持的日期字符串转换为Date格式
    private Date getDate(String dateStr) {
        return DateUtil.formatDateStrToDateAllFormat(dateStr);
    }
    
	/*
   	 * 设置序列化时的默认格式,即后台返回数据到前台的时候,
     * Date类型数据需要转换为的字符串格式
     * 如果不进行指定的话,默认使用 yyyy-MM-dd'T'HH:mm:ss.SSS 格式
     */
    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition){
        SimpleDateFormat sdf = new SimpleDateFormat(DateFormatPart.YYYYMMDD_HHMMSS_SLASH);
        return sdf.format(date, toAppendTo, fieldPosition);
    }

    @Override
    public GlobalJsonDateConvert clone() {
        super.clone();
        return new GlobalJsonDateConvert();
    }
}

3.1 MappingJackson2HttpMessageConverter方式

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

@Configuration
public class CustomConfig {

    // JSON格式 全局日期转换器配置
    @Bean
    public MappingJackson2HttpMessageConverter createMappingJackson2HttpMessageConverter() {

        /*
         * 通过MappingJackson2HttpMessageConverter得到的ObjectMapper,
         * 已经默认把 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 给关闭了
         */
        MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
        jacksonConverter.getObjectMapper().setDateFormat(GlobalJsonDateConvert.instance);

        return jacksonConverter;
    }
}

3.2 ObjectMapper方式

通过Jackson2ObjectMapperBuilder创建ObjectMapper对象,然后将我们定义的转换器GlobalJsonDateConvert放到ObjectMapper对象中

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@Configuration
public class CustomConfig {

    @Bean("objectMapper")
    @Primary
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
		
        ObjectMapper objectMapper = builder.build();
        objectMapper.setDateFormat(GlobalJsonDateConvert.instance);
        return objectMapper;
    }
}

3.3 Jackson2ObjectMapperBuilder方式

将我们定义的转换器GlobalJsonDateConvert放到Jackson2ObjectMapperBuilder对象中

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@Configuration
public class CustomConfig {

    @Bean
    public Jackson2ObjectMapperBuilder objectMapper() {

        Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder = new Jackson2ObjectMapperBuilder();
        jackson2ObjectMapperBuilder.dateFormat(GlobalJsonDateConvert.instance);
        return jackson2ObjectMapperBuilder;
    }
}

四. 效果

⏹前台JS

// 向后台传输的json数据
const jsonData = {
	// ????待处理的日期字符串数据
    birthday: '2027年12月12日',
    nameAA: 'jiafeitian',
    hobby: '吃饭'
};

$.ajax({
    url: url,
    type: 'POST',
    // 对象转换为json字符串
    data: JSON.stringify(jsonData),
    contentType: "application/json;charset=utf-8",
    success: function (data, status, xhr) {
        console.log(data);
    }
});

⏹后台Form

import lombok.Data;
import java.util.Date;

@Data
public class Test15Form {

    private String name;

    private String hobby;

    private String address;
	
	// 用来接收的Date类型的数据
    private Date birthday;
}

可以看到前台提交的日期字符串被转换为Date格式了

SpringBoot JSON全局日期格式转换器如何实现

感谢各位的阅读,以上就是“SpringBoot JSON全局日期格式转换器如何实现”的内容了,经过本文的学习后,相信大家对SpringBoot JSON全局日期格式转换器如何实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. springboot vue项目管理前后端怎么实现编辑功能
  2. 怎么用springboot vue接口测试前端模块树和接口列表

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot json

上一篇:Spring整合JUnit的方法是什么

下一篇:JavaScript中高级语法??表达式怎么使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》