Mybatis实现数据库的Json字符串转换为Java对象的方式
在工作中遇到数据库中,某些表的字段存的是Json字符串,取出来的时候需要反序列化为Java对象,特此记录。
主要借助TypeHandler来帮助实现。
一、反序列化Json对象
前提配置
表数据如下,最主要关注function字段,现在为Json对象,后面演示Json数组的方式
对应的Java类
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Permission{
private int seq;
private String title;
private boolean countEnable;
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Code {
private int id;
private Permission function;
}
1.1 自定义类型处理器,继承BaseTypeHandler
@MappedJdbcTypes(JdbcType.VARCHAR) // 表明对应字段在数据库中的类型,也可以写在对应的SQL语句处
public class PermissionHandler extends BaseTypeHandler<Permission> {
// 序列化工具,我这里用的Jackson,也可以用gson等,需要自己写
private Serializer serializer = new Serializer();
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Permission permission, JdbcType jdbcType) throws SQLException {
preparedStatement.setString(i, serializer.encode(permission));
}
@Override
public Permission getNullableResult(ResultSet resultSet, String s) throws SQLException {
return serializer.decode(resultSet.getString(s), Permission.class);
}
@Override
public Permission getNullableResult(ResultSet resultSet, int i) throws SQLException {
return serializer.decode(resultSet.getString(i), Permission.class);
}
@Override
public Permission getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return serializer.decode(callableStatement.getString(i), Permission.class);
}
1.2 配置PermissionHandler
在Mybatis的配置文件中,需要声明自定义的处理器,否则会一直报错
org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### The error may exist in com/mediacomm/dao/IRegCodeDao.java (best guess)
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.IllegalStateException: Type handler was null on parameter mapping for property 'function'. It was either not specified and/or could not be found for the javaType (java.util.List) : jdbcType (null) combination.
【注意】mybatis的配置文件中是有顺序要求的,如果configuration字段下出现了报错,就要看一下提示的内容,我就是因为typeHandlers的位置不对。
<configuration>
......
<typeHandlers>
<typeHandler handler="com.ccc.handler.PermissionHandler"/>
</typeHandlers>
......
<configuration>
1.3 SQL语句中声明字段类型
在对应的字段上,使用javaType声明字段的类型。
前面提到的@MappedJdbcTypes(JdbcType.VARCHAR),也可以不写,然后在此处用
jdbcType = JdbcType.VARCHAR声明
public interface IDao{
@Select("select * from code")
@Results(id = "codeMap",
value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "function", property = "function", javaType = com.ccc.domain.Permission.class),
})
Code findAll();
二、反序列化Json数组
前提配置
表数据如下,function字段,现在为Json数组的方式
对应的Java类
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Permission{
private int seq;
private String title;
private boolean countEnable;
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Code {
private int id;
private List<Permission> function;
}
2.1 自定义类型处理器,继承BaseTypeHandler
@MappedJdbcTypes(JdbcType.VARCHAR)
public class PermissionHandler extends BaseTypeHandler<List<Permission>> {
private Serializer serializer = new LicenceSerializer();
@SneakyThrows
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, List<Permission> permission, JdbcType jdbcType) throws SQLException {
preparedStatement.setString(i, serializer.encode(permission));
}
@SneakyThrows
@Override
public List<Permission> getNullableResult(ResultSet resultSet, String s) throws SQLException {
// 使用Jackson解析Json数组的方式,并以集合的方式返回
return serializer.decodeList(resultSet.getString(s), Permission.class);
}
@SneakyThrows
@Override
public List<Permission> getNullableResult(ResultSet resultSet, int i) throws SQLException {
return serializer.decodeList(resultSet.getString(i), Permission.class);
}
@SneakyThrows
@Override
public List<Permission> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return serializer.decodeList(callableStatement.getString(i), Permission.class);
}
}
2.2 配置PermissionHandler
同样的,在Mybatis的配置文件中,声明自定义的处理器
<configuration>
......
<typeHandlers>
<typeHandler handler="com.ccc.handler.PermissionHandler"/>
</typeHandlers>
......
<configuration>
2.3 SQL语句中声明字段类型
【注意】此处的javaType要用List而不再是Permission
public interface IDao{
@Select("select * from code")
@Results(id = "codeMap",
value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "function", property = "function", javaType = java.util.List.class),
})
Code findAll();
二、测试结果
[Code(id=1,function=[Permission(seq=3, title=null, countEnable=false), Permission(seq=3, title=null, countEnable=false)])]```