自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

實(shí)體類JSON字段的終極轉(zhuǎn)換思路

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

哈嘍,各位代碼戰(zhàn)士們,我是Jensen,一個(gè)夢(mèng)想著和大家一起在代碼的海洋里遨游,順便撿起那些散落的知識(shí)點(diǎn)的程序員小伙伴。

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

今天看看數(shù)據(jù)庫(kù)JSON字段是怎么映射到代碼上來的。

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

一、都有些什么寫法

1.用String映射

這種是最簡(jiǎn)單最普遍的寫法,JSON不就是字符串嘛,能存能取就行了,存數(shù)據(jù)庫(kù)跟存銀行沒什么區(qū)別,數(shù)據(jù)庫(kù)存一條,銀行存一“張不夠花”。

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

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

2.用JSONObject映射

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

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

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

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

3.自定義類型處理器

其實(shí),在Mybatis這個(gè)主流ORM框架中,有這么一個(gè)抽象類:

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

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

在 MyBatis 中,類型處理器負(fù)責(zé)在 Java 類型和 JDBC 類型之間的轉(zhuǎn)換。當(dāng)你想要對(duì)某種類型進(jìn)行特殊的處理,或者 MyBatis 默認(rèn)的類型處理器不能滿足你的需求時(shí),你可以自定義一個(gè)類型處理器。

以下是 BaseTypeHandler的一些關(guān)鍵點(diǎn):

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

通過繼承 BaseTypeHandler<T> 并實(shí)現(xiàn)必要的方法,你可以完全控制數(shù)據(jù)在 Java 對(duì)象和數(shù)據(jù)庫(kù)之間的轉(zhuǎn)換過程,這為處理復(fù)雜的業(yè)務(wù)邏輯提供了靈活性。

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

不錯(cuò)不錯(cuò),就它了。

二、還是先造個(gè)輪子吧

BaseTypeHandler子類已經(jīng)支持挺多常見類型了,但我們要支持更多的類型,就必須自己寫。繼承BaseTypeHandler要覆寫的方法有點(diǎn)多,我們先封裝一輪,把核心的三個(gè)方法暴露出來:
public abstract class BaseTypeHandler<T> extends org.apache.ibatis.type.BaseTypeHandler<T> {
    /**
     * 獲取實(shí)際的類型,用于后續(xù)的類型注冊(cè)與類型判斷
     */
    public Class<T> type() {
        return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), 0);
    }
    /**
     * 把指定類型轉(zhuǎn)換為字符串類型,對(duì)應(yīng)寫庫(kù)
     */
    protected abstract String convert(T obj);
    /**
     * 把字符串類型解析成指定類型,對(duì)應(yīng)讀庫(kù)
     */
    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);
    }
}

接著,繼承這個(gè)抽象類再寫一個(gè)子抽象類:

/**
 * 自定義POJO類型轉(zhuǎn)換器父類:json/varchar <-> T
 * 繼承該類并加@Component注解,放在entity下的typehandlers目錄,PO類無需在@TableField注解上加類型處理器,能自動(dòng)轉(zhuǎn)換
 *
 * @param <T> 自定義POJO,一般以VO命名,與Model同目錄,注意T不能是List集合或Map類型,但可以是數(shù)組類型(以實(shí)現(xiàn)對(duì)對(duì)象數(shù)組的互轉(zhuǎn))
 * @author Jensen
 * @公眾號(hào) 架構(gòu)師修行錄
 */
@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();
        // 判斷具體的類型是否為數(shù)組
        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) {
        // 轉(zhuǎn)換為Json字符串
        return JsonKit.toJson(obj);
    }
    @Override
    protected T parse(String json) {
        if (this.componentType != null) {
            // Json解析為對(duì)象數(shù)組
            List<?> list = JsonKit.toList(json, this.componentType);
            if (list == null) return null;
            return (T) list.toArray(this.componentArray);
        }
        // Json解析為對(duì)象
        return JsonKit.toObject(json, type());
    }
}

這個(gè)JsonString類型解析器,既可以轉(zhuǎn)換對(duì)象,也可以轉(zhuǎn)換對(duì)象數(shù)組(注意是Array不是List),不需要再分開記了。

不要心急,還沒完成,我們還需要把所有實(shí)現(xiàn)它的類型處理器注冊(cè)到類型處理器注冊(cè)器內(nèi):

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

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

至此,大功告成!

三、看看怎么用吧

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

沒錯(cuò),就是這么定義,實(shí)體類啥都不用加了。

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

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


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

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

四、OneMoreThing

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

圖片

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

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

責(zé)任編輯:姜華 來源: 架構(gòu)師修行錄
相關(guān)推薦

2009-09-10 10:09:46

LINQ to SQL

2020-04-22 10:35:57

實(shí)體類屬性映射

2011-06-01 15:45:28

實(shí)體類序列化

2023-01-04 08:53:52

JPA實(shí)體類注解

2023-01-12 09:13:49

Mybatis數(shù)據(jù)庫(kù)

2022-04-18 09:54:37

JDK8日期前端

2025-04-07 02:33:00

項(xiàng)目開發(fā)Spring

2017-07-20 17:05:04

JavaScriptswagger-decSwagger

2011-04-26 14:21:50

MySQL

2011-04-26 15:26:38

PostgreSQL

2013-12-13 16:00:39

社交類APP設(shè)計(jì)思路產(chǎn)品經(jīng)理

2009-06-15 15:10:02

Java數(shù)據(jù)轉(zhuǎn)換JSON

2022-12-27 08:41:51

FastjsonJson字段

2024-03-11 10:07:58

2020-11-20 08:36:59

Jpa數(shù)據(jù)代碼

2021-06-28 07:09:24

MybatisresultMapJava

2009-08-13 09:33:07

JavaBean到XM

2024-10-11 16:34:22

2025-03-04 00:36:00

2009-09-28 09:56:53

Hibernate屬性
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)