mybatis自定义typeHandler对postgresql等支持json类型数据

博客主要讲述在使用PostgreSQL数据库时会用到json数据类型,而MyBatis默认不支持,需自定义typeHandler来处理。文中给出了JsonTypeHandler.java示例,还提到PGobject类的相关处理,最终成功解决了PostgreSQL在MyBatis中json数据类型的问题。

我们在使用PostgreSQL等数据库时会使用到json数据类型,PostgreSQL支持json和jsonb两种格式,而mybatis默认是不支持json数据类型的(在MyBatis的org.apache.ibatis.type包下面没有提供json相关的typeHandler,所以无法正确处理json),MyBatis处理json数据类型需要自定义typeHandler,具体如下:

JsonTypeHandler.java:

package com.demo.mybatis.handler;

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

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.postgresql.util.PGobject;

import com.alibaba.fastjson.JSON;

public class JsonTypeHandler<T extends Object> extends BaseTypeHandler<T> {
	private Class<T> clazz;
	public JsonTypeHandler(Class<T> clazz) {
        this.clazz = clazz;
    }
	private static final PGobject jsonObject = new PGobject();
	
    public JsonTypeHandler() {
     }
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        jsonObject.setType("json");
        jsonObject.setValue(JSON.toJSONString(parameter));
        ps.setObject(i, jsonObject);
    }
    @Override
	public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
		// TODO Auto-generated method stub
		return JSON.parseObject(rs.getString(columnName), clazz);
	}

    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return JSON.parseObject(rs.getString(columnIndex), clazz);
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return JSON.parseObject(cs.getString(columnIndex), clazz);
    }
	
}

此JsonTypeHandler依赖:fastjson

注:PGobject 为PostgreSQL数据库驱动包中的一个类,如果提示找不到PGobject,请将postgresql的pom.xml中的<scope>runtime</scope>注释,或者scope设置为默认compile,如下:

<dependency>
     <groupId>org.postgresql</groupId>
     <artifactId>postgresql</artifactId>
     <!-- <scope>runtime</scope> -->
</dependency>

这里假设有test表:

CREATE TABLE public.test(
    id inetger not null,
    img_url_list json NULL,
    PRIMARY KEY (id)
);

实体类为:

package com.demo.entity;

import com.alibaba.fastjson.JSONArray;

public class Test {
	
	// 对应字段为:id
	private int id;
	
	// 对应字段为:img_url_list
	private JSONArray imgUrlList;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public JSONArray getImgUrlList() {
		return imgUrlList;
	}
	public void setImgUrlList(JSONArray imgUrlList) {
		this.imgUrlList = imgUrlList;
	}
	
}

MyBatis的mapper文件为:

