通用mapper枚举字段和typehandler

本文介绍如何在MyBatis中使用枚举处理器和自定义TypeHandler,包括EnumOrdinalTypeHandler、EnumTypeHandler及AddressTypeHandler的具体实现,展示了如何处理枚举和复杂类型的数据转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

枚举类:

public enum StateEnum {
    disabled,
    enabled,
}

MyBatis 提供的枚举处理器有 EnumOrdinalTypeHandler(数据库存的是枚举索引值,查询的时候根据索引值获取相对于的值)和EnumTypeHandler(数据库存的是枚举的值)

这里打算用 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 {
        		//1.对address对象进行验证
		if(address == null) {
			return ;
		}
		
		//2.从address对象中取出具体数据
		String province = address.getProvince();
		String city = address.getCity();
		String street = address.getStreet();
		
		//3.拼装成一个字符串
		//规则:各个值之间使用“,”分开
		StringBuilder builder = new StringBuilder();
		builder
			.append(province)
			.append(",")
			.append(city)
			.append(",")
			.append(street);
		
		String parameterValue = builder.toString();
		
		//4.设置参数
		ps.setString(i, parameterValue);
    }

    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);

使用 ColumnType 注解指定:

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);
    }
}

//具体的设置值和获取值可以参考EnumOrdinalTypeHandler和EnumTypeHandler

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, State parameter, JdbcType jdbcType) throws SQLException {
       ps.setInt(i,parameter.getId());
    }

    @Override
    public State getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int i = rs.getInt(columnName);
        return getState(i);
    }
    priv State getState(int id){
        State[] enumConstants = State.class.getEnumConstants();
        for(int i=0;i<enumConstants.length;i++){
            if(enumConstants[i].id==id){
                return enumConstants[i];
            }
        }
        return null;
    }

然后配置:

@ColumnType(typeHandler = StateEnumTypeHandler.class) 
private StateEnum state;

springboot配置:

mybatis.configuration.default-enum-type-handler=org.apache.ibatis.type.EnumTypeHandler

除了用这种麻烦的方式外,还可以直接用下面的方式配置全局的 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>

 

全局配置

第二种就是全部在配置文件中使用 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>
public class EnumOrdinalTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
    private final Class<E> type;
    private final E[] enums;

    public EnumOrdinalTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        } else {
            this.type = type;
            this.enums = (Enum[])type.getEnumConstants();
            if (this.enums == null) {
                throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
            }
        }
    }

    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, parameter.ordinal());
    }

    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int i = rs.getInt(columnName);
        if (rs.wasNull()) {
            return null;
        } else {
            try {
                return this.enums[i];
            } catch (Exception var5) {
                throw new IllegalArgumentException("Cannot convert " + i + " to " + this.type.getSimpleName() + " by ordinal value.", var5);
            }
        }
    }

    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        int i = rs.getInt(columnIndex);
        if (rs.wasNull()) {
            return null;
        } else {
            try {
                return this.enums[i];
            } catch (Exception var5) {
                throw new IllegalArgumentException("Cannot convert " + i + " to " + this.type.getSimpleName() + " by ordinal value.", var5);
            }
        }
    }

    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int i = cs.getInt(columnIndex);
        if (cs.wasNull()) {
            return null;
        } else {
            try {
                return this.enums[i];
            } catch (Exception var5) {
                throw new IllegalArgumentException("Cannot convert " + i + " to " + this.type.getSimpleName() + " by ordinal value.", var5);
            }
        }
    }
}



public class EnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
    private final Class<E> type;

    public EnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        } else {
            this.type = type;
        }
    }

    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        if (jdbcType == null) {
            ps.setString(i, parameter.name());
        } else {
            ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE);
        }

    }

    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String s = rs.getString(columnName);
        return s == null ? null : Enum.valueOf(this.type, s);
    }

    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String s = rs.getString(columnIndex);
        return s == null ? null : Enum.valueOf(this.type, s);
    }

    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String s = cs.getString(columnIndex);
        return s == null ? null : Enum.valueOf(this.type, s);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值