# 一.基本介绍

# 1.什么是 TypeHandler?

"TypeHandler" 通常指的是在软件开发中处理数据类型转换和操作的组件或模块。具体来说,TypeHandler 主要用于将一个数据类型转换为另一个数据类型,以便在不同的上下文中使用。

在不同的编程语言和框架中,TypeHandler 的实现方式可能有所不同。以下是一些常见的情况:

  1. 数据库中的 TypeHandler: 在持久化层,比如与数据库的交互中,TypeHandler 可能用于将数据库中的数据类型与应用程序中的数据类型进行映射。例如,将数据库中的字符串字段映射为应用程序中的整数类型。

  2. Web 开发中的 TypeHandler: 在处理用户输入或从网络传输数据时,可能需要将字符串转换为数字、日期等。TypeHandler 在这种情况下可以用于验证和转换数据类型。

  3. 对象关系映射 (ORM) 中的 TypeHandler: 在使用 ORM 框架时,TypeHandler 通常用于将数据库中的数据类型映射到编程语言中的数据类型。这是因为数据库和编程语言之间可能存在类型差异,需要进行适当的转换。

  4. 用户界面 (UI) 层中的 TypeHandler: 当用户与应用程序的用户界面交互时,输入数据通常以字符串形式提供。TypeHandler 在这里可以用于将用户输入的字符串转换为应用程序内部需要的数据类型。

TypeHandler 在软件开发中扮演着一个数据类型转换和操作的角色,有助于确保不同部分之间的数据一致性和正确性。具体实现方式取决于应用程序的需求和使用的技术栈。

# 2.BaseTypeHandler 使用场景?

org.apache.ibatis.type.BaseTypeHandler 是 MyBatis 中的一个抽象基类,用于简化自定义类型处理器(TypeHandler)的实现。MyBatis 是一个支持持久化的 Java 持久层框架,而类型处理器用于处理 Java 对象与数据库中的数据类型之间的映射关系。

BaseTypeHandler 提供了一些默认的实现,减少了自定义类型处理器的工作量。

# 3.BaseTypeHandler 常用方法?

如果你想自定义一个类型处理器,可以继承 BaseTypeHandler 并实现其中的一些方法。以下是 BaseTypeHandler 中的一些关键方法和其作用:

  1. setNonNullParameter 方法:

    • 用于将 Java 类型的非空参数设置到 PreparedStatement 对象中。
    • 子类需要实现此方法以指定如何将 Java 类型的非空参数设置到 PreparedStatement 中。
  2. getNullableResult 方法:

    • 从 ResultSet 中获取指定列的值,以及从 CallableStatement 中获取指定参数的值。
    • 子类需要实现此方法以指定如何从数据库结果集中获取数据。
  3. setNonNullParameter 方法:

    • 将非空的 Java 对象设置到 PreparedStatement 中。
    • 子类需要实现此方法以指定如何将 Java 对象设置到 PreparedStatement 中。
  4. getNullableResult 方法:

    • 从 ResultSet 中获取指定列的值,以及从 CallableStatement 中获取指定参数的值。
    • 子类需要实现此方法以指定如何从数据库结果集中获取数据。

通过继承 BaseTypeHandler,你可以只关注需要自定义的转换逻辑,而无需实现所有的方法。这样,你可以更方便地创建自己的类型处理器,用于处理特定类型的数据映射。

需要注意的是,MyBatis 也提供了一些预定义的类型处理器,用于处理常见的数据类型,如字符串、整数、日期等。但在某些情况下,你可能需要创建自己的类型处理器以处理特定的需求或自定义数据类型。

# 二.基础代码

# 1.启动类

@SpringBootApplication
public class AppRun {
    public static void main(String[] args) {
        SpringApplication.run(AppRun.class, args);
    }
}
1
2
3
4
5
6

# 2.创建 handler

public class Str2DateTypeHandler extends BaseTypeHandler<Date> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, date2Str(parameter));
    }

    @Override
    public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return str2Date(rs.getString(columnName));
    }

    @Override
    public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return str2Date(rs.getString(columnIndex));
    }

    @Override
    public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return str2Date(cs.getString(columnIndex));
    }

    private static Date str2Date(String str) {
        if (str == null || str.trim().length() == 0) return null;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return format.parse(str);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static String date2Str(Date date) {
        if (date == null) return null;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return format.format(date);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
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

# 3.mapper

@Mapper
public interface TestMapper extends BaseMapper<TestPO> {
    TestPO selectOne();
}
1
2
3
4

# 三.注解方式

# 1.注解方式

  • autoResultMap:用于自动生成结果映射,而无需手动定义映射关系。
  • typeHandler: 指定类型处理器。
  • @TableName(autoResultMap = true)
  • @TableField(typeHandler = Str2DateTypeHandler.class)
@Data
@TableName(value = "test", autoResultMap = true)
public class TestPO implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.NONE)
    private String id;

    @TableField(typeHandler = Str2DateTypeHandler.class)
    private Date date;
}
1
2
3
4
5
6
7
8
9
10
11

