Mybatis自定义typehandler

Mybatis自定义typehandler

  1. 自定义typehandler
    官方的建议是继承BaseTypeHandler,其中Typehandler可以受一个type参数,Mybatis会自动传进来实际的class类型。

    /**
     * 用来处理我们自定义的枚举 
     * @author sut
     * @version $Revision:$
     */
    public class GenericEnumUserType<E extends StringEnumTypeImp> extends BaseTypeHandler<E>{
    
        //mybatis will pass actual class when constructing TypeHandler
        private Class<E> type;
    
        private static final String fromStringCode = "fromStringCode";
    
        public GenericEnumUserType(Class<E> type){
            Preconditions.checkNotNull(type, "Type argument cannot be null");
            this.type = type;
        }
    
        /**
         * 设置非空参数
         * @see org.apache.ibatis.type.BaseTypeHandler#setNonNullParameter(java.sql.PreparedStatement, int, java.lang.Object, org.apache.ibatis.type.JdbcType)
         */
        @Override
        public void setNonNullParameter(PreparedStatement ps, int i, StringEnumTypeImp parameter, JdbcType jdbcType) throws SQLException {
            ps.setString(i, parameter.getStoreValue());
        }
    
        /**
         * 得到非空结果,然后转换成E<br>
         * 利用反射调用静态的方法<br>
         * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.ResultSet, java.lang.String)
         */
        @Override
        @SuppressWarnings("unchecked")
        public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
            String storeValue =  rs.getString(columnName);
            Preconditions.checkNotNull(type, "Type argument cannot be null");
            try {
                Method fromMethod = type.getMethod(fromStringCode, String.class);
                return (E) fromMethod.invoke(null, storeValue);
            } catch (IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 空的结果返回类型
         * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.ResultSet, int)
         */
        @Override
        public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
            try {
                return type.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 针对callback的空值结果
         * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.CallableStatement, int)
         */
        @Override
        public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
            try {
                return type.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
    
    }
  2. 注册TypeHandler

    <!-- 类型处理器 -->
    <typeHandlers>
    <!-- 是否枚举 -->
    <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType"
    javaType="com.sut.util.meta.WhetherTypeEnum" jdbcType="VARCHAR"/>
    <!-- 性别枚举 -->
    <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType"
    javaType="com.sut.util.meta.SexTypeEnum" jdbcType="VARCHAR" />
    </typeHandlers>
  3. 这样我们在mapper就可以使用了。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.sut.persist.dao.UserDao">
    
        <!-- 定义User实体 -->
        <resultMap type="com.sut.persist.entity.User" id="userResult">
            <id property="id" javaType="int" column="id" />
            <result property="username" javaType="String" column="USERNAME" />
            <result property="password" javaType="String" column="PASSWORD" />
            <result property="enable" javaType="com.sut.util.meta.WhetherTypeEnum" column="enabled" 
                typeHandler="com.sut.util.enumerate.mybatis.GenericEnumUserType" />
            <result property="createTime" javaType="java.util.Date" column="CREATE_TIME" />
            <result property="lastLoginTime" javaType="java.util.Date" column="LAST_LOGIN_DATE" />
            <result property="sex" javaType="com.sut.util.meta.SexTypeEnum" column="SEX" 
                typeHandler="com.sut.util.enumerate.mybatis.GenericEnumUserType" />
            <result property="email" javaType="String" column="EMAIL" />
            <result property="mobile" javaType="String" column="MOBILE" />
            <result property="province" javaType="String" column="PROVINCE" />
            <result property="city" javaType="String" column="CITY" />
            <result property="area" javaType="String" column="AREA" />
            <result property="address" javaType="String" column="ADDRESS" />
            <result property="remark" javaType="String" column="REMARK" />
        </resultMap>
    
        <!-- query user by id -->
        <select id="getById" parameterType="int"  resultMap="userResult">
            select 
             *
            from user where id = #{id}
        </select>
    
        <!-- query user by name -->
        <select id="getByName" parameterType="String" resultMap="userResult">
            select * from user where username = #{username}
        </select>
    
        <!-- query all user.这里将所有列写出来了,因为最初会报错。字段好像映射的顺序不一样 --> 
        <select id="getAll" resultMap="userResult">
            select 
                id as id,
                username as username,
                password as password,
                enabled as enable,
                create_time as createTime,
                last_login_date as lastLoginTime,
                email as email,
                mobile as mobile,
                province as province,
                city as city,
                area as area,
                address as address,
                remark as remark
            from user
        </select>
    
        <!-- delete by id -->
        <delete id="deleteById" parameterType="int">
            delete from user where id = #{id}
        </delete>
    
        <!-- insert User -->
        <insert id="insert">
            insert into user(
                username,
                password,
                enabled,
                create_time,
                last_login_date,
                sex,
                email,
                mobile,
                province,
                city,
                area,
                address,
                remark
            )values(
                #{username},
                #{password},
                #{enable, typeHandler=com.sut.util.enumerate.mybatis.GenericEnumUserType, jdbcType=VARCHAR,
                     javaType=com.sut.util.meta.WhetherTypeEnum},
                #{createTime},
                #{lastLoginDate},
                #{sex, typeHandler=com.sut.util.enumerate.mybatis.GenericEnumUserType, jdbcType=VARCHAR, 
                     javaType=com.sut.util.meta.SexTypeEnum},
                #{email},
                #{mobile},
                #{province},
                #{city},
                #{area},
                #{address},
                #{remark}
            )
        </insert>
    </mapper>
  4. 测试insert和getAll()方法是可以的。

UPDATE:

  1. 2017/01/07 有一个问题:
    当使用自定义typeHandler的时候,如果bean的属性名和表字段的名称是一样的话,就会被mybatis分为mappedColumns,获取的typeHandler的rawType就不正确,如果是不一样的话,就会成为unMappedColumns, 获取的就是对的. 在测试过程中,即便设置AutoMappingBehavior=NONE,也还是会执行column分类. 最后解决办法只能是改变bean的property名称。

  2. 2017/01/23 来自SO的回答说:
    说是将ResultMapping定义的时候,将education的TypeHandler移除掉,然后指定好javaType,jdbcType就可以了。试了一下,果然可以。但是不明白为什么这样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值