7.2 TypeHandler 类型处理器
本文通过两个例子来演示 typeHandler 的用法。
示例来自 base/src/test/java/tk.mybatis.mapper.typehandler 包中的测试。
在开始例子前,先上相同的代码。
一个简单的枚举类:
public enum StateEnum {disabled,enabled,}
这里打算用 MyBatis 提供的 EnumOrdinalTypeHandler,也是数据库存储枚举对应的序号。
一个简单的地址类:
public class Address implements Serializable {private static final long serialVersionUID = 1L;private String province;private String city;public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();if(province != null && province.length() > 0){builder.append(province);}if(city != null && city.length() > 0){builder.append("/").append(city);}return builder.toString();}}
这个类用来演示自定义类型的用法,针对该类写一个自定义的 TypeHandler,如下:
public class AddressTypeHandler extends BaseTypeHandler<Address> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Address parameter,JdbcType jdbcType) throws SQLException {ps.setString(i, parameter.toString());}private Address convertToAddress(String addressStr){if(addressStr == null || addressStr.length() == 0){return null;}String[] strings = addressStr.split("/");Address address = new Address();if(strings.length > 0 && strings[0].length() > 0){address.setProvince(strings[0]);}if(strings.length > 1 && strings[1].length() > 0){address.setCity(strings[1]);}return address;}@Overridepublic Address getNullableResult(ResultSet rs, String columnName) throws SQLException {return convertToAddress(rs.getString(columnName));}@Overridepublic Address getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return convertToAddress(rs.getString(columnIndex));}@Overridepublic Address getNullableResult(CallableStatement cs, int columnIndex)throws SQLException {return convertToAddress(cs.getString(columnIndex));}}
测试数据如下:
create table user (id integer NOT NULL PRIMARY KEY,name varchar(32),address varchar(64),state integer);INSERT INTO user (id, name, address, state) VALUES (1, 'abel533', 'Hebei/Shijiazhuang', 1);INSERT INTO user (id, name, address, state) VALUES (2, 'isea533', 'Hebei/Handan', 0);
特别注意,state 对应的 0 就是枚举第一个 disabled,1 就是枚举第二个 enabled。
7.2.1 使用 ColumnType 注解指定
创建 user 表对应的 User 实体:
public class User implements Serializable {private static final long serialVersionUID = 1L;@Idprivate Integer id;private String name;@ColumnType(typeHandler = AddressTypeHandler.class)private Address address;private StateEnum state;//省略 setter 和 getter}
特别提醒
- 默认情况下只有简单类型才会被当作表中的字段(
useSimpleType=true)。- 当字段有
@Column或者@ColumnType注解时,也会被当作表中的字段。- 默认情况下,枚举不会当作表中的字段,如果想要自动把枚举作为表中字段,需要配置
enumAsSimpleType=true,这里的例子就启用了这个配置。如果不启用这个功能,也需要加@Column或者@ColumnType注解。
在这个例子中,address 字段通过 @ColumnType 设置了 typeHandler。但是 state 却没这么设置,先看 EnumOrdinalTypeHandler 的定义:
public class EnumOrdinalTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E>
由于需要指定泛型,因此这里不能直接配置,除非你在创建一个针对性的 TypeHandler,例如:
public class StateEnumTypeHandler extends EnumOrdinalTypeHandler<StateEnum> {public StateEnumTypeHandler(Class<StateEnum> type) {super(type);}}
然后配置:
@ColumnType(typeHandler = StateEnumTypeHandler.class)private StateEnum state;
除了用这种麻烦的方式外,还可以直接用下面的方式配置全局的 typeHandler:
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 其他配置 --><typeHandlers><typeHandlerhandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"javaType="tk.mybatis.mapper.typehandler.StateEnum"/></typeHandlers><!-- 其他配置 --></configuration>
有了这些配置后,就可以在增删改查使用了。
这个例子对应的测试: tk.mybatis.mapper.typehandler.TypeHandlerTest。
7.2.2 全局配置
第二种就是全部在配置文件中使用 typeHandler 进行配置,实体只做简单的配置:
@Table(name = "user")public class User2 implements Serializable {private static final long serialVersionUID = 1L;@Idprivate Integer id;private String name;@Columnprivate Address address;private StateEnum state;//省略 setter 和 getter}
这里的 Address 加上 @Column 注解,只是为了把该字段当成表中的字段。
typeHandler 全局配置如下:
<typeHandlers><typeHandlerhandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"javaType="tk.mybatis.mapper.typehandler.StateEnum"/><typeHandler handler="tk.mybatis.mapper.typehandler.AddressTypeHandler"/></typeHandlers>
做好这些配置后,就可以在增删改查使用了。
这个例子对应的测试: tk.mybatis.mapper.typehandler.TypeHandlerTest2。
