成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

實體類JSON字段的終極轉換思路

數據庫 其他數據庫
這種是最簡單最普遍的寫法,JSON不就是字符串嘛,能存能取就行了,存數據庫跟存銀行沒什么區別,數據庫存一條,銀行存一“張不夠花”。前后端要用?對不起,自己解析去吧,用Json工具類,轉完七七四十九遍以后,別把這個字符串玩壞就行。

哈嘍,各位代碼戰士們,我是Jensen,一個夢想著和大家一起在代碼的海洋里遨游,順便撿起那些散落的知識點的程序員小伙伴。

聽說大家都不愛當“接碼俠”,筆者在接盤別人代碼之時也常意難平,我的心情大部分是這樣的:

今天看看數據庫JSON字段是怎么映射到代碼上來的。

本文涉及技術棧:類型處理器、D3Boot。

一、都有些什么寫法

1.用String映射

這種是最簡單最普遍的寫法,JSON不就是字符串嘛,能存能取就行了,存數據庫跟存銀行沒什么區別,數據庫存一條,銀行存一“張不夠花”。

前后端要用?對不起,自己解析去吧,用Json工具類,轉完七七四十九遍以后,別把這個字符串玩壞就行。

完了以后,隔壁組的數據分析獅張開了她的獠牙看向你……

2.用JSONObject映射

那我用世界500強公司的com.alibaba.fastjson.JSONObject總可以了吧。

可以是可以,但麻煩是真麻煩,取元素出來還得轉換成具體的類型,只能通過字符串Key取值,還得引入個fastjson包,對于沒什么阿里信仰的同學可能不是那么的友好。

Hutool包也有個同類名的cn.hutool.json.JSONObject,一不小心把兩個給搞混就GG了。

要是再遇到你的同類把一個實體從頭傳到尾,再作為DTO提供Jar包出去就……

3.自定義類型處理器

其實,在Mybatis這個主流ORM框架中,有這么一個抽象類:

org.apache.ibatis.type.BaseTypeHandler<T>

它是 MyBatis 框架中一個非常重要的類,它提供了一個通用的基類,用于自定義類型處理器(TypeHandler)。

在 MyBatis 中,類型處理器負責在 Java 類型和 JDBC 類型之間的轉換。當你想要對某種類型進行特殊的處理,或者 MyBatis 默認的類型處理器不能滿足你的需求時,你可以自定義一個類型處理器。

以下是 BaseTypeHandler的一些關鍵點:

  1. 泛型:BaseTypeHandler<T> 使用泛型 T 來指定它所處理的 Java 類型。
  2. 繼承:自定義類型處理器通常繼承自 BaseTypeHandler<T>,并且重寫幾個核心方法。
  3. 核心方法——void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType):此方法用于將 Java 類型設置到 SQL 語句的參數中。
  4. 核心方法——T getResult(ResultGetter getter, Class<T> clazz):此方法用于從 SQL 查詢的結果集中獲取 Java 類型。
  5. 類型轉換:BaseTypeHandler 的子類可以實現具體的類型轉換邏輯,包括日期時間格式的轉換、枚舉類型的轉換、復雜對象的序列化和反序列化等。
  6. 配置:自定義的類型處理器可以在 MyBatis 的映射文件中配置,與特定的字段或結果集映射相關聯。
  7. 重用:由于 BaseTypeHandler 是泛型的,因此可以為不同的類型創建不同的處理器,同時重用相同的處理邏輯。

通過繼承 BaseTypeHandler<T> 并實現必要的方法,你可以完全控制數據在 Java 對象和數據庫之間的轉換過程,這為處理復雜的業務邏輯提供了靈活性。

通過類型處理器,我們可以映射成任意類型,存取數據其實沒有那么的麻煩。

不錯不錯,就它了。

二、還是先造個輪子吧