<?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.demo.entity.Test">
    <!-- select 有别名的情况: -->
   <resultMap id="listMap" type="com.demo.entity.Test">
     <!-- 这里省略普通字段,普通字段可以不用写,会自动映射 -->
     <!--column为字段名或者别名,如果select 字段有别名则为别名,property为Java实体类属性名 -->
    <result property="imgUrlList" javaType="com.alibaba.fastjson.JSONArray" column="imgUrlList" typeHandler="com.demo.mybatis.handler.JsonTypeHandler"/>
  </resultMap>
  <!-- 查询列表, -->
  <select id="select_list" resultMap="listMap">
  select id,img_url_list as "imgUrlList" from test
  </select>
  
  
   <!-- select 没有别名的情况: -->  
  <resultMap id="entityMap" type="com.demo.entity.Test">
     <!-- 这里省略普通字段,普通字段可以不用写,会自动映射 -->
     <!--column为字段名或者别名,如果select 字段有别名则为别名,property为Java实体类属性名 -->
    <result property="imgUrlList" javaType="com.alibaba.fastjson.JSONArray" column="img_url_list" typeHandler="com.demo.mybatis.handler.JsonTypeHandler"/>
  </resultMap>
  <!-- 查询一条数据, -->
  <select id="select_list2" resultMap="entityMap">
  select id,img_url_list from test
  </select>

  <insert id="insert" parameterType="Test">
  insert into test (id,img_url_list)
  values (#{id},#{imgUrlList ,typeHandler=com.demo.mybatis.handler.JsonTypeHandler})
  </insert>
    
  <update id="update" parameterType="Test">
  update test set img_url_list=#{imgUrlList ,typeHandler=com.demo.mybatis.handler.JsonTypeHandler} 
  where id=#{id}
  </update>

</mapper>

至此,成功解决了pgsql在MyBatis中json数据类型的问题。这个问题苦恼已久,终于得时间解决,特记之,以供参考。

<think> 我们正在讨论的是MyBatis-Plus中如何为resultType类配置自定义TypeHandler。注意,用户之前提到了Mybatis-plus的枚举处理器,但当前问题是如何为一般的resultType类配置自定义TypeHandler。 在MyBatis-Plus中,我们可以通过多种方式配置自定义TypeHandler。这里主要介绍两种常见场景: 1. 在实体类的字段上通过注解`@TableField`指定TypeHandler。 2. 在MyBatis的映射文件中(即XML文件)通过`<result>`标签指定TypeHandler。 需要注意的是,如果使用resultType(而不是resultMap)来映射结果集,那么默认情况下MyBatis会使用内置的类型处理器或者根据属性类型自动选择。如果要为resultType中的某个属性指定自定义TypeHandler,我们必须在实体类的相应字段上使用注解。 但是,如果使用resultMap,则可以在映射文件中显式指定TypeHandler。由于用户提到了resultType,所以重点讲解如何通过实体类注解的方式配置。 步骤: 一、创建自定义TypeHandler 首先,我们需要创建一个自定义TypeHandler,它需要继承BaseTypeHandler(来自org.apache.ibatis.type包)或者实现TypeHandler接口。 二、在实体类字段上使用@TableField注解指定TypeHandler 然后,在实体类的对应字段上添加`@TableField`注解,并通过`typeHandler`属性指定我们自定义TypeHandler。 三、全局配置(可选) 我们还可以在MyBatis-Plus的全局配置中注册自定义TypeHandler,这样MyBatis就能识别它。 下面是一个具体的例子: 1. 创建自定义TypeHandler(以处理一个自定义类型CustomType为例): ```java public class CustomTypeHandler extends BaseTypeHandler<CustomType> { @Override public void setNonNullParameter(PreparedStatement ps, int i, CustomType parameter, JdbcType jdbcType) throws SQLException { // 将CustomType对象转换为数据库存储的类型(例如字符串) ps.setString(i, parameter.toString()); } @Override public CustomType getNullableResult(ResultSet rs, String columnName) throws SQLException { // 从结果集中获取字符串并转换为CustomType String value = rs.getString(columnName); return value == null ? null : new CustomType(value); } // ... 其他重写方法 } ``` 2. 在实体类字段上使用注解: ```java public class User { private Long id; private String name; @TableField(typeHandler = CustomTypeHandler.class) private CustomType customField; // getters and setters } ``` 3. 在MyBatis-Plus的配置类中,我们可以通过自定义MybatisConfiguration来注册TypeHandler(这一步可选,因为在字段注解上已经指定,但有时为了全局识别,也可以注册): ```java @Configuration public class MybatisPlusConfig { @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> { // 注册自定义TypeHandler configuration.getTypeHandlerRegistry().register(CustomTypeHandler.class); }; } } ``` 或者,如果你已经使用了MybatisPlusInterceptor,可以同时配置这个自定义器。 注意:如果使用的是XML映射文件,那么也可以在XML中配置: ```xml <resultMap id="userResultMap" type="User"> <result column="custom_field" property="customField" typeHandler="com.example.CustomTypeHandler"/> </resultMap> ``` 但是,如果查询使用的是resultType="User",那么上述注解方式已经生效。因为MyBatis在通过resultType自动映射时,会读取实体类字段上的注解(包括@TableField中的typeHandler属性)。 总结: 对于resultType,我们通过在实体类字段上添加`@TableField(typeHandler = ...)`注解来指定自定义TypeHandler。 另外,用户之前引用的内容中提到了枚举处理器,这与我们讨论的自定义TypeHandler原理相同。枚举处理器也是TypeHandler的一种。 相关问题: §§相关问题§§ 1. 如何为MyBatis-Plus中的枚举类型配置自定义TypeHandler? 2. 在MyBatis-Plus中,如何同时使用多个TypeHandler? 3. 自定义TypeHandler在插入和查询时的工作流程是怎样的? 4. 如何调试MyBatis-Plus中TypeHandler的执行? </think> 在 MyBatis-Plus 中为 `resultType` 类配置自定义 TypeHandler 可以通过以下三种方式实现,这些方法能确保类型转换在查询结果映射时自动执行: --- ### 方法一:字段级别注解(推荐) 在实体类字段上直接使用 `@TableField` 注解指定 TypeHandler: ```java public class User { @TableField(typeHandler = CustomJsonTypeHandler.class) private Map<String, Object> attributes; // 自定义类型字段 } ``` **原理**:当 MyBatis-Plus 映射结果集时,自动使用指定的 TypeHandler 处理该字段[^1]。 --- ### 方法二:全局注册 TypeHandlerMyBatis 配置文件中全局注册 TypeHandler: ```xml <!-- mybatis-config.xml --> <typeHandlers> <!-- 指定处理的Java类型 --> <typeHandler handler="com.example.CustomJsonTypeHandler" javaType="java.util.Map"/> </typeHandlers> ``` **效果**:所有返回 `Map` 类型的字段都会自动使用该处理器。 --- ### 方法三:XML 映射文件配置 在 Mapper XML 文件中显式定义结果映射: ```xml <resultMap id="userResultMap" type="User"> <result column="attributes" property="attributes" typeHandler="com.example.CustomJsonTypeHandler"/> </resultMap> <select id="selectUser" resultMap="userResultMap"> SELECT * FROM user </select> ``` --- ### 🔧 自定义 TypeHandler 实现示例 以处理 JSON 字段为例: ```java public class CustomJsonTypeHandler extends BaseTypeHandler<Map<String, Object>> { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public void setNonNullParameter(...) throws SQLException { // 将Map转为JSON字符串存入数据库 ps.setString(i, objectMapper.writeValueAsString(parameter)); } @Override public Map<String, Object> getNullableResult(...) throws SQLException { // 从数据库读取JSON字符串转为Map String json = rs.getString(columnName); return objectMapper.readValue(json, new TypeReference<Map<String, Object>>(){}); } } ``` --- ### 📌 关键注意事项 1. **优先级顺序** 字段注解 > XML配置 > 全局配置(高优先级覆盖低优先级) 2. **枚举类型特殊处理** 如需处理枚举类型,可直接使用内置处理器: ```yaml # application.yml mybatis-plus: configuration: default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler ``` 3. **复杂类型支持** TypeHandler 支持处理任意复杂类型(如 JSON 对象、几何坐标等),只需实现对应的序列化/反序列化逻辑 4. **调试技巧** 若处理器未生效,检查: - 包路径是否正确 - Java 类型是否匹配 - 是否被更高优先级配置覆盖 --- ### 🌰 使用场景示例 假设数据库存储 JSON 字段: ```sql CREATE TABLE user ( id BIGINT, attributes JSON -- PostgreSQL/MySQL的JSON类型 ); ``` 通过自定义 TypeHandler 可自动完成 Java Map ↔ JSON 的转换。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值