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

MyBatis 擴(kuò)展BaseTypeHandler 轉(zhuǎn)換泛型 JSON 列表的解決方法

 更新時間:2025年12月18日 08:48:04   作者:Milton  
本文詳細(xì)介紹了MyBatis中處理JSON轉(zhuǎn)換的bug及其解決方法,文章還介紹了如何處理抽象類和自定義對象的JSON轉(zhuǎn)換,并提供了一個基類AbstractListTypeHandler作為示例,最后,文章附上了MyBatis內(nèi)建的javaTypeAlias鏈接,感興趣的朋友跟隨小編一起看看吧

最近發(fā)現(xiàn)一個mybatis里面json轉(zhuǎn)換的bug, 寫了這么多年Java這方面還是沒有理清楚, 把正確的處理方法記錄一下.

一. 對象JSON轉(zhuǎn)換

這個是比較簡單的情況, 有通用的處理方法, 例如

用Jackson實現(xiàn)一個通用的 TypeHandler

@Slf4j
public class JacksonTypeHandler<T> extends BaseTypeHandler<T> {
private static ObjectMapper OBJECT_MAPPER;
private final Class<T> clazz;
public JacksonTypeHandler(Class<T> clazz) {
if (log.isTraceEnabled()) {
log.trace("JacksonTypeHandler[{}]", clazz);
}
this.clazz = clazz;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, toJson(parameter));
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
return parse(rs.getString(columnName));
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return parse(rs.getString(columnIndex));
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return parse(cs.getString(columnIndex));
}
protected T parse(String json) {
if (json == null || json.isEmpty()) return null;
try {
return getObjectMapper().readValue(json, clazz);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected String toJson(T obj) {
try {
return getObjectMapper().writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
private static ObjectMapper getObjectMapper() {
if (null == OBJECT_MAPPER) {
OBJECT_MAPPER = new ObjectMapper();
OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
return OBJECT_MAPPER;
}
}

使用時直接指定 typeHandler 就行

<result property="groupFilter" column="group_filter" typeHandler="com.somewhere.mybatis.JacksonTypeHandler"/>

以及

#{groupFilter, typeHandler=com.somewhere.mybatis.JacksonTypeHandler},

二. 列表JSON Array轉(zhuǎn)換

字段中更常見的是 List 類型的JSON Array結(jié)構(gòu), 這種情況通過擴(kuò)展 BaseTypeHandler 沒有通用的處理方法, 有兩種實現(xiàn)途徑

通用的TypeHandler, 需要指定javaType

用 Jackson 實現(xiàn)一個通用的 TypeHandler, 注意構(gòu)造函數(shù)中的 clazz, 如果不指定, 在默認(rèn)情況下 mybatis 傳進(jìn)來的是一個不帶泛型參數(shù)的 List

@Slf4j
public class JacksonListTypeHandler<T> extends BaseTypeHandler<List<T>> {
private static ObjectMapper OBJECT_MAPPER;
private final TypeReference<List<T>> type;
public JacksonListTypeHandler(Class<T> clazz) {
log.info("JacksonListTypeHandler[{}]", clazz);
this.type = new TypeReference<>() {
@Override
public Type getType() {
// 返回參數(shù)化類型 List<T>
return new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[]{clazz};
}
@Override
public Type getRawType() {
return List.class;
}
@Override
public Type getOwnerType() {
return null;
}
};
}
};
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<T> parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, toJson(parameter));
}
@Override
public List<T> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return parse(rs.getString(columnName));
}
@Override
public List<T> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return parse(rs.getString(columnIndex));
}
@Override
public List<T> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return parse(cs.getString(columnIndex));
}
private List<T> parse(String json) {
if (json == null || json.isEmpty()) return null;
try {
return getObjectMapper().readValue(json, type);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected String toJson(List<T> obj) {
try {
return getObjectMapper().writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static ObjectMapper getObjectMapper() {
if (null == OBJECT_MAPPER) {
OBJECT_MAPPER = new ObjectMapper();
OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
return OBJECT_MAPPER;
}
}

除了用 TypeReference, 還可以用 JavaType

@Slf4j
public class ListJacksonTypeHandler<T> extends BaseTypeHandler<List<T>> {
private final JavaType type;
public ListJacksonTypeHandler(Class<T> clazz) {
log.info("ListJacksonTypeHandler[{}]", clazz);
// 創(chuàng)建 List<T> 類型的 JavaType
this.type = JacksonUtil.getObjectMapper()
.getTypeFactory()
.constructCollectionType(List.class, clazz);
}
// 其它一樣
}

需要在 mapper 中強(qiáng)制指定javaType, 如果是MyBatis自帶的簡單類型, 可以直接用 alias(見下面的表格), 如果是自定義的對象, 則需要用對象類的完整包路徑

<result property="ips" column="ips" javaType="string" typeHandler="com.somewhere.mybatis.JacksonListTypeHandler"/>

以及

#{users,javaType=string,typeHandler=com.somewhere.mybatis.JacksonListTypeHandler},

這樣啟動后, 如果初始化的type是正確的string 才能正確解析

2025-12-15T10:33:42.896+08:00 INFO 1 --- [some-service] [main] c.somewhere.mybatis.JacksonListTypeHandler: JacksonListTypeHandler[class java.lang.String]

抽象類, 根據(jù)對象類型實現(xiàn)具體的 TypeHandler

如果不在 mapper 中指定類型, 就需要在 TypeHandler 中指定, 這樣就不是通用的了

寫一個基類 AbstractListTypeHandler

@Slf4j
public abstract class AbstractListTypeHandler<T> extends BaseTypeHandler<List<T>> {
private static ObjectMapper OBJECT_MAPPER;
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<T> parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, toJson(parameter));
}
@Override
public List<T> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return parse(rs.getString(columnName));
}
@Override
public List<T> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return parse(rs.getString(columnIndex));
}
@Override
public List<T> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return parse(cs.getString(columnIndex));
}
protected List<T> parse(String json) {
if (json == null || json.isEmpty()) return null;
try {
return getObjectMapper().readValue(json, specificType());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected String toJson(List<T> obj) {
try {
return getObjectMapper().writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
private static ObjectMapper getObjectMapper() {
if (null == OBJECT_MAPPER) {
OBJECT_MAPPER = new ObjectMapper();
OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
return OBJECT_MAPPER;
}
protected abstract TypeReference<List<T>> specificType();
}

根據(jù)具體的使用場景, 創(chuàng)建對應(yīng)的實現(xiàn)類

public class ListLongTypeHandler extends AbstractListTypeHandler<Long> {
@Override
protected TypeReference<List<Long>> specificType() {
return new TypeReference<>() {};
}
}

使用時, 直接用 typeHandler 指定, 不需要指定類型

#{setIds, typeHandler=com.somewhere.mybatis.ListLongTypeHandler},
...
@Result(column="set_ids", property="setIds", typeHandler= ListLongTypeHandler.class),

附: MyBatis 內(nèi)建的 javaType Alias

鏈接: https://mybatis.org/mybatis-3/configuration.html#typeAliases

aliasjavaType
_bytebyte
_char (since 3.5.10)char
_character (since 3.5.10)char
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
char (since 3.5.10)Character
character (since 3.5.10)Character
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
bigintegerBigInteger
objectObject
date[]Date[]
decimal[]BigDecimal[]
bigdecimal[]BigDecimal[]
biginteger[]BigInteger[]
object[]Object[]
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

到此這篇關(guān)于MyBatis 擴(kuò)展BaseTypeHandler 轉(zhuǎn)換泛型 JSON 列表的文章就介紹到這了,更多相關(guān)java的多線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloud FeignClient 超時設(shè)置

    SpringCloud FeignClient 超時設(shè)置

    FeignClient?默認(rèn)的超時時間可能不滿足你的需求,你可以通過幾種方式來自定義這些超時設(shè)置,具有一定的參考價值,感興趣的可以了解一下
    2024-08-08
  • Nacos服務(wù)實例的權(quán)重設(shè)置方式(以及設(shè)置為0時的作用與場景)

    Nacos服務(wù)實例的權(quán)重設(shè)置方式(以及設(shè)置為0時的作用與場景)

    這篇文章主要介紹了Nacos服務(wù)實例的權(quán)重設(shè)置方式(以及設(shè)置為0時的作用與場景),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • java中封裝JDBC工具類的實例分析

    java中封裝JDBC工具類的實例分析

    在本篇內(nèi)容里小編給各位分享了一篇關(guān)于java中封裝JDBC工具類的實例分析,對此有興趣的朋友們可以學(xué)習(xí)下。
    2021-03-03
  • 一文帶你深入解析Java應(yīng)用線程轉(zhuǎn)儲

    一文帶你深入解析Java應(yīng)用線程轉(zhuǎn)儲

    在Java應(yīng)用運維和問題排查過程中,線程轉(zhuǎn)儲(Thread?Dump)是一個非常重要的工具,它能夠幫助我們了解JVM內(nèi)部線程的運行狀態(tài),下面小編來和大家詳細(xì)介紹一下它吧
    2025-04-04
  • Spark Streaming算子開發(fā)實例

    Spark Streaming算子開發(fā)實例

    這篇文章主要介紹了Spark Streaming算子開發(fā)實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • Java Swing中的JButton、JComboBox、JList和JColorChooser組件使用案例

    Java Swing中的JButton、JComboBox、JList和JColorChooser組件使用案例

    這篇文章主要介紹了Java Swing中的按鈕(JButton)、組合框(JComboBox)、下拉列表(JList)和顏色選擇器(JColorChooser)組件使用案例,需要的朋友可以參考下
    2014-10-10
  • Java設(shè)置Excel數(shù)據(jù)驗證的示例代碼

    Java設(shè)置Excel數(shù)據(jù)驗證的示例代碼

    數(shù)據(jù)驗證是Excel 2013版本中,數(shù)據(jù)功能組下面的一個功能。本文將通過Java程序代碼演示數(shù)據(jù)驗證的設(shè)置方法及結(jié)果,感興趣的可以了解一下
    2022-05-05
  • 基于SpringBoot實現(xiàn)一個JAVA代理HTTP/ WS的方法

    基于SpringBoot實現(xiàn)一個JAVA代理HTTP/ WS的方法

    本文主要介紹了基于SpringBoot實現(xiàn)一個JAVA代理HTTP/WS的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-06-06
  • SpringCloud使用FFmpeg對視頻壓縮處理的代碼示例

    SpringCloud使用FFmpeg對視頻壓縮處理的代碼示例

    在現(xiàn)代的視頻處理系統(tǒng)中,壓縮視頻以減小存儲空間、加快傳輸速度是一項非常重要的任務(wù),FFmpeg作為一個強(qiáng)大的開源工具,廣泛應(yīng)用于音視頻的處理,包括視頻的壓縮和格式轉(zhuǎn)換等,本文將通過Java代碼示例,向您展示如何使用FFmpeg進(jìn)行視頻壓縮,并介紹相關(guān)參數(shù)的設(shè)置
    2024-11-11
  • springboot schedule 解決定時任務(wù)不執(zhí)行的問題

    springboot schedule 解決定時任務(wù)不執(zhí)行的問題

    這篇文章主要介紹了springboot schedule 解決定時任務(wù)不執(zhí)行的問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09

最新評論

巩义市| 吉安县| 江北区| 浦东新区| 广东省| 余姚市| 大姚县| 中山市| 博兴县| 平遥县| 鸡东县| 安新县| 会理县| 嘉荫县| 阜阳市| 华蓥市| 铁岭县| 常宁市| 淮滨县| 西城区| 孝昌县| 甘谷县| 潞城市| 鹤壁市| 西乡县| 高雄县| 库伦旗| 沭阳县| 上犹县| 武平县| 青冈县| 慈溪市| 合川市| 惠州市| 新化县| 道孚县| 茌平县| 西乌| 清丰县| 永嘉县| 商丘市|