• MyBatis(十一)扩展:自定义类型处理器


    一、TypeHandler

      TypeHandler 在MyBatis中进行数据库类型和JavaBean类型的映射。

      TypeHandler<T> 接口:

         该接口中声明了四个抽象方法,说明如下:

    //将parameter对象转换为字符串存入到 ps 对象的i位置
    public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
    
    //从结果集中获取数据库对应查询结果
    //将字符串还原为原始的T类型对象
    public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
    
    
    public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
    
    
    public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
    

      

      BaseHandler<T> 类:

         BaseTypeHandler 抽象类实现了上面的四个抽象方法,做了简单的包装,然后又留出四个抽象方法。

      TypeHandle 的子类:

        

      所有的类型处理器都直接或间接继承了 TypeHandler类。

    二、MyBatis 处理枚举类型

      如果我们在 Employee 中又新增一个枚举类型的属性来表示员工的状态,那么在 MyBatis 里面会如何保存的呢?

      员工状态枚举类 EmpStatus:

    public enum EmpStatus {
        LOGIN(100, "用户登录"),
        LOGOUT(200, "用户退出"),
        REMOVE(300, "用户不存在");
    
        private Integer code;
        private String msg;
    
        private EmpStatus(Integer code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        //根据状态码返回枚举对象
        public static EmpStatus getEmpStatusByCode(Integer code) {
            switch (code) {
                case 100:
                    return LOGIN;
                case 200:
                    return LOGOUT;
                case 300:
                    return REMOVE;
                default:
                return LOGOUT;
            }
        }
    }

      Employee 类:

    public class Employee {
        private Integer id;
        private String lastName;
        private String gender;
        private String email;
        private EmpStatus empStatus = EmpStatus.LOGOUT;
    }

      接口中添加方法:

    public Long addEmp(Employee employee);

      SQL映射文件配置:

        <!--
            public Long addEmp(Employee employee);
        -->
        <insert id="addEmp" parameterType="com.njf.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id">
            insert into tbl_employee(`last_name`, `email`, `gender`, `empStatus`)
            values(#{lastName}, #{email}, #{gender}, #{empStatus})
        </insert>

      测试:

        @Test
         public void testEnum() throws IOException {
              //1、获取 sqlSessionFactory
              SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
    
              //2、获取 sqlSession 实例,获取批量执行器
              SqlSession sqlSession = sqlSessionFactory.openSession();
              try {
                   //3、获取接口的实现类对象
                   EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
    
                   Employee emp = new Employee(null, "test_enum", "1", "enum@126.com", EmpStatus.LOGIN);
                   employeeMapper.addEmp(emp);
    
                   sqlSession.commit();
    
    
              } finally {
                   sqlSession.close();
              }
         }

      运行结果:

       可以看到默认情况下MyBatis处理枚举类型使用的是 EnumTypeHandler。

       如果要使用 EnumOrdinalTypeHandler 类型呢?

       可以看到如果配置的 EnumOridnalTypeHandler 类型处理器,保存的就会是枚举的索引值?

      如何配置呢?

      在 MyBatis 的核心配置文件中配置如下内容:

        <typeHandlers>
            <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.njf.mybatis.bean.EmpStatus" />
        </typeHandlers>

      测试效果:

       这是在数据库保存的就是枚举的索引值了。

      小结:

      默认myBatis在处理枚举的时候保存的是枚举的名字:EnumTypeHandler。

      改变使用:EnumOrdinalTypeHandler,在核心配置文件中进行设置

    <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.njf.mybatis.bean.EmpStatus" />
    

      

    三、自定义 TypeHandler 处理枚举

      如果我们想要自己自定义保存的数据呢?

      我们可以通过自定义TypeHandler的形式来在设置参数或者取出结果集的时候自定义参数封装策略。

      步骤:

      (1)实现TypeHandler接口或者继承BaseTypeHandler;

      (2)使用@MappedTypes定义处理的java类型,使用@MappedJdbcTypes定义jdbcType类型;

      (3)在自定义结果集标签或者参数处理的时候声明使用自定义TypeHandler进行处理或者在全局配置TypeHandler要处理的javaType

      自定义枚举类型的 TypeHandler:

    /**
     *
     * 1、实现 TypeHandler<T> 接口或者继承 BaseTypeHandler<T>
     */
    public class MyEnumEmpStatusTypeHandler implements TypeHandler<EmpStatus> {
    
        /**
         *  定义当前数据如何保存到数据库中
         * @param ps
         * @param i
         * @param parameter
         * @param jdbcType
         * @throws SQLException
         */
        @Override
        public void setParameter(PreparedStatement ps, int i, EmpStatus parameter, JdbcType jdbcType) throws SQLException {
            System.out.println("要保存的状态码:" + parameter.getCode());
            ps.setString(i, parameter.getCode().toString());
        }
    
        @Override
        public EmpStatus getResult(ResultSet rs, String columnName) throws SQLException {
            int code = rs.getInt(columnName);
            //需要根据从数据库中拿到的枚举状态码返回一个枚举对象
            EmpStatus empStatus = EmpStatus.getEmpStatusByCode(code);
            return empStatus;
        }
    
        @Override
        public EmpStatus getResult(ResultSet rs, int columnIndex) throws SQLException {
            int code = rs.getInt(columnIndex);
            EmpStatus empStatus = EmpStatus.getEmpStatusByCode(code);
            return empStatus;
        }
    
        @Override
        public EmpStatus getResult(CallableStatement cs, int columnIndex) throws SQLException {
            int code = cs.getInt(columnIndex);
            EmpStatus empStatus = EmpStatus.getEmpStatusByCode(code);
            return empStatus;
        }
    }

      在 MyBatis 的核心配置文件中进行配置:

        <typeHandlers>
            <!--
                1、配置自定义的TypeHandler
                2、也可以在处理某个字段的时候告诉 MyBatis 用什么类型的处理器
                    保存:#{empStatus, typeHandler="xxx"}
                    查询:使用自定义 resultMap 使用 Handler
    
                    注意:如果在参数位置修改TypeHandler,应该保证保存数据和查询数据使用的TypeHandler一样。
            -->
            <typeHandler handler="com.njf.mybatis.typeHandler.MyEnumEmpStatusTypeHandler" javaType="com.njf.mybatis.bean.EmpStatus" />
        </typeHandlers>

      其他方式:

      保存的时候给字段执行处理器:

        <!--
            public Long addEmp(Employee employee);
        -->
        <insert id="addEmp" parameterType="com.njf.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id">
            insert into tbl_employee(`last_name`, `email`, `gender`, `empStatus`)
            values(#{lastName}, #{email}, #{gender}, #{empStatus, typeHandler="全类名"})
        </insert>

      在查询的时候通过自定义 resultMap 来给字段指定处理器:

        <resultMap id="MyEmp" type="com.njf.mybatis.bean.Employee">
            <id column="id" property="id"/>
            <result column="empStatus" property="empStatus" typeHandler="com.njf.mybatis.typeHandler.MyEnumEmpStatusTypeHandler"/>
        </resultMap>
    
    
        <select id="getEmpById" resultMap="MyEmp">
            select id, last_name lastName, email, gender, empStatus from tbl_employee where id = #{id}
        </select>

      测试插入与查询:

         @Test
         public void testEnum() throws IOException {
              //1、获取 sqlSessionFactory
              SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
    
              //2、获取 sqlSession 实例,获取批量执行器
              SqlSession sqlSession = sqlSessionFactory.openSession();
              try {
                   //3、获取接口的实现类对象
                   EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
    
                   //Employee emp = new Employee(null, "test_enum", "1", "enum@126.com", EmpStatus.LOGIN);
                   //employeeMapper.addEmp(emp);
    
                   sqlSession.commit();
    
                   Employee empById = employeeMapper.getEmpById(13);
                   System.out.println("empById = " + empById);
                   System.out.println("员工状态:" + empById.getEmpStatus());
    
              } finally {
                   sqlSession.close();
              }
         }

      运行结果:

       可以看到数据库保存的是我们自定义的值。

       控制台打印的也是根据 code 获取的枚举类型。

  • 相关阅读:
    2020年7月3日 查找算法 代码
    QList 和QStringList为空 at()的错误
    网络编程TCP
    02#2位带操作
    04#认识指针
    03#指针内存图//拓展大小端序
    02#循环控制+分支控制+goto标签//拓展3目运算符和逗号运算符
    01#c语言基础内容
    输入的竖线变横
    Keil打包工程
  • 原文地址:https://www.cnblogs.com/niujifei/p/15312252.html
Copyright © 2020-2023  润新知