目录

mybatis自定义TypeHandler

目录

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

步骤:

  1. 实现TypeHandler接口或者继承BaseTypeHandler

  2. 使用@MappedTypes定义处理的java类型

    使用@MappedJdbcTypes定义jdbcType类型

  3. 在自定义结果集标签或者参数处理的时候声明使用自定义 TypeHandler进行处理

    • 保存 #{deptStatus,typeHandler=com.eh.eden.mybatis.enums.StatusEnumTypeHandler}

    • 查询

      1
      2
      3
      4
      5
      6
      
      <resultMap id="dept" type="com.eh.eden.mybatis.orm.bean.Dept">
              <id column="id" property="id"/>
              <result column="dept_name" property="deptName"/>
              <result column="dept_status" property="deptStatus"
                      typeHandler="com.eh.eden.mybatis.enums.StatusEnumTypeHandler"/>
          </resultMap>
      

    或者在全局配置TypeHandler要处理的javaType,如下示例程序

示例程序

数据准备:

1
ALTER TABLE tbl_dept add column dept_status int(3);

一个代表部门状态的枚举类DeptStatus

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.eh.eden.mybatis.enums;

public enum DeptStatus implements IStatusEnum {
    WORKING(100, "工作中"),
    MEETING(100, "会议中"),
    VOCATION(100, "休假中");


    private int code;
    private String desc;

    DeptStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }


    @Override
    public int getCode() {
        return code;
    }

    @Override
    public void setCode(int code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }
}

IStatusEnum

1
2
3
4
5
6
7
8
9
package com.eh.eden.mybatis.enums;


public interface IStatusEnum<E> {
    int getCode();

    void setCode(int code);

}

StatusEnumUtil

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.eh.eden.mybatis.enums;

public class StatusEnumUtil {

    public static <E extends Enum<E> & IStatusEnum<E>> E getEnumByCode(E e, int code) {
        if (e == null) {
            throw new RuntimeException("传入枚举类型不能为空");
        }
        return getEnumByCode((Class<E>) e.getClass(), code);
    }

    public static <E extends Enum<E> & IStatusEnum<E>> E getEnumByCode(Class<E> clazz, int code) {
        try {
            E[] es = clazz.getEnumConstants();
            for (E e : es) {
                if (code == e.getCode()) return e;
            }
        } catch (Exception e) {
            throw new RuntimeException("枚举类型转换内部错误");
        }
        throw new RuntimeException(String.format("通过%s没有找到具体的枚举类型", String.valueOf(code)));
    }

}

StatusEnumTypeHandler

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.eh.eden.mybatis.enums;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class StatusEnumTypeHandler<E extends Enum<E> & IStatusEnum<E>> extends BaseTypeHandler<E> {
    private final Class<E> type;

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

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        if (jdbcType == null) {
            ps.setInt(i, parameter.getCode());
        } else {
            ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589
        }
    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Integer code = rs.getInt(columnName);
        return code == null ? null : StatusEnumUtil.getEnumByCode(type, code);
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        Integer code = rs.getInt(columnIndex);
        return code == null ? null : StatusEnumUtil.getEnumByCode(type, code);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        Integer code = cs.getInt(columnIndex);
        return code == null ? null : StatusEnumUtil.getEnumByCode(type, code);
    }
}

mybatis-config.xml

1
2
3
4
<typeHandlers>
    <typeHandler handler="com.eh.eden.mybatis.enums.StatusEnumTypeHandler"
                 javaType="com.eh.eden.mybatis.enums.IStatusEnum"/>
</typeHandlers>

DeptMapper.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<resultMap id="dept" type="com.eh.eden.mybatis.orm.bean.Dept">
        <id column="id" property="id"/>
        <result column="dept_name" property="deptName"/>
        <result column="dept_status" property="deptStatus"/>
    </resultMap>

    <insert id="insertSelective" parameterType="com.eh.eden.mybatis.orm.bean.Dept">
        insert into tbl_dept
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">
                id,
            </if>
            <if test="deptName != null">
                dept_name,
            </if>
            <if test="deptStatus != null">
                dept_status,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">
                #{id,jdbcType=INTEGER},
            </if>
            <if test="deptName != null">
                #{deptName,jdbcType=VARCHAR},
            </if>
            <if test="deptStatus != null">
                #{deptStatus}
            </if>
        </trim>
    </insert>

    <select id="getDeptById" resultMap="dept">
        select id, dept_name,dept_status from tbl_dept where id = #{id}
    </select>

测试类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void testTypeHandlerSelect() throws IOException {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    try (SqlSession session = sqlSessionFactory.openSession()
    ) {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = deptMapper.getDeptById(4);
        System.out.println(dept);
    }
}

@Test
public void testTypeHandlerInsert() throws IOException {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    try (SqlSession session = sqlSessionFactory.openSession(true)
    ) {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        deptMapper.insertSelective(new Dept(null, "人事部", null, DeptStatus.WORKING));
    }
}