最近在做的功能,由于别的数据库有值,需要这边的不同入口的进来查询,所以需要同步过来,如果再继续一个一个生成列对应处理感觉不方便,如果没有别的操作,只是存储和查询,那就可以用MySql支持的json格式存储了。
MySql的json是5.7之后才可以处理的,所以版本一定要是这个或者比这个高呦!
首先第一步我们需要定义个处理json类型类,可以叫BaseAttributeTypeHandler,来继承BaseTypeHandler这个ibatis的类,一定要定义类型,后期传参用,
package xx;
import cn.hutool.core.util.StrUtil;
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.lettuce.core.dynamic.support.ResolvableType;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
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;
/**
* @Author df
* @Description: 基础类, 处理mySql字段为json类型
* @Date 2023/10/19 9:52
*/
public abstract class BaseAttributeTypeHandler<T> extends BaseTypeHandler<Object> {
private JavaType javaType;
/**
* ObjectMapper
*/
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
/**
* 构造方法
*/
public BaseAttributeTypeHandler() {
// 通过class构造一个ResolvableType对象
ResolvableType resolvableType = ResolvableType.forClass(getClass());
// 获取对应泛型实体
Type type = resolvableType.as(BaseAttributeTypeHandler.class).getGeneric() != null ?
resolvableType.as(BaseAttributeTypeHandler.class).getGeneric().getType() :
null;
// 根据对应类型构造出java类型
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);
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSONUtil.toJsonStr(parameter));
}
@Override
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
String value = rs.getString(columnName);
return convertToEntityAttribute(value);
}
@Override
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return convertToEntityAttribute(rs.getString(columnIndex));
}
@Override
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String value = cs.getString(columnIndex);
return convertToEntityAttribute(value);
}
private Object convertToEntityAttribute(String dbData) {
// 根据得到的数据判断类型
if (StrUtil.isEmpty(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);
}
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 (T) 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);
}
}
}
定义要存储的json类型的实体类,假如存储个用户信息把,我们就定义了UserSportTypeHandler,然后继承刚才的类BaseAttributeTypeHandler,传入json实体UserSport(你们自己定义的要存储或者查询出来的实体哈)
public class UserSportTypeHandler extends BaseAttributeTypeHandler<UserSport> {
}
存储时在po实体里添加如下的说明,好让MySql知道是json,这里的typeHandler则定义为UserSportTypeHandler
@Data
public class User {
private Long id;
private String username;
@TableField(jdbcType = JdbcType.OTHER, typeHandler = UserSportTypeHandler.class)
private UserSport userSport;
}
新增
调用mybatis插件直接保存即可
public class UserBusinessImpl extends ServiceImpl<UserMapper, User> implements UserBusiness {
public Boolean saveSportDataBatch(List<User> users) {
super.saveBatch(users);
}
}
测试下,可以哦,直接存储了json的数据
当然还可以存储list以及list<json>这样的格式,可以这样改。
public class UserSportTypeHandler extends BaseAttributeTypeHandler<List<UserSport>> {
}
也可以在mapper.xml里这样添加,也要指明typeHadler
<insert id="saveBatch" parameterType="java.util.List">
INSERT INTO user_sport_record (user_sport)
<foreach collection="list" separator="," item="item">
VALUES (
#{item.userSport,javaType=com.uniigym.Uniiuser.infrastructure.po.HeartDistribute,typeHandler=HeartDistributeTypeHandler,jdbcType=OTHER});
</foreach>
</insert>
查询
当然你要是自己在mapper里写,可以在resultMap下里写,示例:
<resultMap type="xx.po.User" id="user">
<result property="id" column="id" jdbcType="INTEGER"/>
<!-- json需要配置如下才能查询出来数据 -->
<result typeHandler="com.uniigym.Uniiuser.common.config.mybatis.HeartDistributeTypeHandler"
property="heartDistribute" column="heart_distribute"
jdbcType="OTHER" javaType="com.uniigym.Uniiuser.infrastructure.po.HeartDistribute"/>
</resultMap>
这样查询和添加都可以用这个,但是要在sql种指定resultMap的id,但是如果实体上写了 @TableField(jdbcType = JdbcType.OTHER, typeHandler = UserSportTypeHandler.class),就不用在ResultMap标签在定义了。如果都不配置typeHandler则关于json的字段查询出来为空,只有对了查询和保存才可以处理。