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;
}
@Override
public 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> {
@Override
public 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;
}
@Override
public Address getNullableResult(ResultSet rs, String columnName) throws SQLException {
return convertToAddress(rs.getString(columnName));
}
@Override
public Address getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return convertToAddress(rs.getString(columnIndex));
}
@Override
public 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;
@Id
private 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 configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 其他配置 -->
<typeHandlers>
<typeHandler
handler="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;
@Id
private Integer id;
private String name;
@Column
private Address address;
private StateEnum state;
//省略 setter 和 getter
}
这里的 Address
加上 @Column
注解,只是为了把该字段当成表中的字段。
typeHandler 全局配置如下:
<typeHandlers>
<typeHandler
handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
javaType="tk.mybatis.mapper.typehandler.StateEnum"/>
<typeHandler handler="tk.mybatis.mapper.typehandler.AddressTypeHandler"/>
</typeHandlers>
做好这些配置后,就可以在增删改查使用了。
这个例子对应的测试: tk.mybatis.mapper.typehandler.TypeHandlerTest2
。