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

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

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

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

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

這個(gè)是比較簡(jiǎn)單的情況, 有通用的處理方法, 例如

用Jackson實(shí)現(xiàn)一個(gè)通用的 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;
}
}

使用時(shí)直接指定 typeHandler 就行

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

以及

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

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

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

通用的TypeHandler, 需要指定javaType

用 Jackson 實(shí)現(xiàn)一個(gè)通用的 TypeHandler, 注意構(gòu)造函數(shù)中的 clazz, 如果不指定, 在默認(rèn)情況下 mybatis 傳進(jìn)來(lái)的是一個(gè)不帶泛型參數(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自帶的簡(jiǎn)單類型, 可以直接用 alias(見(jiàn)下面的表格), 如果是自定義的對(duì)象, 則需要用對(duì)象類的完整包路徑

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

以及

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

這樣啟動(dòng)后, 如果初始化的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ù)對(duì)象類型實(shí)現(xiàn)具體的 TypeHandler

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

寫一個(gè)基類 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ù)具體的使用場(chǎng)景, 創(chuàng)建對(duì)應(yīng)的實(shí)現(xiàn)類

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

使用時(shí), 直接用 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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloud FeignClient 超時(shí)設(shè)置

    SpringCloud FeignClient 超時(shí)設(shè)置

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

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

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

    java中封裝JDBC工具類的實(shí)例分析

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

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

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

    Spark Streaming算子開(kāi)發(fā)實(shí)例

    這篇文章主要介紹了Spark Streaming算子開(kāi)發(fā)實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(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ù)驗(yàn)證的示例代碼

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

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

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

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

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

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

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

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

最新評(píng)論

道孚县| 齐齐哈尔市| 蒙阴县| 潮州市| 天镇县| 新野县| 青田县| 望奎县| 咸宁市| 招远市| 五常市| 钟祥市| 忻城县| 神池县| 山西省| 孝昌县| 桐梓县| 天长市| 吴堡县| 鸡东县| 三穗县| 高淳县| 津市市| 织金县| 石楼县| 浦江县| 卢龙县| 汨罗市| 潮州市| 万州区| 牟定县| 漯河市| 合作市| 博爱县| 新龙县| 历史| 北京市| 锦屏县| 徐汇区| 灯塔市| 宜良县|