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

SpringBoot+MyBatis處理JSON字段的完整指南

 更新時間:2026年03月30日 09:23:27   作者:荒古前  
本文主要介紹了SpringBoot+MyBatis處理JSON字段的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

最近在開發(fā)一個活動發(fā)布功能時,遇到了一個讓人頭疼的問題:前端傳遞的聯系方式信息(contactInfo)是一個 JSON 對象,但后端始終無法正確接收和存儲到數據庫。經過一番折騰,終于完美解決了。本文將詳細記錄這個問題和解決方案,希望對遇到類似問題的朋友有所幫助。

問題場景

我需要實現一個活動發(fā)布接口,其中聯系方式字段 contactInfo 需要存儲多個信息(如微信、QQ、手機號等),設計如下:

數據庫表結構:

CREATE TABLE activity (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    title VARCHAR(50),
    category VARCHAR(20),
    activity_type VARCHAR(50),
    activity_time DATETIME,
    city VARCHAR(50),
    people_limit INT,
    current_people INT,
    contact_info JSON,  -- JSON 類型字段
    contact_visibility VARCHAR(20),
    create_time DATETIME,
    status TINYINT
);

前端傳參格式:

{
  "title": "今晚王者三排",
  "category": "GAME",
  "activityType": "王者榮耀",
  "activityTime": "2026-03-23 20:00:00",
  "city": "南京",
  "peopleLimit": 3,
  "contactInfo": {
    "wechat": "test123",
    "qq": "123456789",
    "phone": "13800138000"
  },
  "contactVisibility": "PUBLIC"
}

遇到的坑

坑1:LocalDateTime 反序列化失敗

錯誤信息:

Cannot deserialize value of type `java.time.LocalDateTime` from String "2026-03-23 20:00:00"

原因: Jackson 默認的日期格式是 yyyy-MM-ddTHH:mm:ss,但前端傳的是 yyyy-MM-dd HH:mm:ss(空格分隔)。

解決方案: 在 DTO 中添加 @JsonFormat 注解

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime activityTime;

坑2:contactInfo 類型不匹配

錯誤信息:

Cannot deserialize value of type `java.lang.String` from Object value

原因: 前端傳的是對象 {"wechat":"test123"},但后端 DTO 定義的是 String 類型。

坑3:MyBatis 無法處理 JSON 字段

錯誤信息:

Type handler was null on parameter mapping for property 'contactInfo'

原因: MyBatis 默認不知道如何將 Java 對象轉換為數據庫的 JSON 字段。

坑4:自增 ID 返回 null

錯誤信息:

Column 'activity_id' cannot be null

原因: MyBatis insert 后沒有返回自增 ID,導致插入 activity_member 時 activity_id 為 null。

解決方案

經過多次嘗試,我選擇了最簡單直接的方案:手動轉換 JSON

1. DTO 使用 Object 類型接收

package com.jade.partnermatch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class ActivityCreateDTO {
    private String title;
    private String category;
    private String activityType;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime activityTime;
    private String city;
    private Integer peopleLimit;
    private Object contactInfo;  // 使用 Object 接收,可以是字符串或對象
    private String contactVisibility;
}

2. Entity 使用 String 存儲

package com.jade.partnermatch.entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Activity {
    private Long id;
    private Long userId;
    private String title;
    private String category;
    private String activityType;
    private LocalDateTime activityTime;
    private String city;
    private Integer peopleLimit;
    private Integer currentPeople;
    private String contactInfo;  // 存 JSON 字符串
    private String contactVisibility;
    private LocalDateTime createTime;
    private Integer status;
}

3. Service 手動轉換

package com.jade.partnermatch.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jade.partnermatch.dto.ActivityCreateDTO;
import com.jade.partnermatch.entity.Activity;
import com.jade.partnermatch.mapper.ActivityMapper;
import com.jade.partnermatch.mapper.ActivityMemberMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
@Service
public class ActivityService {
    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityMemberMapper activityMemberMapper;
    @Autowired
    private ObjectMapper objectMapper;  // 注入 Jackson
    @Transactional
    public void create(ActivityCreateDTO dto) {
        Activity activity = new Activity();
        activity.setUserId(1L);
        activity.setTitle(dto.getTitle());
        activity.setCategory(dto.getCategory());
        activity.setActivityType(dto.getActivityType());
        activity.setActivityTime(dto.getActivityTime());
        activity.setCity(dto.getCity());
        activity.setPeopleLimit(dto.getPeopleLimit());
        activity.setCurrentPeople(1);
        // 關鍵:將 Object 轉換為 JSON 字符串
        String contactInfoJson = convertToJson(dto.getContactInfo());
        activity.setContactInfo(contactInfoJson);
        activity.setContactVisibility(dto.getContactVisibility());
        activity.setCreateTime(LocalDateTime.now());
        activity.setStatus(0);
        // 先插入活動,獲取自增 ID
        activityMapper.insert(activity);
        // 再插入活動成員
        activityMemberMapper.insert(activity.getId(), activity.getUserId());
    }
    private String convertToJson(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            e.printStackTrace();
            return "{}";
        }
    }
}

