最近在做的功能,由于别的数据库有值,需要这边的不同入口的进来查询,所以需要同步过来,如果再继续一个一个生成列对应处理感觉不方便,如果没有别的操作,只是存储和查询,那就可以用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);}@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, JSONUtil.toJsonStr(parameter));}@Overridepublic Object getNullableResult(ResultSet rs, String columnName) throws SQLException {String value = rs.getString(columnName);return convertToEntityAttribute(value);}@Overridepublic Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return convertToEntityAttribute(rs.getString(columnIndex));}@Overridepublic 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的字段查询出来为空,只有对了查询和保存才可以处理。