9.3 自定义类型处理器TypeHandler
以上问题的解决方式有两种。第一种是新建一张address表,建立user表到address表的关联关系,在MyBatis Mapper XML中使用resultMap和collection标签重新定义映射关系
第二种方式是不创建新的表,就将Address属性的内容全部存到表的address字段中,这就需要使用到自定义的类型处理器
自定义类型处理器要注意字段存储的内容为字符串,所以自定义的类型处理器的主要功能是建立一个规则,将address属性转化为字符串存储在数据库中,并按照一定的格式存储,这个规则还包括查询时,将字符串转化为实体类类型。
查看类型转换的顶级接口TypeHandler以及BaseTypeHandler
- setNonNullParameter:将要做类型处理的parameter对象转换为字符串存在ps对象的i位置
- getNullableResult:从结果集中获取查询结果转换为原始对象
可以通过继承BaseTypeHandler实现自定义的类型处理器
9.3.1 实现自定义类型处理器AddressTypeHandler
新建一个类AddressTypeHandler继承BaseTypeHandler
public class AddressTypeHandler extends BaseTypeHandler<Address> { @Override public void setNonNullParameter(PreparedStatement ps, int i, Address parameter, JdbcType jdbcType) throws SQLException { // 1.对传进来的address对象进行校验 if (parameter == null){ return; } // 2.从address对象中取出数据 String province = parameter.getProvince(); String city = parameter.getCity(); String street = parameter.getStreet(); // 3.拼接成一个字符串,用","隔开 StringBuilder builder = new StringBuilder(); builder.append(province).append(",").append(city).append(",").append(street); // 4.设置参数 String parameterValue = builder.toString(); ps.setString(i,parameterValue); } @Override public Address getNullableResult(ResultSet rs, String columnName) throws SQLException { // 根据字段名从rs对象中获取字段值 String columnValue = rs.getString(columnName); // 校验 columnValue是否有效 if (columnValue == null || columnValue.length() == 0|| !columnValue.contains(",")){ return null; } // 拆分columnValue String[] split = columnValue.split(","); // 从拆分结果中给对象赋值 Address address = new Address(); address.setProvince(split[0]); address.setCity(split[1]); address.setStreet(split[2]); return address; } @Override public Address getNullableResult(ResultSet rs, int columnIndex) throws SQLException { // 根据字段索引从rs对象中获取字段值 String columnValue = rs.getString(columnIndex); // 校验 columnValue是否有效 if (columnValue == null || columnValue.length() == 0|| !columnValue.contains(",")){ return null; } // 拆分columnValue String[] split = columnValue.split(","); // 从拆分结果中给对象赋值 Address address = new Address(); address.setProvince(split[0]); address.setCity(split[1]); address.setStreet(split[2]); return address; } @Override public Address getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { // 根据字段索引从cs对象中获取字段值 String columnValue = cs.getString(columnIndex); // 校验 columnValue是否有效 if (columnValue == null || columnValue.length() == 0|| !columnValue.contains(",")){ return null; } // 拆分columnValue String[] split = columnValue.split(","); // 从拆分结果中给对象赋值 Address address = new Address(); address.setProvince(split[0]); address.setCity(split[1]); address.setStreet(split[2]); return address; } } 复制代码
注册AddressTypeHandler的方式有两种
- 字段/属性级别注册:在要使用自定义类型转换器的属性上使用@ColumnType注解
- 全局注册:在MyBatis全局配置文件中使用typeHandlers标签注册,并在要转换的属性上增加@Colum注解。
首先使用@ColumnsType注解注册
@ColumnType(typeHandler = AddressTypeHandler.class) private Address address; 复制代码
执行查询测试
输出的Address对象不再是空对象
执行插入测试
查看插入的数据
插入的address字段也不再是空。说明自定义的类型处理器生效
然后使用MyBatis全局配置文件注册AddressTypeHandler 给address属性增加@Column注解,让通用Mapper处理普通字段一样处理address 在全局配置文件中增加配置,settings标签下
<typeHandlers> <typeHandler handler="com.citi.handler.AddressTypeHandler" javaType="com.citi.entity.Address" /> </typeHandlers> 复制代码
再次执行查询测试
Address对象不为空
9.4 枚举类型的处理
9.4.1 将枚举类型当作简单类型来处理
配置enumAsSimpleType=true会把枚举类型当作简单类型处理,默认simpleType会忽略枚举类型,默认不处理,所以出现了一开始枚举内容为空的情况
在MyBatis全局配置文件中配置枚举类型处理的配置
<bean id="mapperScannerConfigurer" class="tk.mybatis.spring.mapper.MapperScannerConfigurer"> <!--其他被容不变--> <property name="properties"> <value> enumAsSimpleType=true </value> </property> </bean> 复制代码
执行查询测试
成功输出枚举类型的内容
执行插入测试
根据输出的SQL语句,插入时枚举内容不为空,可以查看数据库中插入的数据
枚举类型的内容也被成功插入到数据库中,说明配置生效。
9.4.2 为枚举类型配置对应的类型处理器
MyBatis内置了两种枚举类型的处理器
- org.apache.ibatis.type.EnumTypeHandler
- org.apache.ibatis.type.EnumOrdinalTypeHandler
使用EnumTypeHandler类型处理器
使用@ColumnType注解方式注册EnumTypeHandler处理器
编译阶段就已经报错,不能使用@Column注解注册EnumTypeHandler处理器
MyBatis全局配置文件中注册类型处理器,并在season属性上增加@Column注解
<typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumTypeHandler" javaType="com.citi.entity.SeasonEnum" /> </typeHandlers> 复制代码
增加@Column注解的作用是让通用Mapper不忽略枚举类型
执行查询测试
成功输出枚举类型的内容
执行插入测试
根据INSERT语句内容来看,插入的内容不为空,可以查看数据库插入的内容
成功将枚举内容插入到数据库中
使用EnumOrdinalTypeHandler类型处理器
枚举处理器中带Ordinal与不带Ordinal的区别:
- 带Ordinal存的是索引值
- 不带Ordinal存的是具体内容
在MyBatis全局配置文件中注册EnumOrdinalTypeHandler类型处理器
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.citi.entity.SeasonEnum" /> 复制代码
执行插入测试
查看数据库
查询刚刚插入的数据
针对索引对应的内容非常大的时候比较适用
十、通用Mapper的配置项
通用Mapper的配置项配置位置在name=propertiesy的property标签下
<bean id="mapperScannerConfigurer" class="tk.mybatis.spring.mapper.MapperScannerConfigurer"> <!--指定接口所在的包--> <property name="basePackage" value="com.citi.mapper"></property> <property name="properties"> <value> enumAsSimpleType=true </value> </property> </bean> 复制代码
有多个配置项可以设置多个value标签。
通用 Mapper 提供了十几个配置参数,具体请参考通用Mapper配置
至此,通用Mapper部分完结✿✿ヽ(°▽°)ノ✿!