存储或读取时转换JSON数据

一、 数据库类型

在这里插入图片描述

二、使用Hutool工具

存储时将数据转换为JSON数据

在这里插入图片描述

获取时将JSON数据转换为对象

在这里插入图片描述

发现问题:

原本数据对象是AddressFirend但是转换完成后数据变成了JSONArray和JSONObject
在这里插入图片描述

三、自定义TypeHandler继承Mybatis的BaseTypeHandler处理器
package com.jiusi.config;


import cn.hutool.json.JSONUtil;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class jsonTypeHandler01<T> extends BaseTypeHandler {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        //将数据转换为json字符串
        ps.setString(i, JSONUtil.toJsonStr(parameter));
    }

    @Override
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        //将json字符串转换为任意类型
        if(rs.getString(columnName).charAt(0)=='{'){
            return (T) JSONUtil.parseObj(rs.getString(columnName));
        }
        return (T)JSONUtil.parseArray(rs.getString(columnName));
    }

    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }
}

在xml中使用

添加数据时在需要改变的字段后添加TypeHandler属性,使用自定义的JsonTypeHandler

    <insert id="insert">
        insert into msg (name, age, height, address, friend)
        values (#{name}, #{age}, #{height}, #{address,typeHandler=com.jiusi.config.jsonTypeHandler},
        #{friend,typeHandler=com.jiusi.config.jsonTypeHandler})
    </insert>

获取数据时在ResultMap里Result上添加typeHandler属性,同样使用自定义的JackonTypeHandler

    <resultMap type="com.jiusi.model.Msg" id="Jackon">
        <result property="id" column="id"></result>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <result property="height" column="height"></result>
        <result property="address" column="address" typeHandler="com.jiusi.config.JackonTypeHandler">				</result>
        <result property="friend" column="friend" typeHandler="com.jiusi.config.JackonTypeHandler"></result>
    </resultMap>

但是查询出来的同样是JSONArray和HJSONObject
在这里插入图片描述

为什么使用BaseTypeHandler 而不是 TypeHandler

BaseTypeHandler<T>是一个实现了TypeHandler接口的抽象基类,提供了对TypeHandler接口的一些基础实现和默认行为,简化了自定义类型处理器的开发。通过继承BaseTypeHandler,开发者只需要关注具体的转换逻辑,而无需重复实现所有接口方法。
在这里插入图片描述

四、结合Redis进行转换

往数据库存储数据的同时将全类名也存入进去

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
package com.jiusi.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class jsonTypeHandler02<T> extends BaseTypeHandler<T> {
    Jackson2JsonRedisSerializer<Object> serializer;
     // 解决序列化乱码问题
    public jsonTypeHandler02() {       
        // 指定序列化输入的类型, 即输入到redis的类型
        serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        // 指定序列化输出的类型
        ObjectMapper objectMapper = new ObjectMapper();
        //JsonAutoDetect.Visibility.ANY 代表所有属性或字段都可以序列化
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //新版用法
        //以数组的方式存放到Redis,Class Type 全类名作为为第一个元素,Json字符串为第二个元素。
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        //将参数序列化为byts数组然后转成字符串
        ps.setString(i,new String( serializer.serialize(parameter)));
    }

    @Override
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        //  将字符串反序列化为对象
        return (T) serializer.deserialize(rs.getString(columnName).getBytes(StandardCharsets.UTF_8));
    }

    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }

}

将xml中的typeHandler 修改成当前处理器

在这里插入图片描述
在这里插入图片描述

五、自定义序列化方式

与Redis一样将全类名同时存入数据库

package com.jiusi.config;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 自定义序列化方式
 * @param <T>
 */
public class MybatisToJsonConfig<T> {
    static {
        DEFAULT_CHARSET = StandardCharsets.UTF_8;
    }

    public static final Charset DEFAULT_CHARSET;
    private final JavaType javaType;

    private ObjectMapper objectMapper = new ObjectMapper();

    public MybatisToJsonConfig(Class<T> type) {
        this.javaType = this.getJavaType(type);
    }

    public MybatisToJsonConfig(JavaType javaType) {
        this.javaType = javaType;
    }

    public T deserialize(@Nullable byte[] bytes) throws Exception {

        try {
            return this.objectMapper.readValue(bytes, 0, bytes.length, this.javaType);
        } catch (Exception ex) {
            throw new Exception("无法读取JSON: " + ex.getMessage(), ex);
        }
    }

    public byte[] serialize(@Nullable Object t) throws Exception {
        try {
            return this.objectMapper.writeValueAsBytes(t);
        } catch (Exception ex) {
            throw new Exception("无法写入JSON: " + ex.getMessage(), ex);
        }
    }

