最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot+MyBatisPlus對Map中Date格式轉(zhuǎn)換處理的方法詳解

 更新時間:2022年10月10日 11:12:03   作者:Milton  
在?SpringBoot?項目中,?如何統(tǒng)一?JSON?格式化中的日期格式。本文將為大家介紹一種方法:利用MyBatisPlus實現(xiàn)對Map中Date格式轉(zhuǎn)換處理,需要的可以參考一下

在 SpringBoot 項目中, 如何統(tǒng)一 JSON 格式化中的日期格式

問題

現(xiàn)在的關(guān)系型數(shù)據(jù)庫例如PostgreSQL/MySQL, 都已經(jīng)對 JSON 類型提供相當(dāng)豐富的功能, 項目中對于不需要檢索但是又需要結(jié)構(gòu)化的存儲, 會在數(shù)據(jù)庫中產(chǎn)生很多 JSON 類型的字段, 與 Jackson 做對象的序列化和反序列化配合非常方便.

如果 JSON 都是類定義的, 這個序列化和反序列化就非常透明 -- 不需要任何干預(yù), 寫進去是什么, 讀出來就是什么. 但是如果 JSON 在 Java 代碼中是定義為一個 Map, 例如 Map<String, Object> 那么就有問題了, 對于 Date 類型的數(shù)據(jù), 在存入之前是 Date, 取出來之后就變成 Long 了.

SomePO po = new SomePO();
//...
Map<String, Object> map = new HashMap<>();
map.put("k1", new Date());
po.setProperties(map);
//...
mapper.insert(po);
//...
SomePO dummy = mapper.select(po.id);
// 這里的k1已經(jīng)變成了 Long 類型
Object k1 = dummy.getProperties().get("k1");

原因

不管是使用原生的 MyBatis 還是包裝后的 MyBatis Plus, 在對 JSON 類型字段進行序列化和反序列化時, 都需要借助類型判斷, 調(diào)用對應(yīng)的處理邏輯, 大部分情況, 使用的是默認(rèn)的 Jackson 的 ObjectMapper, 而 ObjectMapper 對 Date 類型默認(rèn)的序列化方式就是取時間戳, 對于早于1970年之前的日期, 生成的是一個負(fù)的長整數(shù), 對于1970年之后的日期, 生成的是一個正的長整數(shù).

查看 ObjectMapper 的源碼, 可以看到其對Date格式的序列化和反序列化方式設(shè)置于_serializationConfig 和 _deserializationConfig 這兩個成員變量中, 可以通過 setDateFormat() 進行修改

public class ObjectMapper extends ObjectCodec implements Versioned, Serializable {
    //...
    protected SerializationConfig _serializationConfig;
    protected DeserializationConfig _deserializationConfig;
    //...

    public ObjectMapper setDateFormat(DateFormat dateFormat) {
        this._deserializationConfig = (DeserializationConfig)this._deserializationConfig.with(dateFormat);
        this._serializationConfig = this._serializationConfig.with(dateFormat);
        return this;
    }

    public DateFormat getDateFormat() {
        return this._serializationConfig.getDateFormat();
    }
}

默認(rèn)的序列化反序列化選項, 使用了一個常量 WRITE_DATES_AS_TIMESTAMPS, 在類 SerializationConfig 中進行判斷, 未指定時使用的是時間戳

public SerializationConfig with(DateFormat df) {
	SerializationConfig cfg = (SerializationConfig)super.with(df);
	return df == null ? cfg.with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) : cfg.without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}

實際的轉(zhuǎn)換工作在 SerializerProvider 類中, 轉(zhuǎn)換方法為

public final void defaultSerializeDateValue(long timestamp, JsonGenerator gen) throws IOException {
	if (this.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) {
		gen.writeNumber(timestamp);
	} else {
		gen.writeString(this._dateFormat().format(new Date(timestamp)));
	}
}

public final void defaultSerializeDateValue(Date date, JsonGenerator gen) throws IOException {
	if (this.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) {
		gen.writeNumber(date.getTime());
	} else {
		gen.writeString(this._dateFormat().format(date));
	}
}