BaseTypeHandler子類已經支持挺多常見類型了,但我們要支持更多的類型,就必須自己寫。繼承BaseTypeHandler要覆寫的方法有點多,我們先封裝一輪,把核心的三個方法暴露出來:
public abstract class BaseTypeHandler<T> extends org.apache.ibatis.type.BaseTypeHandler<T> {
    /**
     * 獲取實際的類型,用于后續的類型注冊與類型判斷
     */
    public Class<T> type() {
        return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), 0);
    }
    /**
     * 把指定類型轉換為字符串類型,對應寫庫
     */
    protected abstract String convert(T obj);
    /**
     * 把字符串類型解析成指定類型,對應讀庫
     */
    protected abstract T parse(String result);
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) return;
        ps.setString(i, this.convert(parameter));
    }
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String str = rs.getString(columnName);
        return str == null || str.isEmpty() ? null : this.parse(str);
    }
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String str = rs.getString(columnIndex);
        return str == null || str.isEmpty() ? null : this.parse(str);
    }
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String str = cs.getString(columnIndex);
        return str == null || str.isEmpty() ? null : this.parse(str);
    }
}

接著,繼承這個抽象類再寫一個子抽象類:

/**
 * 自定義POJO類型轉換器父類:json/varchar <-> T
 * 繼承該類并加@Component注解,放在entity下的typehandlers目錄,PO類無需在@TableField注解上加類型處理器,能自動轉換
 *
 * @param <T> 自定義POJO,一般以VO命名,與Model同目錄,注意T不能是List集合或Map類型,但可以是數組類型(以實現對對象數組的互轉)
 * @author Jensen
 * @公眾號 架構師修行錄
 */
@Slf4j(topic = "### BASE-DATA : TypeHandlers ###")
public abstract class JsonStringTypeHandler<T> extends BaseTypeHandler<T> {
    private Class<?> componentType;
    private Object[] componentArray;
    public JsonStringTypeHandler() {
        Class<T> tClass = type();
        // 判斷具體的類型是否為數組
        if (tClass.isArray()) {
            Class<Object[]> arrayClass = (Class<Object[]>) tClass;
            this.componentType = arrayClass.getComponentType();
            this.componentArray = (Object[]) Array.newInstance(componentType, 0);
        }
        log.info("Loading {}, type: {}", this.getClass().getSimpleName(), type().getSimpleName());
    }
    @Override
    protected String convert(T obj) {
        // 轉換為Json字符串
        return JsonKit.toJson(obj);
    }
    @Override
    protected T parse(String json) {
        if (this.componentType != null) {
            // Json解析為對象數組
            List<?> list = JsonKit.toList(json, this.componentType);
            if (list == null) return null;
            return (T) list.toArray(this.componentArray);
        }
        // Json解析為對象
        return JsonKit.toObject(json, type());
    }
}

這個JsonString類型解析器,既可以轉換對象,也可以轉換對象數組(注意是Array不是List),不需要再分開記了。

不要心急,還沒完成,我們還需要把所有實現它的類型處理器注冊到類型處理器注冊器內:

/**
 * Mybatis 配置
 *
 * @author Jensen
 * @公眾號 架構師修行錄
 **/
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(DataSource.class)
@AllArgsConstructor
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisConfiguration.class})
public class MybatisPlusConfig implements InitializingBean {
    final MybatisPlusProperties mybatisPlusProperties;
    // 把所有實現了BaseTypeHandler的子類都注入進來
    final List<BaseTypeHandler> jsonStringTypeHandlers;
    @Override
    public void afterPropertiesSet() {
        MybatisConfiguration configuration = mybatisPlusProperties.getConfiguration();
        if (configuration == null) {
            configuration = new MybatisConfiguration();
            mybatisPlusProperties.setConfiguration(configuration);
        }
        // 核心的注冊邏輯
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        // JavaObject、JavaArray
        if (jsonStringTypeHandlers != null && !jsonStringTypeHandlers.isEmpty()) {
            for (BaseTypeHandler baseTypeHandler : jsonStringTypeHandlers) {
                typeHandlerRegistry.register(baseTypeHandler.type(), baseTypeHandler);
            }
        }
    }
}

這里用到了Spring的依賴注入,一次注入多個Bean(記筆記,又是一個解耦神器),后續實現的自定義類型處理器只需要受Spring管理就行了。

至此,大功告成!

三、看看怎么用吧

