MySQL读取JSON转换
ItOYoung 人气:0存储
mysql5.7+开始支持存储JSON,后续不断优化,应用也越来越广泛 你可以自己将数据转换成Json String后插入,也可以选择使用工具, 而mybatis-plus就为此提供了非常简便的方式, 只需要在字段上加上 @TableField(typeHandler = XxxTypeHandler.class), mybatis-plus就会自动帮你做转换,通用一般就两个: - com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler - com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler
例如
@Data @TableName(autoResultMap = true) public class Department implements Serializable { private static final long serialVersionUID = 203788572415896870L; @TableField(typeHandler = FastjsonTypeHandler.class) private List<Integer> userIds; }
存在什么问题?
如果使用通用处理器,那对于基础类型以及对象来说没有什么问题。 但如果存储的字段类型是对象集合,那么当你取出来时,会发现集合中的对象都是JSONObject类型。 最常见的情况就拿出来进行遍历操作时,会抛出强转异常: java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to ... 因为处理器帮你转换时,并不会存储你集合的泛型,所以统统都按照Object类型来转换了: @Override protected Object parse(String json) { return JSON.parseObject(json, type); }
例如下面这种形式的类:
@Data @TableName(autoResultMap = true) public class Department implements Serializable { private static final long serialVersionUID = 203788572415896870L; @TableId(value = "id", type = IdType.AUTO) private Integer id; @TableField(typeHandler = FastjsonTypeHandler.class) private List<User> users; @Data public static class USer implements Serializable { // ... } }
如何处理
方式一:自定义处理器,自己做类型转换,这也是当前最普遍的方式,但是对于存在List字段的对象,还需要在XxxMapper.xml中进行resultMap配置
@MappedTypes({Object.class}) @MappedJdbcTypes(JdbcType.VARCHAR) public class ListFastJsonTypeHandler extends FastjsonTypeHandler { private final Class<? extends Object> type; public ListFastJsonTypeHandler(Class<?> type) { super(type); this.type = type; } /** * 自己将json转换成list * @param json * @return */ @Override protected Object parse(String json) { return JSON.parseArray(json, this.type); }
<mapper namespace="com.xxx.cn.mapper.DepartmentMapper"> <resultMap id="BaseResultMap" type="com.xxx.cn.domain.Department"> <id property="id" column="id"/> <result property="users" column="users" jdbcType="VARCHAR" javaType="com.xxx.cn.domain.Department.User" typeHandler="com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler"/> </resultMap> </mapper>
配置完成后,ListFastJsonTypeHandler就会将json转换成javaType对应的对象集合了
方式二:配置一个Mybatis插件,拦截ResultSetHandler,将返回结果进行处理。 这样的好处就是不用写自定义的处理器和在XxxMapper.xml中做配置,减少了工作
@Component @Intercepts({ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}) }) public class ResultSetInterceptor implements Interceptor { /** * json序列化规则 */ private final SerializerFeature[] serializerFeatures = { SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty }; @Override public Object intercept(Invocation invocation) throws Throwable { Object proceed = invocation.proceed(); if (containJSONObject(proceed)) { if (proceed instanceof Collection) { return JSON.parseArray(JSON.toJSONString(proceed, serializerFeatures), ((Collection<?>) proceed).toArray()[0].getClass()); } return JSON.parseObject(JSON.toJSONString(proceed, serializerFeatures), proceed.getClass()); } // if (proceed instanceof Collection) { // for (Object obj : ((Collection<?>) proceed)) { // parseJSON2Object(obj, obj.getClass()); // } // } else { // parseJSON2Object(proceed, proceed.getClass()); // } return proceed; } * 将返回数据中心的JSONObject对象转换成正常的对象 * * @param obj * @param typeClass * @throws IllegalAccessException * @throws ClassNotFoundException private void parseJSON2Object(Object obj, Class<?> typeClass) throws IllegalAccessException, ClassNotFoundException { for (Field declaredField : typeClass.getDeclaredFields()) { declaredField.setAccessible(true); Object value = declaredField.get(obj); if (isNullValueField(value)) { continue; Type genericType = declaredField.getGenericType(); String fieldClassName = genericType.getTypeName(); if (genericType instanceof ParameterizedType) { fieldClassName = ((ParameterizedType) genericType).getActualTypeArguments()[0].getTypeName(); if (containJSONObject(value)) { if (value instanceof Collection) { declaredField.set(obj, JSON.parseArray(JSON.toJSONString(value, serializerFeatures), Class.forName(fieldClassName))); } else { declaredField.set(obj, JSON.parseObject(JSON.toJSONString(value, serializerFeatures), Class.forName(fieldClassName))); } * 判断是否跳过字段 * @param value * @return private Boolean isNullValueField(Object value) { return null == value || "".equals(String.valueOf(value).trim()) || (value instanceof Collection && ((Collection<?>) value).size() == 0); * 判断值是否包含JSONObject对象 private boolean containJSONObject(Object value) throws IllegalAccessException { if (isNullValueField(value)) { return false; if (value instanceof Collection) { for (Object obj : (Collection<?>) value) { if (obj instanceof JSONObject) { return true; if (obj instanceof Collection && containJSONObject(obj)) { for (Field declaredField : obj.getClass().getDeclaredFields()) { declaredField.setAccessible(true); Object fieldValue = declaredField.get(obj); if (isNullValueField(fieldValue)) { continue; } if (fieldValue instanceof JSONObject) { return true; if (fieldValue instanceof Collection && containJSONObject(fieldValue)) { } return value instanceof JSONObject; }
加载全部内容