    public void setObjectMapper(ObjectMapper objectMapper) {
        Assert.notNull(objectMapper, "'objectMapper' 不能为空");
        this.objectMapper = objectMapper;
    }

    private JavaType getJavaType(Class<?> clazz) {
        return TypeFactory.defaultInstance().constructType(clazz);
    }


}
package com.jiusi.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 同样继承BaseTypeHandler但是序列化方式是使用自定义序列化方式
 * @param <T>
 */
public class JsonTypeHandler03<T> extends BaseTypeHandler<T> {
    private static MybatisToJsonConfig<Object> serializer;

    static {
        serializer = new MybatisToJsonConfig<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        //JsonAutoDetect.Visibility.ANY 代表所有属性或字段都可以序列化
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //以数组的方式存放到Redis,Class Type 全类名作为为第一个元素,Json字符串为第二个元素。
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(objectMapper);
    }


    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        //使用Redis的序列化将参数序列化为byts数组然后转成字符串
        try {
            ps.setString(i,new String( serializer.serialize(parameter)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        //  是使用自定义的Redis反序列化将字符串反序列化为对象
        try {
            return (T) serializer.deserialize(rs.getString(columnName).getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }

}

将xml中的typeHandler 修改成当前处理器
在这里插入图片描述

在这里插入图片描述

六、Mybatis-Plus

使用Mybatis-Plus同样可以只需要只需要加两个注解在类上添加@TableName(Value = “表名” , autoResultMap = true),并且在需要转换的字段上添加@TableField( typeHandler = 处理器)

处理器可以使用上面我们自定义的处理器

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/595350.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Feign 和 OpenFeign 的区别

Feign 和 OpenFeign 都是用来进行服务间调用的客户端库&#xff0c;它们旨在简化HTTP API客户端的编写过程&#xff0c;使得编写对外部服务的接口就像调用本地方法一样简单。尽管它们有相似之处&#xff0c;但也存在一些关键差异&#xff1a; 归属和演进&#xff1a; Feign 最初…

硬件设计计划与APQP

硬件设计的关键节点: 大的里程碑milestone分为: Kickoff->A Samples->做出第一批B样总成件->B Samples/OTS->C Samples->PPAP->SOP 具体到硬件,A/B/C sample阶段,又可细分为: 关键器件选型&硬件系统方案设计原理图绘制PCB LayoutA_BOM输出PCB制板…

3. 深度学习笔记--优化函数

深度学习——优化器算法Optimizer详解&#xff08;BGD、SGD、MBGD、Momentum、Adagrad、Adadelta、RMSprop、Adam、Nadam、AdaMax、AdamW &#xff09; 0. GD &#xff08;梯度下降&#xff09; Gradient Descent&#xff08;梯度下降&#xff09;是一种迭代优化算法&#xf…

FreeRTOS内存管理(1-20)

FreeRTOS内存管理简介 在使用FreeRTOS创建任务&#xff0c;队列&#xff0c;信号量等对象时&#xff0c;一般都提供两种方法 1&#xff1a;动态创建任务&#xff08;方法&#xff09;自动地从FreeRTOS管理的内存堆中申请创建对象所需要的内存&#xff0c;并且在删除对象后可以…

九州金榜|孩子沉迷于网络:家庭教育的挑战与对策

随着时代的进步&#xff0c;科技的发展&#xff0c;网络现在成为了我们日常生活不可分割的一部分。然而&#xff0c;随着网络的普及也出现了一些列的问题&#xff0c;其中孩子沉迷于网络就是当前家长最为关心的问题&#xff0c;对于这种情况的发生&#xff0c;家庭教育就显得尤…

Linux主机重启后报错:[FAILED] Failed to start Switch Root.

一、问题描述 某次云主机因计费问题&#xff0c;导致批量重启&#xff0c;重启后发现某台云主机竟进入紧急救援模式&#xff08;emergency模式&#xff09;&#xff0c;如下所示&#xff1a; 二、原因及处理 1&#xff09;原因&#xff1a;加载根分区失败&#xff0c;导致无…

Libcity笔记:原子文件

1 介绍 Libcity中的数据以原子文件的形式存在 2 原子文件类别 对于不同的交通预测任务&#xff0c;可能用到不同的原子文件&#xff0c;同一个数据集不一定包含全部六种原子文件 网格数据需要按照先行后列的顺序遍历OD数据需要按照先起点后终点的顺序遍历 2.1 geo 存储地理…

Netty 实现dubbo rpc

一、RPC 的基本介绍 RPC (Remote Procedure Call) 远程过程调用&#xff0c;是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序&#xff0c;而程序员无需额外的为这个交互编程。也就是说可以达到两个或者多个应用程序部署在不同的服务器上&…

OpenCV 入门(七)—— 身份证识别

OpenCV 入门系列&#xff1a; OpenCV 入门&#xff08;一&#xff09;—— OpenCV 基础 OpenCV 入门&#xff08;二&#xff09;—— 车牌定位 OpenCV 入门&#xff08;三&#xff09;—— 车牌筛选 OpenCV 入门&#xff08;四&#xff09;—— 车牌号识别 OpenCV 入门&#xf…

德国韦纳WENAROLL滚压刀,液压缸,滚光刀,挤压刀,滚轧刀

德国韦纳WENAROLL滚压刀,液压缸&#xff0c;滚光刀,挤压刀&#xff0c;滚轧刀&#xff08;百度一下&#xff0c;西安尚融&#xff09; 德国韦纳&#xff08;WENAROLL&#xff09;的滚压刀、液压缸、滚光刀、挤压刀和滚轧刀在工业领域享有很高的声誉&#xff0c;这些产品因其高…

SM618卡件SM480模块和利时

SM618卡件❗电:183-6998-1851❗SM480模块和利时。自动化程度的提高&#xff0c;I/O点数大幅增 加&#xff0c;传统单一配线的方式已经无法满足发展的需 要SM618卡件SM480模块和利时。&#xff0e;对简单、可靠的配线方式的需求日益强烈&#xff0e; 传统接线 - 以并联方式连 接…

C# WinForm —— 12 ListBox绑定数据

ListBox加载大量数据时&#xff0c;避免窗体闪烁的方法&#xff1a; 在加载语句的前后分别加上 BeginUpdate()方法 和 EndUpdate()方法 指定一个集合为绑定的数据源 1. 首先&#xff0c;右键项目&#xff0c;添加类 2. 在新建的类文件中添加属性值信息 3. 构建初始化的对象…

访问学者在外访学期间,是否可以中途回国?

在全球化的今天&#xff0c;访问学者制度已成为促进国际学术交流与合作的重要桥梁。然而&#xff0c;对于许多国外访问学者来说&#xff0c;一个常见的问题是&#xff1a;在访学期间&#xff0c;我是否可以中途回国&#xff1f;这个问题涉及到多个方面&#xff0c;包括政策法规…

7步教程从零开始搭建跨境电商平台开发

跨境电商平台开发一直是创业者们追逐的热门领域之一。本文将为您提供一个7步教程&#xff0c;帮助您从零开始搭建跨境电商平台&#xff0c;让您在这个充满机遇的领域中抢占先机。 步骤一&#xff1a;市场调研和定位 在开始搭建跨境电商平台之前&#xff0c;第一步是进行充分的…

大数据与会计专业主要学什么课程

大数据与会计专业是一个结合了传统会计知识与现代大数据技术的交叉学科&#xff0c;旨在培养既懂会计又熟悉大数据分析的复合型人才。该专业的学生将会学习以下主要课程内容&#xff1a; 会计基础课程&#xff1a;包括基础会计、财务会计、成本会计、管理会计等&#xff0c;这些…

我独自升级崛起下载教程 我独自升级崛起怎么一键下载

定于5月8日全球盛大发布的动作RPG力作《我独自升级崛起》&#xff0c;基于备受追捧的同名动画及网络漫画&#xff0c;誓为热情洋溢的游戏爱好者们呈献一场深度与广度兼具的冒险盛宴。这款游戏巧妙融合网络武侠元素&#xff0c;其创意十足的设计框架下&#xff0c;核心叙述聚焦于…

OSPF综合实验(超详细易懂)(HCIP)

1、拓扑信息 2、需求分析 3、IP规划 4、配置 5、测试 1、拓扑信息 2、需求分析 R4为ISP&#xff0c;其上只能配置I地址&#xff1b; R4与其他所有直连设备间均使用公有IP 公网中使用的是点到…

外贸大客户开发的三大困境

外贸大客户开发的三大困境&#xff0c;第一个是进不来&#xff0c;什么叫进不来呢&#xff1f;就是客户&#xff0c;大客户他不仅能够为企业带来大额的业绩&#xff0c;而且利润也高&#xff0c;那么也对于这种品牌也有一定的关联&#xff0c;还能为企业带来更多的一些资源&…

Python测试框架Pytest的参数化详解

上篇博文介绍过&#xff0c;Pytest是目前比较成熟功能齐全的测试框架&#xff0c;使用率肯定也不断攀升。 在实际工作中&#xff0c;许多测试用例都是类似的重复&#xff0c;一个个写最后代码会显得很冗余。这里&#xff0c;我们来了解一下pytest.mark.parametrize装饰器&…

karateclub,一个超酷的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超酷的 Python 库 - karateclub。 Github地址&#xff1a;https://github.com/benedekrozemberczki/karateclub Python karateclub是一个用于图嵌入和图聚类的库&#xff…