一、typeHandler 的使用
1、存储json格式字段
如果字段需要存储为json格式,可以使用JacksonTypeHandler处理器。使用方式非常简单,如下所示:
只需要加上两个注解即可:
@TableName(autoResultMap = true)
表示自动映射resultMap
@TableField(typeHandler = JacksonTypeHandler.class)
表示将UserInfo对象转为json对象入库
2、自定义 typeHandler 实现类
例如当我们 某个字段存储的类型为List或者Map时,我们可以自定义一个TypeHandler,以 list 为例,我们想存储一个字段类型为 list ,在数据库中的存储的格式是 多条数据以逗号分割,当查询时会自动根据逗号分割成列表格式。
需要实现BaseTypeHandler
抽象类:
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes({List.class})
public class ListTypeHandler extends BaseTypeHandler<List<String>> {private static final String DELIM = ",";@Overridepublic void setNonNullParameter(PreparedStatement preparedStatement, int i, List<String> strings, JdbcType jdbcType) throws SQLException {String value = StringUtils.collectionToDelimitedString(strings, DELIM);preparedStatement.setString(i, value);}@Overridepublic List<String> getNullableResult(ResultSet resultSet, String s) throws SQLException {String value = resultSet.getString(s);return Arrays.asList(StringUtils.tokenizeToStringArray(value, DELIM));}@Overridepublic List<String> getNullableResult(ResultSet resultSet, int i) throws SQLException {String value = resultSet.getString(i);return Arrays.asList(StringUtils.tokenizeToStringArray(value, DELIM));}@Overridepublic List<String> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {String value = callableStatement.getString(i);return Arrays.asList(StringUtils.tokenizeToStringArray(value, DELIM));}
}
- @MappedJdbcTypes:表示
SQL
语句中查出来的类型; - @MappedTypes:表示要转成 Java 对象的类型;
- DELIM:表示字符串的分隔符,如果你是用空格分开的就赋值为空格。
-
setNonNullParameter(插入时设置参数类型)
-
getNullableResult(获取时转换回的自定义类型)
根据列名获取
resultSet:结果集
columnName:列名
public UserInfo getNullableResult(ResultSet resultSet, String columnName)
根据索引位置获取
resultSet:结果集
columnIndex:列索引
public UserInfo getNullableResult(ResultSet resultSet, int columnIndex)
根据存储过程获取
callableStatement:结果集
columnIndex:列索引
public UserInfo getNullableResult(CallableStatement callableStatement, int columnIndex)
然后再字段上指定该实现了即可:
@TableField(typeHandler = ListTypeHandler.class)private List<String> job;
最后在数据库中存储格式为:
3、存储自定义对象字段
例如我们刚才使用json格式存储 Unit 字段,如果不加 @TableField(typeHandler = JacksonTypeHandler.class)
就会报错,因为 typeHandler 可以指定我们在Java实体类所包含的自定义类型存入数据库后的类型是什么,也可以从数据库中取出该数据后自动转换为我们自定义的Java类型。
我们虽然在 Java中定义了 Unit 类型,但是数据库不认识,我们现在就需要将 Unit 转换为数据库认识的类型。Java自带的类型在存取的时候不会出错,我们自定义的类型就会出错 是因为 mybatis已经将这些类型的TypeHandler提前写好了:
所以如果我们要存储 Unit 类型的字段,又不想用 默认的json 格式,我们也需要自定义一个 关于Unit 的 TypeHandler,如下:
public class JsonUtils {private static ObjectMapper objectMapper = new ObjectMapper();//初始化相关的配置static {//只引用不为空的值objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);//取消默认转换timestempobjectMapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);//忽略空bean转换错误objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);//忽略在json中存在,在java对象不存在的错误objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 解决jackson2无法反序列化LocalDateTime的问题objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);objectMapper.registerModule(new JavaTimeModule());}/*** 将java对象转换成json字符串** @param obj* java 对象* @param <T>* @return*/public static <T> String objectToString(T obj) {if (obj == null) {return null;}try {return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);} catch (JsonProcessingException e) {e.printStackTrace();return null;}}/*** 将json字符串转换成java对象** @param json* 字符串* @param tClass* 要转换的对象* @param <T>* @return*/public static <T> T getObjetFormString(String json, Class<T> tClass) {if (StringUtils.isBlank(json) || tClass == null) {return null;}try {return tClass.equals(String.class) ? (T) json : objectMapper.readValue(json, tClass);} catch (IOException e) {e.printStackTrace();return null;}}/*** 将字符串转换成java对象* @param json* 字符串* @param tTypeReference* 对象** @param <T>* @return*/public static <T> T fromString(String json, TypeReference<T> tTypeReference){if (StringUtils.isBlank(json) || tTypeReference == null) {return null;}try {return tTypeReference.getType().equals(String.class) ? (T) json : objectMapper.readValue(json, tTypeReference);} catch (IOException e) {e.printStackTrace();return null;}}/*** 将json字符串转换成java集合对象* @param json* 字符串* @param collectionClass* 集合类型* @param elementClazzes* 成员类型* @param <T>* @return*/public static <T> T fromString(String json, Class<?> collectionClass, Class<?> ... elementClazzes){JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClazzes);try {return objectMapper.readValue(json, javaType);} catch (IOException e) {e.printStackTrace();return null;}}
}
@MappedTypes(UserInfo.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class UserInfoTypeHandler extends BaseTypeHandler<UserInfo> {@Overridepublic void setNonNullParameter(PreparedStatement preparedStatement, int i, UserInfo userInfo, JdbcType jdbcType) throws SQLException {preparedStatement.setString(i, JsonUtils.objectToString(userInfo));}@Overridepublic UserInfo getNullableResult(ResultSet resultSet, String columnName) throws SQLException {return JsonUtils.fromString(resultSet.getString(columnName),UserInfo.class);}@Overridepublic UserInfo getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {return JsonUtils.fromString(resultSet.getString(columnIndex),UserInfo.class);}@Overridepublic UserInfo getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {return JsonUtils.fromString(callableStatement.getString(columnIndex),UserInfo.class);}
}
其实还是将该对象转成了 json ,但是只不过转成 json 的工具类可以 由我们自己指定。
二、mybatisplus 存储枚举类型
存储枚举类型有两种形式,第一种就是自定义 typeHandler 跟上面一样,
还有一种是使用mybatis提供的默认的处理类,如下所所示:
数据库表结构:
mybatisPlus对枚举处理器进行了补充:
创建枚举类:
@Getter
public enum OrderState {NORMAL(0, "正常"),CANCEL(1, "取消"),DELETE(2, "删除");// 状态码@EnumValue // 用于数据库存储private Integer code;// 描述@JsonValue // 用于序列化返回的json数据private String desc;OrderState(Integer code, String desc) {this.code = code;this.desc = desc;}}
TOrder实体类:
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_order")
public class TOrder implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "order_id", type = IdType.AUTO)private Integer orderId;@TableField("user_id")private Integer userId;@TableField("price")private BigDecimal price;@TableField("status")private OrderState status;}
在配置文件中配置统一的枚举处理器,实现类型转换:
调用:
三、使用CommandLineRunner 修改 JacksonTypeHandler 实现类
@Component
public class JsonTypeHandlerConfig implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {JacksonTypeHandler.setObjectMapper(JsonUtils.getMapper());}
}