解決

局部方案

1. 字段注解

這種方式可以用在固定的類成員變量上, 不改變整體行為

public class Event {
    public String name;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
    public Date eventDate;
}

另外還可以自定義序列化反序列化方法, 實現(xiàn) StdSerializer

public class CustomDateSerializer extends StdSerializer<Date> {
    //...
}

就可以在 @JsonSerialize 注解中使用

public class Event {
    public String name;

    @JsonSerialize(using = CustomDateSerializer.class)
    public Date eventDate;
}

2. 修改 ObjectMapper

通過 ObjectMapper.setDateFormat() 設(shè)置日期格式, 改變默認(rèn)的日期序列化反序列化行為. 這種方式只對調(diào)用此ObjectMapper的場景有效

private static ObjectMapper createObjectMapper() {
	ObjectMapper objectMapper = new ObjectMapper();
	SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	objectMapper.setDateFormat(df);
	return objectMapper;
}

因為 ObjectMapper 一般是當(dāng)作線程安全使用的, 而 SimpleDateFormat 并非線程安全, 在這里使用是否會有問題? 關(guān)于這個疑慮, 可以查看 這個鏈接

@StaxMan: I am a bit concerned if ObjectMapper is still thread-safe after ObjectMapper#setDateFormat() is called. It is known that SimpleDateFormat is not thread safe, thus ObjectMapper won't be unless it clones e.g. SerializationConfig before each writeValue() (I doubt). Could you debunk my fear? – dma_k Aug 2, 2013 at 12:09

DateFormat is indeed cloned under the hood. Good suspicion there, but you are covered. ?? – StaxMan Aug 2, 2013 at 19:43

3. 修改 SpringBoot 配置

增加配置 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss, 這種配置, 只對 Spring BeanFactory 中創(chuàng)建的 Jackson ObjectMapper有效, 例如 HTTP 請求和響應(yīng)中對 Date 類型的轉(zhuǎn)換

spring:
  ...
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss

整體方案

國內(nèi)項目, 幾乎都會希望落庫時日期就是日期的樣子(方便看數(shù)據(jù)庫表), 所謂日期的樣子就是yyyy-MM-dd HH:mm:ss格式的字符串. 如果怕麻煩, 就通通都用這個格式了.

這樣統(tǒng)一存在的隱患是丟失毫秒部分. 這個問題業(yè)務(wù)人員基本上是不會關(guān)心的. 如果需要, 就在格式中加上.

第一是 Spring 配置, 這樣所有的請求響應(yīng)都統(tǒng)一了

spring:
  ...
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss

第二是定義一個工具類, 把 ObjectMapper 自定義一下, 這樣所有手工轉(zhuǎn)換的地方也統(tǒng)一了, 注意留一個getObjectMapper()方法

public class JacksonUtil {
    private static final Logger log = LoggerFactory.getLogger(JacksonUtil.class);
    private static final ObjectMapper MAPPER = createObjectMapper();
    private JacksonUtil() {}

    private static ObjectMapper createObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(df);
        return objectMapper;
    }

    public static ObjectMapper getObjectMapper() {
        return MAPPER;
    }
}

第三是啟動后修改 MyBatisPlus 的設(shè)置, 即下面的 changeObjectMapper() 這個方法, 直接換成了上面工具類中定義的 ObjectMapper, 這樣在 MyBatis 讀寫數(shù)據(jù)庫時的格式也統(tǒng)一了.

@Configuration
@MapperScan(basePackages = {"com.somewhere.commons.impl.mapper"})
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

    @PostConstruct
    public void changeObjectMapper() {
        // This will unify the date format with util methods
        JacksonTypeHandler.setObjectMapper(JacksonUtil.getObjectMapper());
    }
}

