概述
有些场景需要将db中查出的值按照业务需要进行反序列化,在mybatis原生反序列化之后再去处理,需要多些几行代码,此时可以自定义属性的反序列化操作。
需求:
在sql查询的时候使用group_by_concat查询的结果是一个逗号分隔的字符串
例如"1,2,3,4"
java中想用List去接收
字符串自定义反序列化
封装共用泛型类
package com.xxx.xxx.xxx.xxx;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import io.seata.common.util.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.core.ResolvableType;
import org.springframework.util.Assert;
import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class NestingJacksonTypeHandler<T> extends BaseTypeHandler<Object> {
private JavaType javaType;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
/**
* 构造方法
*/
public NestingJacksonTypeHandler() {
ResolvableType resolvableType = ResolvableType.forClass(getClass());
Type type = resolvableType.as(NestingJacksonTypeHandler.class).getGeneric().getType();
javaType = constructType(type);
}
private static JavaType constructType(Type type) {
Assert.notNull(type, "[Assertion failed] - type is required; it must not be null");
return TypeFactory.defaultInstance().constructType(type);
}
private Object convertToEntityAttribute(String dbData) {
if (StringUtils.isBlank(dbData)) {
if (List.class.isAssignableFrom(javaType.getRawClass())) {
return Collections.emptyList();
} else if (Set.class.isAssignableFrom(javaType.getRawClass())) {
return Collections.emptySet();
} else if (Map.class.isAssignableFrom(javaType.getRawClass())) {
return Collections.emptyMap();
} else {
return null;
}
}
return toObject(dbData, javaType);
}
/**
* 用jackson反序列化
*/
private static <T> T toObject(String json, JavaType javaType) {
Assert.hasText(json, "[Assertion failed] - this json must have text; it must not be null, empty, or blank");
Assert.notNull(javaType, "[Assertion failed] - javaType is required; it must not be null");
try {
return OBJECT_MAPPER.readValue(json, javaType);
} catch (com.fasterxml.jackson.core.JsonParseException e) {
throw new RuntimeException(e.getMessage(), e);
} catch (JsonMappingException e) {
throw new RuntimeException(e.getMessage(), e);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* java属性映射db中的存储类型
* 指定索引位置设置参数
*/
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
preparedStatement.setString(i, JSONUtil.toJsonStr(o));
}
/**
* 从db获取取出值后映射到java属性中
* 根据columnName获取属性值
*/
@Override
public Object getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
String value = resultSet.getString(columnName);
return convertToEntityAttribute(value);
}
/**
* 从db获取取出值后映射到java属性中
* 根据columnIndex获取属性值
*/
@Override
public Object getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
return convertToEntityAttribute(resultSet.getString(columnIndex));
}
/**
* 从db获取取出值后映射到java属性中
* 根据CallableStatement及columnIndex获取结果
*/
@Override
public Object getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
String value = callableStatement.getString(columnIndex);
return convertToEntityAttribute(value);
}
}
实际需要反序列化的属性的handler
package com.xxx.xxx.xxx.xxx;
import com.alibaba.fastjson.JSONObject;
/**
* 反序列化JSONObject
*/
public class JsonObjectTypeHandler extends NestingJacksonTypeHandler<JSONObject>{
}
注解使用/xml使用
注解使用
class上需要声明autoResultMap = true
,然后需要在配置文件中配置handler扫描路径
mybatis-plus:
#(路径)
type-handlers-package: com.package.handler
@Data
@TableName(value = "goods", autoResultMap = true)
public class Demo{
@TableField(typeHandler = JsonObjectTypeHandler.class)
private JSONObject reportContent;
}
xml中直接使用
可以不用再class上配置注解参数,也不需要配置文件扫描handler
<resultMap id="queryReportDataDetail" type="com.xxx.xxx.xxx.xxx.ReportDataDTO">
<result property="reportId" column="id"/>
<result property="skuNo" column="sku_no"/>
<result property="reportContent" column="report_content" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
</resultMap>