溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot?JSON全局日期格式轉(zhuǎn)換器如何實現(xiàn)

發(fā)布時間:2023-04-17 15:16:03 來源:億速云 閱讀:150 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“SpringBoot JSON全局日期格式轉(zhuǎn)換器如何實現(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“SpringBoot JSON全局日期格式轉(zhuǎn)換器如何實現(xiàn)”吧!

    需求

    前臺有日期字符串的數(shù)據(jù),提交到后臺。后臺實體類使用Date屬性接收。
    日期字符串有多種格式,需要用一個轉(zhuǎn)換器將合法的日期字符串格式轉(zhuǎn)換為Date類型。

    分析

    當前臺的提交數(shù)據(jù)的Content-Typeapplication/json;charset=utf-8,后臺使用@RequestBody來接收數(shù)據(jù)的時候,使用此轉(zhuǎn)換方式。

    一. 前期準備

    1.1 日期正則注解

    用來標記日期字符串所對應的正則表達式

    import java.lang.annotation.*;
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface DatePattern {
    	
        String value();
    }

    1.2 日期格式定數(shù)

    指定所有支持的日期格式

    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 日期轉(zhuǎn)換工具類

    • 從日期格式定數(shù)類中獲取所有的屬性值和該屬性上所標記的正則注解,通過反射來映射為map。

    • 如果有需要增刪的日期格式的話,只需要修改日期格式定數(shù)即可,便于維護。

    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<>();
    
        // 使用靜態(tài)代碼塊,可以保證只初始化一次
        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());
            }
        }
    	
    	// 用所有可能支持的格式將日期字符串轉(zhuǎn)換為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;
        }
    	
    	// 通過指定的格式將日期字符串轉(zhuǎn)換為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方法

    • 該方式的要點是通過繼承DateDeserializer類,然后重寫_parseDate方法實現(xiàn)轉(zhuǎn)換功能

    • 自定義的GlobalDateDeserializer類需要添加到自定義的SimpleModule模塊中,然后將模塊添加到ObjectMapper中,通過jackson來實現(xiàn)轉(zhuǎn)換。

    • 通過設置ObjectMapper對象的setDateFormat方法來實現(xiàn)后臺數(shù)據(jù)返回到前臺時的Date轉(zhuǎn)String的默認格式。

    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 {
    
        /*
         * 自定義的全局的日期轉(zhuǎn)換解析類,需要繼承jackson包中的DateDeserializer
         * 因為此類不會在別的地方使用了,因此直接使用內(nèi)部類聚合到自定義的配置文件中
         */
        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) {
    
            // 創(chuàng)建jackson對象
            ObjectMapper jackson = builder.createXmlMapper(false).build();
    
            /*
             * DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
             * 在進行序列化或者反序列化的時候,
             * JSON字符串中有一個字段,但是我們的對象沒有這個字段的時候,該怎么處理
             * 設置為true的時候,會拋出異常
             * 設置為false,忽略異常繼續(xù)處理
             */
            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);
    
             /*
             * 設置序列化時的默認格式,即后臺返回數(shù)據(jù)到前臺的時候,
             * Date類型數(shù)據(jù)需要轉(zhuǎn)換為的字符串格式
             * 如果不進行指定的話,默認使用 yyyy-MM-dd'T'HH:mm:ss.SSS 格式
             */
            DateFormat dateFormat = new SimpleDateFormat(DateFormatPart.YYYYMMDD_HHMMSS_SLASH);
            jackson.setDateFormat(dateFormat);
    
            // 創(chuàng)建一個模塊,指定該模塊是用來解析 Date.class 類型數(shù)據(jù)的
            SimpleModule newModule = new SimpleModule("GlobalDateDeserializer", PackageVersion.VERSION);
            // 將我們創(chuàng)建的全局日期轉(zhuǎn)換類添加到模塊中,指定轉(zhuǎn)換Date類型
            newModule.addDeserializer(Date.class, new CustomConfig.GlobalDateDeserializer());
            // 將該模塊添加到jackson中
            jackson.registerModule(newModule);
    
            return jackson;
        }
    }

    三. 方式2-繼承StdDateFormat類,重寫方法

    • parse方法用來將日期字符串轉(zhuǎn)換為Date(前臺向后臺傳數(shù)據(jù))

    • format方法用來將Date格式的數(shù)據(jù)轉(zhuǎn)換為指定格式的字符串(后臺向前臺傳數(shù)據(jù))。

    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 {
    
        // 靜態(tài)初始化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);
        }
    	
    	// 使用自定義的日期轉(zhuǎn)換工具類將所有可能支持的日期字符串轉(zhuǎn)換為Date格式
        private Date getDate(String dateStr) {
            return DateUtil.formatDateStrToDateAllFormat(dateStr);
        }
        
    	/*
       	 * 設置序列化時的默認格式,即后臺返回數(shù)據(jù)到前臺的時候,
         * Date類型數(shù)據(jù)需要轉(zhuǎn)換為的字符串格式
         * 如果不進行指定的話,默認使用 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格式 全局日期轉(zhuǎn)換器配置
        @Bean
        public MappingJackson2HttpMessageConverter createMappingJackson2HttpMessageConverter() {
    
            /*
             * 通過MappingJackson2HttpMessageConverter得到的ObjectMapper,
             * 已經(jīng)默認把 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 給關閉了
             */
            MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
            jacksonConverter.getObjectMapper().setDateFormat(GlobalJsonDateConvert.instance);
    
            return jacksonConverter;
        }
    }

    3.2 ObjectMapper方式

    通過Jackson2ObjectMapperBuilder創(chuàng)建ObjectMapper對象,然后將我們定義的轉(zhuǎn)換器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方式

    將我們定義的轉(zhuǎn)換器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

    // 向后臺傳輸?shù)膉son數(shù)據(jù)
    const jsonData = {
    	// ????待處理的日期字符串數(shù)據(jù)
        birthday: '2027年12月12日',
        nameAA: 'jiafeitian',
        hobby: '吃飯'
    };
    
    $.ajax({
        url: url,
        type: 'POST',
        // 對象轉(zhuǎn)換為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類型的數(shù)據(jù)
        private Date birthday;
    }

    可以看到前臺提交的日期字符串被轉(zhuǎn)換為Date格式了

    SpringBoot?JSON全局日期格式轉(zhuǎn)換器如何實現(xiàn)

    感謝各位的閱讀,以上就是“SpringBoot JSON全局日期格式轉(zhuǎn)換器如何實現(xiàn)”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對SpringBoot JSON全局日期格式轉(zhuǎn)換器如何實現(xiàn)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI