MyBaties存储和查询json格式的数据(实体存储查询版本)

最近在做的功能,由于别的数据库有值,需要这边的不同入口的进来查询,所以需要同步过来,如果再继续一个一个生成列对应处理感觉不方便,如果没有别的操作,只是存储和查询,那就可以用MySql支持的json格式存储了。

MySql的json是5.7之后才可以处理的,所以版本一定要是这个或者比这个高呦!

首先第一步我们需要定义个处理json类型类,可以叫BaseAttributeTypeHandler,来继承BaseTypeHandler这个ibatis的类,一定要定义类型,后期传参用,

java 复制代码
package xx;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import io.lettuce.core.dynamic.support.ResolvableType;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.util.Assert;

import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author df
 * @Description: 基础类, 处理mySql字段为json类型
 * @Date 2023/10/19 9:52
 */
public abstract class BaseAttributeTypeHandler<T> extends BaseTypeHandler<Object> {

    private JavaType javaType;

    /**
     * ObjectMapper
     */
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 构造方法
     */
    public BaseAttributeTypeHandler() {
        // 通过class构造一个ResolvableType对象
        ResolvableType resolvableType = ResolvableType.forClass(getClass());
        // 获取对应泛型实体
        Type type = resolvableType.as(BaseAttributeTypeHandler.class).getGeneric() != null ?
                resolvableType.as(BaseAttributeTypeHandler.class).getGeneric().getType() :
                null;
        // 根据对应类型构造出java类型
        javaType = constructType(type);
    }

    private static JavaType constructType(Type type) {
        Assert.notNull(type, "[Assertion failed] - type is required; it must not be null");
        return TypeFactory.defaultInstance().constructType(type);
    }


    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, JSONUtil.toJsonStr(parameter));
    }

    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        return convertToEntityAttribute(value);
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convertToEntityAttribute(rs.getString(columnIndex));
    }

    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        return convertToEntityAttribute(value);
    }

    private Object convertToEntityAttribute(String dbData) {
        // 根据得到的数据判断类型
        if (StrUtil.isEmpty(dbData)) {
            if (List.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptyList();
            } else if (Set.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptySet();
            } else if (Map.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptyMap();
            } else {
                return null;
            }
        }
        return toObject(dbData, javaType);
    }

    private static <T> T toObject(String json, JavaType javaType) {
        Assert.hasText(json, "[Assertion failed] - this json must have text; it must not be null, empty, or blank");
        Assert.notNull(javaType, "[Assertion failed] - javaType is required; it must not be null");
        try {
            // 给对象设置值
            return (T) OBJECT_MAPPER.readValue(json, javaType);
        } catch (com.fasterxml.jackson.core.JsonParseException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (JsonMappingException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}

定义要存储的json类型的实体类,假如存储个用户信息把,我们就定义了UserSportTypeHandler,然后继承刚才的类BaseAttributeTypeHandler,传入json实体UserSport(你们自己定义的要存储或者查询出来的实体哈)

java 复制代码
public class UserSportTypeHandler extends BaseAttributeTypeHandler<UserSport> {
}

存储时在po实体里添加如下的说明,好让MySql知道是json,这里的typeHandler则定义为UserSportTypeHandler

java 复制代码
   
@Data
public class User {
    
    private Long id;
    
    private String username;

    @TableField(jdbcType = JdbcType.OTHER, typeHandler = UserSportTypeHandler.class)
    private UserSport userSport;

}

新增

调用mybatis插件直接保存即可

java 复制代码
public class UserBusinessImpl extends ServiceImpl<UserMapper, User> implements UserBusiness {

    public Boolean saveSportDataBatch(List<User> users) {
         super.saveBatch(users);
    }

}

测试下,可以哦,直接存储了json的数据

当然还可以存储list以及list<json>这样的格式,可以这样改。

java 复制代码
public class UserSportTypeHandler extends BaseAttributeTypeHandler<List<UserSport>> {
}

也可以在mapper.xml里这样添加,也要指明typeHadler

XML 复制代码
 <insert id="saveBatch" parameterType="java.util.List">
        INSERT INTO user_sport_record (user_sport)
        <foreach collection="list" separator="," item="item">
            VALUES (
                    #{item.userSport,javaType=com.uniigym.Uniiuser.infrastructure.po.HeartDistribute,typeHandler=HeartDistributeTypeHandler,jdbcType=OTHER});
        </foreach>
    </insert>

查询

当然你要是自己在mapper里写,可以在resultMap下里写,示例:

XML 复制代码
<resultMap type="xx.po.User" id="user">
        <result property="id" column="id" jdbcType="INTEGER"/>
      
        <!-- json需要配置如下才能查询出来数据 -->
        <result typeHandler="com.uniigym.Uniiuser.common.config.mybatis.HeartDistributeTypeHandler"
                property="heartDistribute" column="heart_distribute"
                jdbcType="OTHER" javaType="com.uniigym.Uniiuser.infrastructure.po.HeartDistribute"/>
    </resultMap>

这样查询和添加都可以用这个,但是要在sql种指定resultMap的id,但是如果实体上写了 @TableField(jdbcType = JdbcType.OTHER, typeHandler = UserSportTypeHandler.class),就不用在ResultMap标签在定义了。如果都不配置typeHandler则关于json的字段查询出来为空,只有对了查询和保存才可以处理。

相关推荐
Hello_Pyhx3 天前
NWinfo 导出 Windows 硬件信息:从 JSON 报告到缺项排查
windows·json
程序员大阳3 天前
副队长JavaScript教程(66)-本地存储实战:待办事项网页的开发
javascript·json·实战·待办事项·本地存储·案例
视觉小萌新4 天前
AI Class 3 · Chapter 2-3:函数、异常、文件读写+JSON / JSONL 读写(小白版)
人工智能·python·json
翊众建站5 天前
用 JSON-LD 给企业官网做结构化数据:LocalBusiness 与 FAQPage 实践笔记
人工智能·搜索引擎·json
Patrick_Wilson5 天前
读懂一个 Go JSON 处理函数:从输入数据追踪结构体、校验与错误返回
go·json·编程语言
January12077 天前
【AI方法笔记】2026-11-02:模型流式吐 JSON 时,前端会遇到四种崩法
前端·人工智能·笔记·json
Frag0ut8 天前
Notepad++ 零基础入门:从记事本到代码编辑器的平滑过渡(2026最新版)
python·编辑器·html·json·notepad++·markdown·记事本
xiaoye-duck8 天前
《C++ 工具库实战》C++ 解析利器 JsonCpp:从基础使用到封装简易 JSON 工具
c++·json·第三方库
javachen__8 天前
试试Jackson:把JSON拉平成普通属性
json