4. Mapper XML 配置自增 ID

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jade.partnermatch.mapper.ActivityMapper">
    <!-- 關鍵:添加 useGeneratedKeys 和 keyProperty -->
    <insert id="insert" parameterType="Activity" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO activity
        (user_id, title, category, activity_type, activity_time, city,
         people_limit, current_people, contact_info, contact_visibility,
         create_time, status)
        VALUES
        (#{userId}, #{title}, #{category}, #{activityType}, #{activityTime}, #{city},
         #{peopleLimit}, #{currentPeople}, #{contactInfo}, #{contactVisibility},
         #{createTime}, #{status})
    </insert>
    <select id="list" resultType="Activity">
        SELECT * FROM activity
        WHERE status = 0
        ORDER BY create_time DESC
    </select>
</mapper>

5. 如果需要查詢時解析 JSON

// 在查詢后解析 JSON 字符串為 Map
public List<Activity> list() {
    List<Activity> activities = activityMapper.list();
    for (Activity activity : activities) {
        if (activity.getContactInfo() != null) {
            try {
                Map<String, Object> contactInfoMap = objectMapper.readValue(
                    activity.getContactInfo(), 
                    Map.class
                );
                // 使用 contactInfoMap...
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    return activities;
}

最終效果

數據庫成功存儲 JSON 數據:

mysql> select * from activity;
+----+---------+--------------+----------+---------------+---------------------+------+--------------+----------------+-----------------------+--------------------+---------------------+--------+
| id | user_id | title        | category | activity_type | activity_time       | city | people_limit | current_people | contact_info          | contact_visibility | create_time         | status |
+----+---------+--------------+----------+---------------+---------------------+------+--------------+----------------+-----------------------+--------------------+---------------------+--------+
|  1 |       1 | 今晚王者三排 | GAME     | 王者榮耀      | 2026-03-23 20:00:00 | 南京 |            3 |              2 | {"wechat": "test123"} | PUBLIC             | 2026-03-24 20:22:59 |      0 |
|  2 |       1 | 今晚王者三排 | GAME     | 王者榮耀      | 2026-03-23 20:00:00 | 南京 |            3 |              1 | {"wechat": "test123"} | PUBLIC             | 2026-03-26 13:50:05 |      0 |
|  3 |       1 | 今晚王者三排 | GAME     | 王者榮耀      | 2026-03-23 20:00:00 | 南京 |            3 |              1 | {"wechat": "test123"} | PUBLIC             | 2026-03-26 13:51:45 |      0 |
|  4 |       1 | 今晚王者三排 | GAME     | 王者榮耀      | 2026-03-23 20:00:00 | 南京 |            3 |              1 | {"wechat": "test123"} | PUBLIC             | 2026-03-26 13:53:44 |      0 |
+----+---------+--------------+----------+---------------+---------------------+------+--------------+----------------+-----------------------+--------------------+---------------------+--------+
4 rows in set (0.00 sec)

方案優(yōu)缺點

優(yōu)點

  • 簡單直接:不需要學習復雜的 TypeHandler
  • 完全可控:自己決定如何轉換,易于調試
  • 兼容性好:前端傳字符串或對象都能處理
  • 代碼清晰:邏輯一目了然

缺點

  • 查詢時需要手動解析 JSON
  • 如果需要頻繁操作 JSON 內的字段,性能稍差

其他可選方案

方案2:使用 MyBatis 的 JacksonTypeHandler

在 Mapper XML 中配置:

<result column="contact_info" property="contactInfo" 
        typeHandler="org.apache.ibatis.type.JacksonTypeHandler"/>

方案3:自定義 TypeHandler

實現 BaseTypeHandler 接口,自己處理 JSON 轉換。

總結

  • JSON 字段接收:DTO 使用 Object 或 Map 類型
  • JSON 字段存儲:Entity 使用 String 類型
  • 轉換工具:使用 Jackson 的 ObjectMapper
  • 自增 ID:MyBatis insert 添加 useGeneratedKeys 和 keyProperty

遇到類似問題不要慌,一步步排查,總能找到解決方案。

到此這篇關于SpringBoot+MyBatis處理JSON字段的完整指南的文章就介紹到這了,更多相關SpringBoot+MyBatis處理JSON字段內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Jenkins服務器配置SSH實踐

    Jenkins服務器配置SSH實踐

    文章指導如何配置Jenkins用戶的SSH免密登錄:需獲取Jenkins公鑰并添加至目標服務器authorized_keys文件,測試時若無需輸入密碼則表示配置成功,否則需檢查公鑰配置步驟
    2025-09-09
  • Java獲取隨機數的n種方法

    Java獲取隨機數的n種方法

    項目中,我們常常會用到隨機數,本文主要介紹了Java獲取隨機數的n種方法,具有一定的參考價值,感興趣的可以了解一下
    2023-11-11
  • Lombok同時使?@Data和@Builder踩坑總結

    Lombok同時使?@Data和@Builder踩坑總結

    這篇文章主要介紹了Lombok同時使?@Data和@Builder踩坑總結,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值需要的小伙伴可以參考一下,希望對你的學習有所幫助
    2022-05-05
  • 在springboot中如何給mybatis加攔截器

    在springboot中如何給mybatis加攔截器

    這篇文章主要介紹了在springboot中如何給mybatis加攔截器,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 從零實現一個簡單的Spring Bean容器的代碼案例

    從零實現一個簡單的Spring Bean容器的代碼案例

    Spring是一個非常流行的Java?Web開發(fā)框架,它提供了強大的依賴注入、面向切面編程、聲明式事務管理等功能,為開發(fā)者提供了高效、快速地構建Web應用程序的工具,在這篇文章中,咱們將一步一步地構建一個簡單的SpringBean容器,需要的朋友可以參考下
    2023-06-06
  • JAVA對象中使用?static?和?String?基礎探究

    JAVA對象中使用?static?和?String?基礎探究

    這篇文章主要介紹了JAVA對象中使用static和String基礎探究,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • 淺析SpringBoot中使用thymeleaf找不到.HTML文件的原因

    淺析SpringBoot中使用thymeleaf找不到.HTML文件的原因

    這篇文章主要介紹了SpringBoot中使用thymeleaf找不到.HTML文件的原因分析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • Intellij IDEA十大快捷鍵

    Intellij IDEA十大快捷鍵

    Intellij IDEA中有很多快捷鍵讓人愛不釋手,stackoverflow上也有一些有趣的討論.這篇文章主要介紹了Intellij IDEA十大快捷鍵,需要的朋友可以參考下
    2018-03-03
  • mybatis的insert語句插入數據時的返回值的實現

    mybatis的insert語句插入數據時的返回值的實現

    這篇文章主要介紹了mybatis的insert語句插入數據時的返回值的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • RocketMQ源碼本地搭建調試方法

    RocketMQ源碼本地搭建調試方法

    這篇文章主要介紹了RocketMQ源碼本地搭建調試,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-01-01

最新評論

青田县| 长阳| 大同县| 上林县| 佛教| 沂水县| 朝阳县| 丰台区| 潜山县| 淮南市| 外汇| 华容县| 苍南县| 子长县| 锡林郭勒盟| 大足县| 吉木萨尔县| 依兰县| 卢湾区| 遂宁市| 东安县| 华蓥市| 木兰县| 芷江| 通化县| 贡嘎县| 东光县| 兰坪| 罗山县| 巴林左旗| 祥云县| 成安县| 潞西市| 淮北市| 澄城县| 封丘县| 西充县| 安福县| 兴宁市| 东海县| 弥勒县|