到此這篇關(guān)于SpringBoot+MyBatisPlus對Map中Date格式轉(zhuǎn)換處理的方法詳解的文章就介紹到這了,更多相關(guān)SpringBoot MyBatisPlus處理Date格式轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot優(yōu)化接口響應(yīng)時間的九個技巧

    SpringBoot優(yōu)化接口響應(yīng)時間的九個技巧

    在實際開發(fā)中,提升接口響應(yīng)速度是一件挺重要的事,特別是在面臨大量用戶請求的時候,本文為大家整理了9個SpringBoot優(yōu)化接口響應(yīng)時間的技巧,希望對大家有所幫助
    2024-01-01
  • Spring Boot 入門指南

    Spring Boot 入門指南

    Spring Boot 簡化了Spring 應(yīng)用的初始搭建、開發(fā)過程,開發(fā)人員可使用Spring提供的特定的方式來進行配置,不再需要重復(fù)自定義樣板化的配置。本文就將帶你入門Spring Boot
    2021-05-05
  • SpringBoot整合jasypt加密配置文件敏感信息

    SpringBoot整合jasypt加密配置文件敏感信息

    在項目中我們需要對配置文件的一些敏感信息進行加密處理,比如數(shù)據(jù)庫賬戶密碼,避免直接暴露出來,這種場景常常用于生產(chǎn)環(huán)境,我們不想讓開發(fā)人員知道生產(chǎn)庫的密碼,有運維人員統(tǒng)一管理,所以本文給大家介紹了SpringBoot整合jasypt加密配置文件敏感信息
    2024-06-06
  • 詳解RabbitMq如何做到消息的可靠性投遞

    詳解RabbitMq如何做到消息的可靠性投遞

    這篇文章主要為大家介紹了RabbitMq如何做到消息的可靠性投遞,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • 基于編譯虛擬機jvm—openjdk的編譯詳解

    基于編譯虛擬機jvm—openjdk的編譯詳解

    下面小編就為大家分享一篇基于編譯虛擬機jvm—openjdk的編譯詳解,具有很好的參考價值,希望對大家有所幫助
    2017-12-12
  • 微信小程序與Java后端接口交互

    微信小程序與Java后端接口交互

    本文主要介紹了微信小程序與Java后端接口交互,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java利用Geotools實現(xiàn)不同坐標(biāo)系之間坐標(biāo)轉(zhuǎn)換

    Java利用Geotools實現(xiàn)不同坐標(biāo)系之間坐標(biāo)轉(zhuǎn)換

    GeoTools 是一個開源的 Java GIS 工具包,可利用它來開發(fā)符合標(biāo)準(zhǔn)的地理信息系統(tǒng)。本文將利用工具包Geotools實現(xiàn)不同坐標(biāo)系之間坐標(biāo)轉(zhuǎn)換,感興趣的可以了解一下
    2022-08-08
  • Java根據(jù)實體生成SQL數(shù)據(jù)庫表的示例代碼

    Java根據(jù)實體生成SQL數(shù)據(jù)庫表的示例代碼

    這篇文章主要來和大家分享一個Java實現(xiàn)根據(jù)實體生成SQL數(shù)據(jù)庫表的代碼,文中的實現(xiàn)代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-07-07
  • idea安裝漢化插件的圖文教程

    idea安裝漢化插件的圖文教程

    本文主要介紹了idea安裝漢化插件的圖文教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Java使用jxl庫輕松玩轉(zhuǎn)Excel表操作

    Java使用jxl庫輕松玩轉(zhuǎn)Excel表操作

    jxl?是一個非常實用的?Java?庫,專門用于操作?Excel?表格,這篇文章主要為大家介紹了如何使用jxl進行Excel的基本操作,有需要的可以了解下
    2025-02-02

最新評論

周口市| 澄迈县| 旬邑县| 铁力市| 鹤山市| 卓资县| 遵化市| 樟树市| 新化县| 大理市| 准格尔旗| 乌拉特前旗| 德庆县| 上杭县| 泌阳县| 台东市| 太和县| 遂宁市| 凌海市| 池州市| 泸西县| 平远县| 会东县| 平舆县| 辉县市| 高唐县| 壶关县| 永兴县| 沁水县| 保靖县| 桃园县| 临夏市| 米脂县| 沈丘县| 苗栗市| 屏南县| 望谟县| 武乡县| 龙南县| 黄陵县| 三明市|