# 2.resultMap 配置

如果返回值是 resultMap 类型,可以通过配置 resultMap 中列的 typeHandler 属性进行类型转换。

<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="org.example.pojo.TestPO">
    <id column="id" property="id"/>
    <result column="date" property="date" typeHandler="org.example.typehandler.Str2DateTypeHandler"/>
</resultMap>
1
2
3
4
5

# 3.测试

使用 CommandLineRunner 进行测试,方便快捷。

@Component
public class TestRunner implements CommandLineRunner {

    @Autowired
    private TestMapper testMapper;

    @Override
    public void run(String... args) throws Exception {
        List<TestPO> list = this.testMapper.selectList(null);
        System.out.println(list.get(0).getId() + " - " + list.get(0).getDate());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 四.全局配置方式

# 1.全局配置方式

设置类型处理的包路径: type-handlers-package

mybatis-plus:
  mapper-locations: classpath*:mapper/*Mapper.xml
  configuration:
    cache-enabled: true
  type-handlers-package: org.example.typehandler
1
2
3
4
5

# 2.SQL 语句

数据库 date 是 String 类型,PO 定义的是 Date 类型,直接查询数据是会报错的。

<select id="selectOne" resultType="org.example.pojo.TestPO">
    SELECT id, date
    FROM test limit 1;
</select>
1
2
3
4

# 3.测试用例

使用 CommandLineRunner 进行测试,方便快捷。

@Component
public class TestRunner2 implements CommandLineRunner {

    @Autowired
    private TestMapper testMapper;

    @Override
    public void run(String... args) throws Exception {
        TestPO testPO = this.testMapper.selectOne();
        System.out.println(testPO.getId() + " - " + testPO.getDate());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 五.源码分析

# 1.BaseTypeHandler

需要重写的四个方法如下:

public abstract void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;

public abstract T getNullableResult(ResultSet var1, String var2) throws SQLException;

public abstract T getNullableResult(ResultSet var1, int var2) throws SQLException;

public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
1
2
3
4
5
6
7

# 2.setNonNullParameter

作用: 该方法用于将 Java 类型的非空参数设置到 PreparedStatement 对象中,以便将数据插入到数据库中。

参数:

  • var1:表示要设置参数的 PreparedStatement 对象。
  • var2:表示要设置的参数的位置。
  • var3:表示要设置的非空参数值,即从 Java 对象映射到数据库中的数据。
  • var4:表示 JDBC 类型,用于指定参数的数据类型。

异常: 抛出 SQLException,以处理可能的数据库操作异常。

# 3.getNullableResult(接受列名参数)

作用: 该方法从 ResultSet 中获取指定列的值,并将其映射为 Java 对象,处理可空的查询结果。

参数:

  • var1:表示要获取数据的 ResultSet 对象。
  • var2:表示要获取的列的名称。

返回值: 返回映射到 Java 对象的可空结果。

异常: 抛出 SQLException,以处理可能的数据库操作异常。

# 4.getNullableResult(接受列索引参数)

作用: 该方法从 ResultSet 中获取指定列的值,并将其映射为 Java 对象,处理可空的查询结果。

参数:

  • var1:表示要获取数据的 ResultSet 对象。
  • var2:表示要获取的列的索引。

返回值: 返回映射到 Java 对象的可空结果。

异常: 抛出 SQLException,以处理可能的数据库操作异常。

# 5.getNullableResult 方法(接受 CallableStatement 参数)

作用: 该方法从 CallableStatement 中获取指定位置的值,并将其映射为 Java 对象,处理可空的查询结果。

参数:

  • var1:表示要获取数据的 CallableStatement 对象。
  • var2:表示要获取的位置。

返回值: 返回映射到 Java 对象的可空结果。

异常: 抛出 SQLException,以处理可能的数据库操作异常。

# 6.类图关系

image-20231128122432039

上次更新: 10/29/2024, 10:27:50 AM