比如訂單表存了用戶快照和商品列表快照:
@Data
@TableName("order_info")
public class OrderInfo {
    // 用戶快照
    private UserInfoVO userInfo;
    // 商品列表快照
    private GoodsSpuVO[] goodsSpus;
}

沒錯,就是這么定義,實體類啥都不用加了。

但我們還是要另外針對性加兩個類型處理器,只是這個類型處理器是不需要被實體類依賴的,隨便你放哪兒都行,我把它們安放在entity.typehandlers目錄下:

@Component
public class UserInfoTypeHandler extends JsonStringTypeHandler<UserInfoVO> {
  // 類名隨便起,啥都不用寫,加個@Component受Spring管理就行了
}


@Component
public class GoodsSpusTypeHandler extends JsonStringTypeHandler<GoodsSpuVO[]> {
  // 類名隨便起,啥都不用寫,加個@Component受Spring管理就行了
}

好了,咱就是說,以后再也不需要煩怎么存取的問題了,有道是,有頭發誰要吃咖喱?

四、OneMoreThing

以上是筆者研究了一段時間磨出來的方案,遺憾的是JSON對象數組的解析只能通過數組的方式,研究了很久都沒能映射到List類型,大概是Mybatis的鍋,大家如果有思路可以在評論區告訴我,我一定往厚里謝。除了{"k","v"}、[{"k","v"}]這兩種常用存儲形式,我們還會經常用到別的自定義存儲格式,如["xxx","xxx"]、[12.3, 45.6]、aaa,bbb等,并不能用上面的類型處理器,我把其他的類型處理器集成到了D3Boot框架的BASE-DATA組件內,大家需要的話可以移步Gitee抄作業。

圖片

Gitee源碼地址:https://gitee.com/jensvn/d3boot。

今天又是干貨滿滿的一天,果然在程序員的眼里,對象是最好處理的。

責任編輯:姜華 來源: 架構師修行錄
相關推薦

2009-09-10 10:09:46

LINQ to SQL

2020-04-22 10:35:57

實體類屬性映射

2011-06-01 15:45:28

實體類序列化

2023-01-04 08:53:52

JPA實體類注解

2023-01-12 09:13:49

Mybatis數據庫

2022-04-18 09:54:37

JDK8日期前端

2025-04-07 02:33:00

項目開發Spring

2017-07-20 17:05:04

JavaScriptswagger-decSwagger

2011-04-26 15:26:38

PostgreSQL

2011-04-26 14:21:50

MySQL

2013-12-13 16:00:39

社交類APP設計思路產品經理

2009-06-15 15:10:02

Java數據轉換JSON

2022-12-27 08:41:51

FastjsonJson字段

2024-03-11 10:07:58

2021-06-28 07:09:24

MybatisresultMapJava

2020-11-20 08:36:59

Jpa數據代碼

2024-10-11 16:34:22

2009-09-28 09:56:53

Hibernate屬性

2025-03-04 00:36:00

2009-08-13 09:33:07

JavaBean到XM
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区日韩精品 | 毛片一级片 | 91在线看片 | 免费在线一区二区 | 网址黄 | 国产免费视频 | 国内精品视频在线观看 | 91精品中文字幕一区二区三区 | 久久一区二区视频 | 中文字幕在线视频网站 | 日日夜夜狠狠操 | 午夜精品久久久久久久久久久久 | 黄网站免费观看 | www.亚洲成人网 | www久久久| 国产伦精品一区二区三区精品视频 | 91久久久久 | 亚洲精品国产成人 | 黄色在线观看网址 | 亚洲免费观看视频网站 | 亚洲午夜av久久乱码 | 精品国产乱码久久久久久影片 | 亚洲精品福利在线 | 欧美精品久久久 | 日日久 | 欧美国产亚洲一区二区 | 国产精品久久久久久av公交车 | 久久99精品久久久久婷婷 | 欧美精品一区二区三区四区 在线 | 黑人精品| 91高清免费观看 | 亚洲成人一区 | 久久国产一区二区 | 一区二区国产精品 | 最新免费视频 | 亚洲成人免费 | 国产精品v | 久久aⅴ乱码一区二区三区 亚洲欧美综合精品另类天天更新 | 欧美二级 | 免费在线看a | 欧美一级在线观看 |