MyBatis-Plus 实现PostgreSQL数据库jsonb类型的保存与查询
新建Jsonb处理类
方式 1
/**
* PostgreSQL jsonb 数据处理器
*
* @author CoderKK
* @date 2025/09/08
*/
@MappedTypes({Object.class})
@MappedJdbcTypes(JdbcType.OTHER)//JSONB对应JdbcType.OTHER
public class JsonbTypeHandler extends BaseTypeHandler<Object> {
private static final PGobject jsonObject = new PGobject();
private static final String JSONB_STR = "jsonb";
private static final String JSON_STR = "json";
/**
* 写数据库时,把Java对象转成JSONB类型
*/
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
if (preparedStatement != null) {
jsonObject.setType(JSONB_STR);
jsonObject.setValue(JSON.toJSONString(o));
preparedStatement.setObject(i, jsonObject);
}
}
@Override
public Object getNullableResult(ResultSet resultSet, String s) throws SQLException {
return JSON.parse(resultSet.getString(s));
}
@Override
public Object getNullableResult(ResultSet resultSet, int i) throws SQLException {
return JSON.parse(resultSet.getString(i));
}
@Override
public Object getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return JSON.parse(callableStatement.getString(i));
}
}
方式 2
如果数据库字段是字符类型,可以直接使用Mybatis-Plus内置的JacksonTypeHandler,如果是像PostgreSQL数据库的JSONB类型,则需要自定义开发一个TypeHandler,可以继承JacksonTypeHandler,然后覆写父类的方法,代码如下:
/**
* PostgreSQL数据库中的JSON、JSONB字段类型的处理程序
*
* @author CoderKK
* @date 2025/09/08
*/
@MappedTypes({Object.class})
@MappedJdbcTypes(JdbcType.OTHER)// JSONB对应JdbcType.OTHER
public class JsonbTypeHandler extends JacksonTypeHandler {
private static final PGobject jsonObject = new PGobject();
private static final String JSONB = "jsonb";
private static final String JSON = "json";
public JsonbTypeHandler(Class<?> type) {
super(type);
}
/**
* 写数据库时,把java对象转成JSONB类型
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
if (ps != null) {
jsonObject.setType(JSONB);
jsonObject.setValue(toJson(parameter));
ps.setObject(i, jsonObject);
}
}
/**
* 读数据时,把JSONB类型的字段转成java对象
*/
@Override
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
Object v = rs.getObject(columnName);
return convertDbToJavaObject(v);
}
/**
* 读数据时,把JSONB类型的字段转成java对象
*/
@Override
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Object v = rs.getObject(columnIndex);
return convertDbToJavaObject(v);
}
/**
* 读数据时,把JSONB类型的字段转成java对象
*/
@Override
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Object v = cs.getObject(columnIndex);
return convertDbToJavaObject(v);
}
/**
* 读数据时,把JSONB类型的字段转成java对象
*/
private Object convertDbToJavaObject(Object v) {
if (Objects.isNull(v)) {
return null;
}
if (!PGobject.class.isAssignableFrom(v.getClass())) {
return v;
}
PGobject p = (PGobject) v;
String type = p.getType();
if (type == null) {
return v;
}
if (!JSONB.equalsIgnoreCase(type) && !JSON.equalsIgnoreCase(type)) {
return v;
}
String pv = p.getValue();
if (StringUtils.isBlank(pv)) {
return v;
}
try {
return parse(pv);
} catch (Exception e) {
// 根据实际业务需求,可以选择返回null、抛出异常或返回原始值
return v;
}
}
}
推荐方式 2 可以兼容所有类型自动转换,其他类型例如数组类型等都可以写自定义转换器实现
使用JacksonTypeHandler可以帮开发者自动处理json格式与java对象之间的映射关系,不需要每次手动做序列化和反序列化的工作了。
PostgreSQL 整数数组类型处理程序
/**
* PostgreSQL 整数数组类型处理程序
*
* @author CoderKK
* @date 2025/09/08
*/
public class IntegerArrayTypeHandler extends BaseTypeHandler<Integer[]> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Integer[] parameter, JdbcType jdbcType) throws SQLException {
if (parameter != null && parameter.length > 0) {
StringBuilder sb = new StringBuilder("{");
for (int j = 0; j < parameter.length; j++) {
sb.append(parameter[j]);
if (j < parameter.length - 1) {
sb.append(",");
}
}
sb.append("}");
ps.setString(i, sb.toString());
} else {
ps.setNull(i, java.sql.Types.VARCHAR);
}
}
@Override
public Integer[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
String str = rs.getString(columnName);
return parseString(str);
}
@Override
public Integer[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String str = rs.getString(columnIndex);
return parseString(str);
}
@Override
public Integer[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String str = cs.getString(columnIndex);
return parseString(str);
}
private Integer[] parseString(String str) {
if (str == null || !str.startsWith("{") || !str.endsWith("}")) {
return null;
}
// 去掉首尾的大括号
String content = str.substring(1, str.length() - 1);
if (content.isEmpty()) {
return new Integer[0];
}
String[] parts = content.split(",");
Integer[] result = new Integer[parts.length];
for (int i = 0; i < parts.length; i++) {
result[i] = Integer.parseInt(parts[i]);
}
return result;
}
}
优化版IntegerArrayTypeHandler (推荐使用此方法)
/**
* PostgreSQL 整数数组类型处理程序
*
* @author CoderKK
* @date 2025/09/08
*/
@Slf4j
public class IntegerArrayTypeHandler extends BaseTypeHandler<Integer[]> {
// PostgreSQL 数组常量定义
private static final String EMPTY_ARRAY = "{}";
private static final String ARRAY_START = "{";
private static final String ARRAY_END = "}";
private static final String DELIMITER = ",";
/**
* 设置非空参数到 PreparedStatement
*
* @param ps PreparedStatement 对象
* @param i 参数位置
* @param parameter 要设置的 Integer 数组
* @param jdbcType JDBC 类型
* @throws SQLException 如果数据库访问出错
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Integer[] parameter, JdbcType jdbcType) throws SQLException {
// 将 Integer 数组转换为 PostgreSQL 数组字符串格式
ps.setString(i, toPgArrayString(parameter));
}
/**
* 从 ResultSet 中通过列名获取结果
*
* @param rs ResultSet 对象
* @param columnName 列名
* @return 解析后的 Integer 数组,可能为 null
* @throws SQLException 如果数据库访问出错
*/
@Override
public Integer[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
return parsePgArray(rs.getString(columnName));
}
/**
* 从 ResultSet 中通过列索引获取结果
*
* @param rs ResultSet 对象
* @param columnIndex 列索引
* @return 解析后的 Integer 数组,可能为 null
* @throws SQLException 如果数据库访问出错
*/
@Override
public Integer[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return parsePgArray(rs.getString(columnIndex));
}
/**
* 从 CallableStatement 中获取结果
*
* @param cs CallableStatement 对象
* @param columnIndex 列索引
* @return 解析后的 Integer 数组,可能为 null
* @throws SQLException 如果数据库访问出错
*/
@Override
public Integer[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return parsePgArray(cs.getString(columnIndex));
}
/**
* 将 Integer 数组转换为 PostgreSQL 数组字符串格式
*
* @param array 要转换的 Integer 数组
* @return PostgreSQL 数组格式的字符串,空数组返回 "{}"
*/
private String toPgArrayString(Integer[] array) {
// 处理 null 或空数组
if (array == null || array.length == 0) {
return EMPTY_ARRAY;
}
// 使用流式处理过滤 null 元素并转换为字符串
return Stream.of(array)
.filter(Objects::nonNull) // 过滤掉 null 元素
.map(String::valueOf) // 转换为字符串
.collect(Collectors.joining(
DELIMITER, // 分隔符
ARRAY_START, // 前缀
ARRAY_END // 后缀
));
}
/**
* 解析 PostgreSQL 数组字符串为 Integer 数组
*
* @param pgArray PostgreSQL 数组格式的字符串
* @return 解析后的 Integer 数组,输入为 null 时返回 null,空数组返回空数组
* @throws IllegalArgumentException 如果数组格式无效或包含无法解析的元素
*/
private Integer[] parsePgArray(String pgArray) {
// 处理 null 输入
if (pgArray == null) {
return null;
}
// 处理空数组
if (EMPTY_ARRAY.equals(pgArray)) {
return new Integer[0];
}
// 验证数组格式是否正确
if (!pgArray.startsWith(ARRAY_START) || !pgArray.endsWith(ARRAY_END)) {
log.error("Invalid PostgreSQL array format: {}", pgArray);
return null;
}
try {
// 提取数组内容部分
String content = pgArray.substring(1, pgArray.length() - 1);
// 处理空内容情况
if (content.isEmpty()) {
return new Integer[0];
}
// 分割、清理并转换数组元素
return Arrays.stream(content.split(DELIMITER))
.map(String::trim) // 去除空格
.filter(s -> !s.isEmpty()) // 过滤空字符串
.map(Integer::valueOf) // 转换为 Integer
.toArray(Integer[]::new); // 收集为数组
} catch (NumberFormatException e) {
log.error("Error occurred while parsing PostgreSQL array: {}", pgArray, e);
}
return null;
}
}
创建实体类
1️⃣设置 autoResultMap = true,自动为实体类生成一个结果映射
2️⃣字段上添加处理器
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder(toBuilder = true)
@TableName(value = "t_uz_word_assess", autoResultMap = true)
public class WordAssessPO implements Serializable {
/**
* 主键ID
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 定位点(x1,x2,y1,y2)
*/
@TableField(value = "point", typeHandler = IntegerArrayTypeHandler.class)
private Integer[] point;
/**
* 各维度得分
*/
@TableField(value = "dim_score", typeHandler = JsonbTypeHandler.class)
private EvalDim dimScore;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
}
原始Mybatis映射
<resultMap id="ReportInfo" type="com.xx.entity.ReportInfo">
<result property="currentHandler" column="current_handler" javaType="java.util.List" typeHandler="com.xx.utils.JSONTypePgHandler"></result>
</resultMap>
本文来自博客园,作者:Micky233,转载请注明原文链接:https://chuna2.787528.xyz/geek233/p/19080222

浙公网安备 33010602011771号