Mybatis-Plus+JPA+postgresql存储复杂类型、TypeHandle使用

文章介绍了在使用Mybatis-Plus和PostgreSQL进行开发时,如何处理Object和List<Object>类型的对象,将其转换为JSON字符串存储到数据库。通过自定义TypeHandler和利用Jackson库进行序列化与反序列化,实现了在存取数据时的自动格式化。同时,文章提供了一个自定义的JsonTypeHandle示例,并展示了测试结果,强调了这种方法的通用性,但也指出其可能缺乏类型约束的问题。
摘要由CSDN通过智能技术生成

在使用Mybatis-Plus + PostgreSQL开发时,我们会遇到一种情况,需要将Object类型或者List<Object>类型数据存入数据库,这时候我们需要将数据转化为jsonString以字符串的形式存入数据库,我在学习过程中发现,List格式的jsonString在直接存入postgreSql时会报错。那么有没有一种好的方式可以在存入和取出时自动对Object和List<Object>进行格式化呢?Mybatis-Plus为我们提供了TypeHandle接口,供用户进行自定义属性转换。下面列举了一些例子。

一、Entity定义

package com.xia.xiatest.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.vladmihalcea.hibernate.type.array.IntArrayType;
import com.vladmihalcea.hibernate.type.array.StringArrayType;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import com.vladmihalcea.hibernate.type.json.JsonStringType;
import com.xia.xiatest.typeHandle.JsonTypeHandle;
import lombok.Data;
import org.apache.ibatis.type.ArrayTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
import javax.persistence.*;
import java.util.List;

@Data
@Entity
@Table(name = "banner")
@TableName(value = "banner",autoResultMap = true)
@TypeDefs(value = {
        @TypeDef(name = "string-array", typeClass = StringArrayType.class),
        @TypeDef(name = "int-array", typeClass = IntArrayType.class),
        @TypeDef(name = "json", typeClass = JsonStringType.class),
        @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})

public class Banner {
    @TableId(value = "id", type = IdType.AUTO)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @TableField(value = "num_arr", jdbcType = JdbcType.ARRAY, typeHandler = ArrayTypeHandler.class)
    @Type(type = "int-array")
    @Column(columnDefinition = "int[]")
    private Integer[] numArr;

    @TableField(value = "str_arr", jdbcType = JdbcType.ARRAY, typeHandler = ArrayTypeHandler.class)
    @Type(type = "string-array")
    @Column(columnDefinition = "varchar[]")
    private String[] strArr;

    @TableField(value = "json_obj", jdbcType = JdbcType.VARCHAR, typeHandler = JsonTypeHandle.class)
    @Type(type = "jsonb")
    @Column(columnDefinition = "varchar")
    private List<Object> jsonObj;
}
  1. @TableName(value = "banner",autoResultMap = true) autoResultMap必须设置为true,这里是mybatis-plus序列化使用。

  1. @Type要设置为jsonb,@Column设置为varchar。这里是给JPA自动建表用。

二、序列化与反序列化静态方法编写

package com.xia.xiatest.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xia.xiatest.exception.http.SystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

@Component
public class GenericAndJson {
    private static ObjectMapper mapper;

    @Autowired
    private ObjectMapper mapper1;

    @PostConstruct
    public void setMapper(){
        mapper = mapper1;
    }

//    两种静态属性注入方式
//    @Autowired
//    public void setMapper(ObjectMapper mapper) {
//        GenericAndJson.mapper = mapper;
//    }

    public static <T> String objectToJson(T obj) {
        try {
            String str = mapper.writeValueAsString(obj);
            return str;

        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new SystemException(500);
        }
    }
    public static <T> T jsonToObject(String s, TypeReference<T> tr) {
        try {
            if(s == null) {
                return null;
            }
            T t = mapper.readValue(s, tr);
            return t;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new SystemException(500);
        }
    }
//    两种方法,其实有上面那个就够了
    public static <T> List<T> jsonToList(String s) {
        try {
            if(s == null) {
                return null;
            }
            List<T> t = mapper.readValue(s, new TypeReference<List<T>>(){
            });
            return t;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new SystemException(500);
        }
    }
}

三、自定义TypeHandle

package com.xia.xiatest.typeHandle;

import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.xia.xiatest.utils.GenericAndJson;
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 JsonTypeHandle<T> extends BaseTypeHandler<T> {

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, T t, JdbcType jdbcType) throws SQLException {
        if(ObjectUtil.isNotEmpty(t)){
            String str = GenericAndJson.objectToJson(t);
            preparedStatement.setString(i, str);
        }else{
            preparedStatement.setString(i, null);
        }

    }

    @Override
    public T getNullableResult(ResultSet resultSet, String s) throws SQLException {
        String str = resultSet.getString(s);
        if(str == null){
            return null;
        } else {
            T result = GenericAndJson.jsonToObject(str, new TypeReference<T>() {
            });
            return result == null? null : result;
        }

    }

    @Override
    public T getNullableResult(ResultSet resultSet, int i) throws SQLException {
        String str = resultSet.getString(i);
        if(str == null){
            return null;
        } else {
            T result = GenericAndJson.jsonToObject(str, new TypeReference<T>() {
            });
            return result == null? null : result;
        }
    }

    @Override
    public T getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        String str = callableStatement.getString(i);
        if(str == null){
            return null;
        } else {
            T result = GenericAndJson.jsonToObject(str, new TypeReference<T>() {
            });
            return result == null? null : result;
        }
    }
}

这样就可以在Entity中使用啦

 @TableField(value = "json_obj", jdbcType = JdbcType.VARCHAR, typeHandler = JsonTypeHandle.class)

四、测试一下

存入截图

返回数据截图

五、优缺点总结

  1. 优点:通用,不用定义多个TypeHandle。

  1. 缺点:这种通用方式反序列化出来的对象没有类型约束,如图jsonObject反序列化出来的类型为LinkedHashMap,如果有类型约束需求,则需要给不同的类型定义不同的TypeHandle。

Mybatis-plus是一个基于Mybatis的增强工具,它提供了一些常用的插件来增加开发效率和功能。其中,Mybatis-plus-join是一个用于解决Mybatis-plus在多表连接查询方面的不足的工具。它能够对Mybatis-plus进行功能升级,使其能够进行多表连接查询,从而摆脱了传统的XML模式多表连接的限制。使用Mybatis-plus-join可以提高开发效率,而且使用方法与Mybatis-plus一样,学习成本较低。另外,Mybatis-plus还提供了其他常用的插件,如自动分页插件、防止全表更新与删除插件、乐观锁插件等,可以根据需要进行配置和使用。如果想要使用Mybatis-plus插件,需要在配置类或启动类中进行相应的配置,比如配置分页插件,可以通过添加PaginationInnerInterceptor来实现。具体的配置方法可以参考相关文档或示例代码。 #### 引用[.reference_title] - *1* [Mybatis-plus做连接查询的插件Mybatis-plus-join](https://blog.csdn.net/m0_67400973/article/details/126463252)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [MyBatis-Plus 常用插件](https://blog.csdn.net/m0_53067943/article/details/126112463)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值