Mybatis——数据库json字段映射实体类
场景:数据库varchar字段存放json格式字符串数据,Mybatis查询解析json数据映射到实体类属性变量。
相关依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.10</version>
</dependency>
Json解析工具类:
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.TypeUtil;
/**
* @Title: JsonUtil
* @Description: Json工具类,暂时内部使用fastjson实现
* @version V1.0
*/
public class JsonUtil {
private JsonUtil() {}
public static String obj2json(Object obj) {
return obj2json(obj, DateUtil.DATE_TIME_PATTERN);
}
/**
*
* @Description:
* @param obj
* @param beIgnoreNull 是否忽略null值
* @param beFormat 是否格式化
* @param dataFormat 指定日期格式化
* @return
*/
public static String obj2json2(Object obj, boolean beIgnoreNull, boolean beFormat, String dataFormat) {
List<SerializerFeature> features = new ArrayList<>();
if (!beIgnoreNull) {
features.add(SerializerFeature.WriteMapNullValue);
features.add(SerializerFeature.DisableCircularReferenceDetect);
features.add(SerializerFeature.WriteNullStringAsEmpty);
features.add(SerializerFeature.WriteNullListAsEmpty);
features.add(SerializerFeature.WriteDateUseDateFormat);
}
if (beFormat) {
features.add(SerializerFeature.PrettyFormat);
}
features.add(SerializerFeature.WriteDateUseDateFormat);
return obj2json2(obj, dataFormat, features.toArray(new SerializerFeature[] {}));
}
public static String obj2json2(Object obj, boolean beIgnoreNull, boolean beFormat) {
return obj2json2(obj, beIgnoreNull, beFormat, DateUtil.DATE_TIME_PATTERN);
}
public static String obj2json2(Object obj, boolean beIgnoreNull) {
return obj2json2(obj, beIgnoreNull, false);
}
public static String obj2json2(Object obj) {
return obj2json2(obj, false);
}
/**
*
* @Description: 对象转json
* @param obj
* 对象
* @param beFormat
* 是否格式化
* @return json字符串
*/
public static String obj2json(Object obj, boolean beFormat) {
return obj2json2(obj, false, beFormat);
}
/**
*
* @Description: 对象转json
* @param obj
* @param dataFormat 日期格式
* @return
*
* 如果java bean的Date类型属性需要特殊处理,使用注解
* @com.alibaba.fastjson.annotation.JSONField
*/
public static String obj2json(Object obj, String dataFormat) {
return obj2json2(obj, false, false, dataFormat);
}
private static String obj2json2(Object obj, String dataFormat, SerializerFeature... feature) {
String defaultFormat = JSONObject.DEFFAULT_DATE_FORMAT;
JSONObject.DEFFAULT_DATE_FORMAT = dataFormat;
String json = JSON.toJSONString(obj, feature);
JSONObject.DEFFAULT_DATE_FORMAT = defaultFormat;
return json;
}
/**
*
* @Description: xml转json
* @param xml
* @return json字符串
*/
public static String xml2json(String xml) {
return cn.hutool.json.JSONUtil.xmlToJson(xml).toJSONString(0);
}
/**
*
* @Description: json转对象
* @param jsonString
* @param beanClass
* @return 实体类对象
*/
public static <T> T json2Obj(String jsonString, Class<T> beanClass) {
return JSON.parseObject(jsonString, beanClass);
}
/**
*
* @Description JSON字符串转为实体类对象,转换异常将被抛出
*
* @param <T>
* Bean类型
* @param jsonString
* JSON字符串
* @param typeReference
* {@link TypeReference}类型参考子类,可以获取其泛型参数中的Type类型
* @param ignoreError
* 是否忽略错误
* @return 实体类对象
*/
public static <T> T json2Obj(String jsonString, com.sf.nwms.core.util.lang.TypeReference<T> typeReference,
boolean ignoreError) {
/* return cn.hutool.json.JSONUtil.toBean(jsonString, TypeUtil.getTypeArgument(typeReference.getClass()),
ignoreError);*/
return json2Obj(jsonString, typeReference);
}
/**
*
* @Description:
* @param <T>
* @param jsonString
* @param typeReference
* @return
*
* eg: JsonUtil.json2Obj(jsonString, new com.sf.nwms.core.util.lang.TypeReference<List<JavaBean>())
*/
public static <T> T json2Obj(String jsonString, com.sf.nwms.core.util.lang.TypeReference<T> typeReference) {
return JSON.parseObject(jsonString, TypeUtil.getTypeArgument(typeReference.getClass()));
}
/**
*
* @Description: json转对象
* @param jsonString
* json字符串
* @param beanType
* 实体类对象类型
* @param ignoreError
* 是否忽略错误
* @return 实体类对象
*/
public static <T> T json2Obj(String jsonString, Type beanType, boolean ignoreError) {
return JSON.parseObject(jsonString, beanType);
}
}
使用到日期工具类:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
/**
* @Title: DateUtils
* @Description: 日期工具类
*/
public class DateUtil {
/** 分 */
public static final long MINUTE_TTL = 60 * 1000L;
/** 时 */
public static final long HOURS_TTL = 60 * 60 * 1000L;
/** 半天 */
public static final long HALF_DAY_TTL = 12 * 60 * 60 * 1000L;
/** 天 */
public static final long DAY_TTL = 24 * 60 * 60 * 1000L;
/** 月 */
public static final long MONTH_TTL = 30 * 24 * 60 * 60 * 1000L;
/** 时间格式(yyyy-MM-dd) */
public final static String DATE_PATTERN = "yyyy-MM-dd";
/** 时间格式(yyyy-MM-dd'T'HH:mm:ss.SSSZ) */
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ";
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(DATE_TIME_PATTERN);
}
};
public static Long getSystemTimeSeconds() {
return System.currentTimeMillis() / 1000L;
}
/**
* @Description: 将时间戳转换为时间
* 输入形如:148851067484755 输出形如:2017-03-03T11:11:14.000+0800
* 异常格式返回-1
* @param s
* @return
*/
public static String getTimestampDateTimeLong(Long s) {
String res;
Date date = new Date(s * 1000);
res = simpleDateFormatThreadLocal.get().format(date);
return res;
}
/**
*
* @Description: 将时间戳转换为时间
* @param s 毫秒数
* @return
*/
public static String getTimestampDateLong(Long s) {
return simpleDateFormatThreadLocal.get().format(new Date(s));
}
/**
*
* @Description: 日期格式化 日期格式为:yyyy-MM-dd
* @param date 日期
* @return 返回yyyy-MM-dd格式日期
*/
public static String formatShort(Date date) {
return format(date, DATE_PATTERN);
}
/**
*
* @Description: 日期格式化 日期格式为:yyyy-MM-dd'T'HH:mm:ss.SSSZ
* @param date 日期
* @return 返回
*/
public static String formatLong(Date date) {
return format(date, DATE_TIME_PATTERN);
}
/**
*
* @Description: 格式化时间
* @param date
* @param pattern
* @return
*/
public static String format(Date date, String pattern) {
if (date != null) {
SimpleDateFormat df = null;
if (DATE_TIME_PATTERN.equals(pattern)) {
df = simpleDateFormatThreadLocal.get();
} else {
df = new SimpleDateFormat(pattern);
}
return df.format(date);
}
return null;
}
/**
*
* @Description: 字符串转时间
* @param strDate
* @return
* @throws ParseException
*/
public static Date stringLongToDate(String strDate) throws ParseException {
return stringToDate(strDate, DATE_TIME_PATTERN);
}
public static Date stringShortToDate(String strDate) throws ParseException {
return stringToDate(strDate, DATE_PATTERN);
}
/**
* 字符串转换成日期
* @param strDate 日期字符串
* @param pattern 日期的格式
* @throws ParseException
*/
public static Date stringToDate(String strDate, String pattern) throws ParseException {
if (StringUtils.isBlank(strDate)) {
return null;
}
SimpleDateFormat df = null;
if (DATE_TIME_PATTERN.equals(pattern)) {
df = simpleDateFormatThreadLocal.get();
} else {
df = new SimpleDateFormat(pattern);
}
return df.parse(strDate);
}
/**
* @Description: 日期计算
* @param oldDate
* @param addValue
* @param unit
* @return
*/
public static Date add(Date oldDate, Long addValue, TimeUnit unit) {
long milliseconds = oldDate.getTime();
milliseconds += unit.toMillis(addValue);
return new Date(milliseconds);
}
}
mysql存储json的字段类型转换抽象类:
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import com.alibaba.fastjson.JSON;
/**
* @Title: AbstractObjectTypeHandler
* @Description: mysql存储json的字段类型转换抽象类
*/
// @Slf4j
// @MappedJdbcTypes(JdbcType.VARCHAR)
public abstract class AbstractObjectTypeHandler<T> extends BaseTypeHandler<T> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (null != parameter) {
ps.setString(i, JsonUtil.obj2json(parameter));
}
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
return deserialize(rs.getString(columnName));
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return deserialize(rs.getString(columnIndex));
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return deserialize(cs.getString(columnIndex));
}
/**
* @Description: json反序列化
* @param data
* @return
*/
private T deserialize(String data) {
return StringUtils.isBlank(data) ? null : string2Obj(data);
}
// 重点,解析方法,子类可重写json解析
@SuppressWarnings("unchecked")
protected T string2Obj(String jsonString) {
Class<T> clazz = (Class<T>)getRawType();
return JSON.parseObject(jsonString, clazz);
}
}
解析实体
数据库表test:
字段名 | 类别 | 参考值 |
---|---|---|
id | bigint | 1 |
json_value | varchar | {name:“张三”,age:14} |
… |
正常Mybatis映射实体类:
@Data
public class Test{
private Long id;
private String jsonValue;
}
Json内容实体类:
@Data
public class Person{
private String name;
private int age;
}
Mybatis映射实体类时,解析json字段数据到变量,改造Test实体类:
@Data
public class Test{
private Long id;
@ColumnType(jdbcType = JdbcType.VARCHAR, typeHandler = PersonTypeHandler.class)
private Person jsonValue;
}
添加Json解析转换器:
import com.alibaba.fastjson.JSON;
/**
* @Description: Person类型转换器
*/
public class PersonTypeHandler extends AbstractObjectTypeHandler<Person> {}
Mybatis xml映射
<resultMap type="com.test.model.Test" id="TestMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result typeHandler="com.test.typehandler.PersonTypeHandler" property="jsonValue" column="json_value" jdbcType="VARCHAR"/>
</resultMap>
查询test数据时,使用以上resultMap接收,在映射实体类时自动解析json字段。
解析List
数据库表test:
字段名 | 类别 | 参考值 |
---|---|---|
id | bigint | 1 |
json_list_value | varchar | [{name:“张三”,age:14},{name:“李四”,age:15}] |
… |
正常Mybatis映射实体类:
@Data
public class Test{
private Long id;
private String jsonListValue;
}
Json内容实体类:
@Data
public class Person{
private String name;
private int age;
}
Mybatis映射实体类时,解析json字段数据到变量,改造Test实体类:
@Data
public class Test{
private Long id;
// 映射成List<Person>
@ColumnType(jdbcType = JdbcType.VARCHAR, typeHandler = ListPersonTypeHandler.class)
private List<Person> jsonValue;
}
添加Json解析转换器:
import com.alibaba.fastjson.JSON;
/**
* @Description: List<Person>类型转换器
*/
public class ListPersonTypeHandler extends AbstractObjectTypeHandler<List<Person>> {
@Override
protected List<Person> string2Obj(String jsonString) {
return JSON.parseArray(jsonString, Person.class);
}
}
Mybatis xml映射
<resultMap type="com.test.model.Test" id="TestMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result typeHandler="com.test.typehandler.ListPersonTypeHandler" property="jsonListValue" column="json_list_value" jdbcType="VARCHAR"/>
</resultMap>
查询test数据时,使用以上resultMap接收,在映射实体类时自动解析json集合字段。