问题描述

今天在使用mybatis-plus的时候向postgresql数据库添加json格式的数据时,突然报了错

场景重现

当我们在使用代码生成器生成的实体类对象中默认是String类型的,但是存储的时候他又会报出异常

org.postgresql.util.PSQLException: ERROR: column "form_data" is of type json but expression is of type character varying

image-20220629142258534

在经过多方查验之后发现,存储的类型是字符串是不能够直接存储进数据库的,需要我们通过类型转换让他进行自动转换存储进去

尝试方法

在各方面查找之后,发现可以使用SpringBoot自带的JacksonTypeHandler类自动进行json处理,有的存储的是一个Object,有的存储的是一个Map<String, Object>,但是经过多次尝试,最终都是没有成功的

个人解决办法

在使用了Mybatis-Plus自己封装的TypeHandler无法生效之后,我尝试自己封装一个typeHandler来完成我的目标

  1. 封装一个typeHandler类

JsonTypeHandler.java

@MappedTypes(Map.class)
@MappedJdbcTypes(JdbcType.OTHER)
public class JsonTypeHandler extends BaseTypeHandler<Map<String, Object>> {
    private static final PGobject jsonObject = new PGobject();

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @SneakyThrows
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Map<String, Object> stringObjectMap, JdbcType jdbcType) throws SQLException {
        jsonObject.setType("json");
        jsonObject.setValue(objectMapper.writeValueAsString(stringObjectMap));
        preparedStatement.setObject(i, jsonObject);
    }

    @SneakyThrows
    @Override
    public Map<String, Object> getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return objectMapper.readValue(resultSet.getString(s), Map.class);
    }

    @SneakyThrows
    @Override
    public Map<String, Object> getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return objectMapper.readValue(resultSet.getString(i), Map.class);
    }

    @SneakyThrows
    @Override
    public Map<String, Object> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return objectMapper.readValue(callableStatement.getString(i), Map.class);
    }
}
  1. 在实体类中使用自定义的typeHandler,并将对应的类型改为Map<String, Object>
@Setter
@Getter
@TableName(value = "t_json_test", autoResultMap = true)
public class JsonTestEntity {
    @TableId(value = "id", type = IdType.ASSIGN_UUID)
    private String id;

    @TableField(value = "form_key")
    private String formKey;

    @TableField(value = "form_data", typeHandler = JsonTypeHandler.class)
    private Map<String, Object> formData;
}
  1. 在Mapper.xml文件中声明typeHandler
<?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.wenze.mapper.JsonTestMapper">
    <resultMap id="BaseResultMap" type="com.wenze.entity.JsonTestEntity">
        <!--@mbg.generated-->
        <!--@Table t_json_test-->
        <id column="id" jdbcType="CHAR" property="id" />
        <result column="form_key" jdbcType="VARCHAR" property="formKey" />
        <result column="form_data" jdbcType="OTHER" property="formData" typeHandler="com.wenze.handler.JsonTypeHandler" />
    </resultMap>
    <sql id="Base_Column_List">
        <!--@mbg.generated-->
        id, form_key, form_data
    </sql>
</mapper>
  1. 修改我们其他代码中与实体类字段相关联的部分,保证其可以正常运行

然后我们就可以正常添加json类型的数据了,只不过在之前需要将其转换为Map类型的

image-20220629144851339

今天的问题就解决了,可能有些地方我写的时候没有遇到,大家遇到什么问题我们可以共同探讨