MyBatis 類型處理器(TypeHandler)注冊與映射機制:JsonListTypeHandler和JsonListTypeHandler注冊時機

下面幾種機制會讓你的 List<String>/Map<String,?> 能正確讀寫成 JSON 數組/對象文本:

  1. MyBatis-Plus 自動注冊
    最新版本的 MyBatis-Plus starter 會把類路徑下所有帶 @MappedTypes({List.class})@MappedJdbcTypes(JdbcType.VARCHAR) 這類注解的 TypeHandler 自動注冊進 TypeHandlerRegistry,所以即使你不在 ConfigurationCustomizer 里再手動 registry.register(...),MyBatis-Plus 啟動時也會把它們掃描進來。

  2. 字段注解強制指定
    如果你的實體里寫了

    @TableField(typeHandler = JsonListTypeHandler.class) private List<String> skills;

    那 MyBatis 在構建映射的時候會直接 new 這個 JsonListTypeHandler 來處理該字段,不會再走默認的 StringTypeHandler

  3. JDBC 驅動的容錯
    就算真沒有任何自定義 Handler,JDBC 驅動也會把你傳進去的字符串(比如你在 Mapper XML 里寫 #{skills},skills.toString() 恰好是 ["a","b"])原封不動地當 VARCHAR 存到 DB,當你再查回 String 字段時,就能看到 JSON 文本。


所以你看到“即使把那兩行全局注冊刪掉,也能正常上傳/查詢”,并不奇怪:

  • MyBatis-Plus Starter 在后臺已經給你注冊好了 List/Map 的 JSON 處理器;

  • 你要么在實體里用注解顯式選了 Handler,要么 DB 和驅動自己把字符串存下來了。

如果你真想驗證“到底哪條路徑在生效”,可以:

  1. 斷點調試 JsonListTypeHandler#setNonNullParameter(...)
    直接看看在執行插入/更新時,MyBatis 到底走的是哪個 Handler 的方法。

  2. 臨時寫個 ConfigurationCustomizer 打日志

    @Bean public ConfigurationCustomizer customizer() { return config -> { config.getTypeHandlerRegistry() .getTypeHandler(List.class) .ifPresent(h -> System.out.println("List 類型處理器是:" + h.getClass())); }; }

啟動后控制臺能看到到底用的哪個 Handler。

核心原理回顧

  1. @MappedTypes 注解
    在類上打了 @MappedTypes(List.class)@MappedTypes(Map.class),MyBatis-Plus Starter 在啟動時會 掃描自動注冊 這些類型處理器。

    • 如果你的版本里這個自動掃描沒開,就算有 @MappedTypes,MyBatis 也不會加載它,你就必須在 ConfigurationCustomizer 里手動 registry.register(...)

  2. 字段級別指定
    如果你在實體類字段上寫了

    @TableField(typeHandler = JsonListTypeHandler.class) private List<String> skills;

    那就算全局沒注冊,MyBatis 也會給該字段硬綁定到這個 handler 上。

  3. MyBatis-Plus 內置 JSON 處理器
    新版本里,MP 自帶了基于 Jackson 的 JacksonTypeHandler,它也會給帶 @MappedTypes 的類自動裝上。
    所以你如果單純刪掉全局注冊,MP 可能已經自己把 JsonListTypeHandlerJsonMapTypeHandler 掃進去了,看起來就“好像不用注冊也行”了。


為什么你“以前刪掉會報錯”?

  • 舊版本 的 MP Starter 并不自動掃描你自己寫的 JsonListTypeHandler,也沒給 List.classMap.class 任何默認 handler。

  • 這時,插入或查詢帶 List<String> 字段,就會拋錯:

    Type handler was null for parameter List

  • 你就逼不得已在 ConfigurationCustomizer 里手動注冊,或者在字段上加 @TableField(typeHandler=…),才跑通。


現在為啥又“刪了也能正常”?

  • 升級后,MP 已經把所有帶 @MappedTypes 注解的 handler 自動掃描并注冊 了;

  • 或者你給字段加了 @TableField(typeHandler=…),繞過了全局注冊需求;

  • 又或者你的表里該列其實是 VARCHARTEXT,你直接在 service 里手動 JSON.toString(list) 存,插入成功——但是反查時就只能拿到 String。


建議

  1. 保留你的 Handler 類,畢竟它能讓你自動在實體里寫 List<String>Map<String,?>

  2. 如果想最簡化,全局注冊可以刪,但要確保你的 MP Starter 版本 ≥ 3.5 且內置掃描打開:

    mybatis-plus: type-handlers-package: com.example.chat2.handler

  3. 或者在每個 JSON 字段上寫:

    @TableField(typeHandler = JsonListTypeHandler.class) private List<String> skills;

    這樣就算全局沒掃到,也能按字段綁定。


小結

  • JsonListTypeHandler/JsonMapTypeHandler 本身是你項目必需的,只是注冊方式可以有三條路:

    1. 全局 ConfigurationCustomizer 手動注冊

    2. @MappedTypes + MP 自動掃描

    3. 字段上 @TableField(typeHandler=…)

  • 你“以前沒寫注冊就報錯”是因為那會兒自動掃描沒開;現在自動掃描打開了,注冊看似“多余”了,但在老版本或沒有字段注解的情況下,它依然是必不可少的。

希望理清了為什么「看著好像多余」又「刪掉又會報錯」的來龍去脈!

而我是在xml寫了這個

?<result property="skills" column="skills" typeHandler="com.example.chat2.handler.JsonListTypeHandler"/>?
? ? ? ? <result property="tools" column="tools" typeHandler="com.example.chat2.handler.JsonListTypeHandler"/>


MyBatis 會直接按照你指定的 typeHandler 來做序列化/反序列化,這種方式和在 Java 里用 @MappedTypes 或者在全局注冊處理器是等價的——它們都是最終把 JSON 文本和 List<String> 對象掛鉤。


是XML 顯式覆蓋
在 <resultMap> 或 <select> 的 <result> 里寫 typeHandler="...",MyBatis 在映射這個列的時候,跳過默認的類型推斷,直接 new 指定的 JsonListTypeHandler。

不再依賴自動掃描
無需再借助 @MappedTypes、type-handlers-package 或者 ConfigurationCustomizer 全局注冊,都能保證該字段走你想要的 Handler。

清晰直觀
只要看 XML 就知道哪些列要走 JSON 處理,不會被其他配置“隱式”影響。

何時用哪種方式?

方式優點缺點
XML 中 typeHandler最直觀,按字段精確控制;不依賴額外掃描每個字段都得在 XML 定義一次,比較啰嗦
字段注解 @TableField(typeHandler=…)配置集中在實體類;配合 MP 自動生成也能生效如果你寫 XML,而是用 MP 的 Wrapper/注解方式,則需要這樣,XML 與注解混用時可能有重復
全局自動掃描(@MappedTypes + Starter 或者 ConfigurationCustomizer一次注冊,全表所有 List/Map 列自動生效控制粒度粗,所有同類型字段都會走同一個 Handler

小貼士
如果你只在少數幾個字段用 JSON,XML 顯式 是最簡單可靠的方式;

如果全項目大量用到,建議用 全局掃描 或者 字段注解,免得 XML 太長;

切勿同時對同一個字段在 XML、注解和全局注冊里都寫不同的 Handler,否則會有優先級混亂的問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/79014.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/79014.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/79014.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

專題二十一:無線局域網——WLAN

一、WLAN簡介 WLAN&#xff08;Wireless Local Area Network &#xff09;無線局域網&#xff0c;使用的是 IEEE 802.11 標準系列。 標準版本發布年份最大傳輸速率頻段Wi-Fi代數特點/描述IEEE 802.1119971–2 Mbps2.4 GHzWi-Fi 0最早的無線局域網標準&#xff0c;傳輸速率低&…

python多進程的使用

多進程編程全面指南&#xff1a;從入門到實踐 摘要&#xff1a;本文是為初學者設計的Python多進程編程全攻略&#xff0c;涵蓋基礎概念、核心函數詳解、系統特性分析&#xff0c;并附帶流程圖、測試用例、開源項目推薦和經典書籍清單。通過8個實戰代碼示例和3個性能對比實驗&am…

數據庫管理與安全:從用戶權限到備份恢復的全面指南

引言 在數字化時代&#xff0c;數據已成為組織最寶貴的資產之一。數據庫作為存儲和管理這些數據的核心系統&#xff0c;其安全性和可靠性直接關系到企業的運營和發展。無論是金融交易記錄、醫療健康信息&#xff0c;還是電子商務平臺的用戶數據&#xff0c;都需要通過完善的數…

Electron Forge【實戰】帶圖片的 AI 聊天

改用支持圖片的 AI 模型 qwen-turbo 僅支持文字&#xff0c;要想體驗圖片聊天&#xff0c;需改用 qwen-vl-plus src/initData.ts {id: 2,name: "aliyun",title: "阿里 -- 通義千問",desc: "阿里百煉 -- 通義千問",// https://help.aliyun.com/z…

在 Elastic 中使用 JOIN 進行威脅狩獵!

作者&#xff1a;來自 Elastic Paul Ewing, Jonhnathan Ribeiro Elastic 的管道查詢語言 ES | QL 為查詢帶來了 join 功能。 威脅狩獵者歡呼吧&#xff01;你是否一直在尋找一種通過 Elastic 的速度和強大功能來連接數據的方法&#xff1f;好消息&#xff01;Elastic 現在可以通…

從實列中學習linux shell5: 利用shell 腳本 檢測硬盤空間容量,當使用量達到80%的時候 發送郵件

下面是用于檢測硬盤空間并在使用量達到80%時發送郵件的Shell腳本 第一步 編寫腳本 #!/bin/bash# 郵件配置 recipient"zhaoqingyou99qhzt.com" subject"磁盤空間警報" mail_cmd"/usr/bin/mail" # 根據實際郵件命令路徑修改# 檢查是否安裝郵件工…

Ethan獨立開發產品日報 | 2025-04-30

1. Daytona 安全且靈活的基礎設施&#xff0c;用于運行你的人工智能生成代碼。 Daytona Cloud重新定義了AI代理的基礎設施&#xff0c;具備低于90毫秒的啟動時間、原生性能和有狀態執行能力&#xff0c;這些是傳統云服務無法比擬的。您可以以前所未有的速度和靈活性來創建、管…

Unity SpriteMask(精靈遮罩)

&#x1f3c6; 個人愚見&#xff0c;沒事寫寫筆記 &#x1f3c6;《博客內容》&#xff1a;Unity3D開發內容 &#x1f3c6;&#x1f389;歡迎 &#x1f44d;點贊?評論?收藏 &#x1f50e;SpriteMask&#xff1a;精靈遮罩 &#x1f4a1;作用就是對精靈圖片產生遮罩&#xff0c…

OpenHarmony全局資源調度管控子系統之內存管理部件

OpenHarmony之內存管理部件 內存管理部件 簡介目錄框架 進程回收優先級列表 補充 回收策略/查殺策略 使用說明參數配置說明 availbufferSizeZswapdParamkillConfignandlife 相關倉 簡介 內存管理部件位于全局資源調度管控子系統中&#xff0c;基于應用的生命周期狀態&#…

姜老師的MBTI課程筆記小結(1)ENFJ人格

課程文稿&#xff1a; 好&#xff0c;今天我們的重點其實并不在ENTJ&#xff0c;而是在于如果一個人其他都很像&#xff0c;只是在思考和感受這兩端選擇的時候&#xff0c;他缺了思考而更尊重感受&#xff0c;它會是什么樣的一個人格特質呢&#xff1f;這就是ENFG在16人格的學派…

Node.js 應用場景

Node.js 應用場景 引言 Node.js 是一個基于 Chrome V8 JavaScript 引擎的開源、跨平臺 JavaScript 運行環境。它主要用于服務器端開發&#xff0c;通過非阻塞 I/O 模型實現了高并發處理能力。本文將詳細介紹 Node.js 的應用場景&#xff0c;幫助你了解其在實際項目中的應用。…

Qt/C++面試【速通筆記六】—Qt 中的線程同步

在多線程編程中&#xff0c;多個線程同時訪問共享資源時&#xff0c;可能會出現數據不一致或者錯誤的情況。這時&#xff0c;我們需要線程同步機制來保證程序的正確性。Qt 提供了多種線程同步方式&#xff0c;每種方式適用于不同的場景。 1. 互斥鎖&#xff08;QMutex&#xff…

JDK-17 保姆級安裝教程(附安裝包)

文章目錄 一、下載二、安裝三、驗證是否安裝成功1、看 java 和 javac 是否可用2、看 java 和 javac 的版本號是否無問題 一、下載 JDK-17_windows-x64_bin.exe 二、安裝 三、驗證是否安裝成功 java&#xff1a;執行工具 javac&#xff1a;編譯工具 1、看 java 和 javac 是否…

【LeetCode Hot100】回溯篇

前言 本文用于整理LeetCode Hot100中題目解答&#xff0c;因題目比較簡單且更多是為了面試快速寫出正確思路&#xff0c;只做簡單題意解讀和一句話題解方便記憶。但代碼會全部給出&#xff0c;方便大家整理代碼思路。 46. 全排列 一句話題意 給定一個無重復數字的序列&#xf…

pytest-前后置及fixture運用

1.pytest中的xunit風格前后置處理 pytest中用例的前后置可以直接使用類似于unittest中的前后置處理&#xff0c;但是pytest中的前后置處理方式更 加豐富&#xff0c;分為模塊級、類級、方法級、函數級等不同等級的前后置處理&#xff0c;具體見下面的代碼&#xff1a; test_…

使用scipy求解優化問題

一、求解二次規劃問題 min(X.T * P * X C.T * X) s.t. Xi > 0 ∑Xi 1 1.定義目標函數 def objective(x):return 0.5 * np.dot(x, np.dot(P, x)) np.dot(c, x)2. 定義等式約束 def equality_constraint(x):return np.sum(x) - 1 3.定義邊界約束&#xff1a;x # …

C++初階-STL簡介

目錄 1.什么是STL 2.STL的版本 3.STL的六大組件 4.STL的重要性 4.1在筆試中 4.2在面試中 4.3.在公司中 5.如何學習STL 6.總結和之后的規劃 1.什么是STL STL&#xff08;standard template library-標準模板庫&#xff09;&#xff1b;是C標準庫的重要組成部分&#xf…

kivy android打包buildozer.spec GUI配置

這個適合剛剛學習kivyd的道友使用&#xff0c;后面看情況更新 代碼 import tkinter as tk from tkinter import ttk, filedialog, messagebox, simpledialog import configparser import os import json # 新增導入class BuildozerConfigTool:def __init__(self, master):se…

MOOS-ivp使用(一)——水下機器人系統的入門與使用

MOOS-ivp使用&#xff08;一&#xff09;——水下機器人系統的入門與使用 MOOS-ivp&#xff08;Marine Operational Oceanographic System for Intelligent Vehicle Planning&#xff09;是專為水下機器人&#xff08;如AUV&#xff09;設計的開源框架。類似于ROS&#xff0c;…