默认的
EnumTypeHandler
映射枚举的名称(例如 "CREATED"
、"RUNNING"
),因此列类型必须是 VARCHAR
[1] 等文本类型之一。
由于 MyBatis 对
id
属性一无所知,因此您必须编写自定义类型处理程序。import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
@MappedTypes(Status.class)
public class StatusTypeHandler implements TypeHandler<Status> {
@Override
public void setParameter(PreparedStatement ps,
int i, Status parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
ps.setNull(i, Types.INTEGER);
} else {
ps.setInt(i, parameter.getId());
}
}
@Override
public Status getResult(ResultSet rs, String columnName) throws SQLException {
return getStatus(rs.getInt(columnName));
}
@Override
public Status getResult(ResultSet rs, int columnIndex) throws SQLException {
return getStatus(rs.getInt(columnIndex));
}
@Override
public Status getResult(CallableStatement cs, int columnIndex) throws SQLException {
return getStatus(cs.getInt(columnIndex));
}
private static Status getStatus(int id) {
if (id == 0) {
return null;
}
for (Status status : Status.values()) {
if (id == status.getId()) {
return status;
}
}
throw new IllegalArgumentException("Cannot convert " + id + " to Status");
}
}
您应该全局注册此类型处理程序。
那么大多数情况下就不需要显式指定
typeHandler
。
如果您使用mybatis-spring-boot,在配置中指定
mybatis.type-handlers-package
可能是全局注册类型处理程序的最简单方法。
如果您使用 XML 配置,请添加以下内容。
<typeHandlers>
<typeHandler
handler="xxx.yyy.StatusTypeHandler" />
</typeHandlers>
如果
Status
是您项目中唯一的枚举,您可以停止阅读。
但是,如果有许多具有
id
属性的枚举,并且您不想为每个枚举编写类似的自定义类型处理程序,该怎么办?
如果您的枚举实现如下所示的通用接口,您可以编写一个可以映射所有枚举的类型处理程序。
public interface HasId {
Integer getId();
}
这是一个类型处理程序实现示例。 请注意,它有一个以
java.lang.Class
作为参数的构造函数。
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
@MappedTypes(HasId.class)
public class HasIdTypeHandler<E extends Enum<E> & HasId> implements TypeHandler<E> {
private Class<E> type;
private final E[] enums;
public HasIdTypeHandler(Class<E> type) {
if (type == null)
throw new IllegalArgumentException("Type argument cannot be null");
this.type = type;
this.enums = type.getEnumConstants();
if (!type.isInterface() && this.enums == null)
throw new IllegalArgumentException(type.getSimpleName()
+ " does not represent an enum type.");
}
@Override
public void setParameter(PreparedStatement ps,
int i, E parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
ps.setNull(i, Types.INTEGER);
} else {
ps.setInt(i, parameter.getId());
}
}
@Override
public E getResult(ResultSet rs, String columnName) throws SQLException {
return getEnum(rs.getInt(columnName));
}
@Override
public E getResult(ResultSet rs, int columnIndex) throws SQLException {
return getEnum(rs.getInt(columnIndex));
}
@Override
public E getResult(CallableStatement cs, int columnIndex) throws SQLException {
return getEnum(cs.getInt(columnIndex));
}
private E getEnum(int id) {
if (id == 0) {
return null;
}
for (E e : enums) {
if (id == e.getId()) {
return e;
}
}
throw new IllegalArgumentException("Cannot convert " +
id + " to " + type.getSimpleName());
}
}
请注意,如果您尝试在映射器中指定此类型处理程序,它可能无法正常工作。有一个已知的问题。
[1] 仅供参考,还有另一个用于枚举的内置类型处理程序:
EnumOrdinalTypeHandler
映射枚举的 ordinal。
这是另一种没有
TypeHandler
的方法。
只需在结果类型类中添加一个setter,其中输入参数应与数据库中的列类型相同。
例如
@Data
public class YourDTO {
private YourEnum yourEnum;
public void setYourEnum(Integer enumCode) {
this.yourEnum= YourEnum.fromCode(enumCode);//Call your static method defined in YourEnum
}
仅此而已。对于mapper.xml 无需再做任何事情。
<resultMap id="yourDTO" type="YourDTO">
<result property="yourEnum" column="enumCode"/>