1.背景
为什么要做自定义类型转换器。就是为了解决 java 类中的属性和数据库表字段属性类型不一致的情况。例如如下案例:
我们可以看到 id、name、age的属性表与实体类都是一一对应的,但是 sex确不对应,此时如果我们不进行类型转换,那么向表 person 插入数据的时候会报错,查询的时候性别 sex 会显示空值(NULL),为了解决类似这种情形,我们需要自定义类型转换器;
2.具体实现步骤
我们通过实例具体对其进行演示,具体实现步骤如下:
- 在 mysql 数据库中建立一个表 person,建表语句如下:
create table person ( id int(10) auto_increment comment '人员ID' primary key, name varchar(20) null comment '姓名', age int(20) null comment '年龄', sex int(10) null comment '性别:1-男,0-女' ) comment '人力表';
- 建立一个实体类 命名为 Person,省略其 Setter、Getter 以及 toString 方法
package com.entity; /** * 类注释 * * @author Lenovo * @Title: Person * @ProjectName mybatisYG * @Description: TODO 与 person 对应的 Person 实体类 * @date 2019/11/1513:54 */ public class Person { private int id; private String name; private int age; private String sex; public Person() { } public Person(int id, String name, int age, String sex) { this.id = id; this.name = name; this.age = age; this.sex = sex; } @Setter
@Getter
@toString
}
- 建立转换器类,叫其继承 BaseTypeHandler(当然也可以叫其实现 TypeHandler 接口,BaseTypeHandler 为 TypeHandler 接口的实现类),具体实现代码如下:
package com.convert; 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; /** * 类注释 * * @author Lenovo * @Title: StringToInt * @ProjectName mybatisYG * @Description: TODO 建立一个转换器,将String 转换为 int * @date 2019/11/1515:57 */ public class StringToInt extends BaseTypeHandler<String> { /* 该方法实现:通过 java类向数据库中设置(插入数据) 参数含义:第一个为 JDBC 预处理对象,第二个为操作的位置,第三个为 javaType,第四个为 jdbcTpye*/ @Override public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException { //如果是男,则存储到数据库中为1,如果为女,则存储在数据库中为0 if (s.equals( "男" )) { preparedStatement.setInt( i, 1 ); } else { preparedStatement.setInt( i, 0 ); } } /*该方法实现通过列名获取数据库表中的数据*/ @Override public String getNullableResult(ResultSet resultSet, String s) throws SQLException { int sex = resultSet.getInt( s ); /* 三目运算符,如果表达式为 true,返回第一个值,如果表达式为 false,返回第二个值 */ return sex == 1 ? " 男" : "女"; } /*该方法实现通过列标获取数据库表中的数据*/ @Override public String getNullableResult(ResultSet resultSet, int i) throws SQLException { int sex = resultSet.getInt( i ); /* 三目运算符,如果表达式为 true,返回第一个值,如果表达式为 false,返回第二个值 */ return sex == 1 ? " 男" : "女"; } /*该方法实现通过存储过程获取数据库表中的数据*/ @Override public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException { int sex = callableStatement.getInt( i ); /* 三目运算符,如果表达式为 true,返回第一个值,如果表达式为 false,返回第二个值 */ return sex == 1 ? " 男" : "女"; } }
- 在 mybatis-config.xml 中配置自定义的转换器
<!--配置类型转换器--> <typeHandlers> <typeHandler handler="com.convert.StringToInt" javaType="String" jdbcType="INTEGER"></typeHandler> </typeHandlers>
- 配置实体类 Person 的映射文件 PersonMapper.xml,具体配置内容如下:
<?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.mapper.PersonMapper"> <!--带转换器查询单个人员信息--> <select id="selectById" resultMap="PersonResult" parameterType="int"> select * from person where id=#{id} </select> <resultMap id="PersonResult" type="Person"> <!--主键是 id,其他列值为result--> <id property="id" column="id"></id> <result property="name" column="name"></result> <result property="age" column="age"></result> <result property="sex" column="sex" javaType="String" jdbcType="INTEGER"></result> </resultMap> <!--带转换器形式的插入一个人员信息--> <insert id="addPerson" parameterType="Person"> INSERT INTO person (id, name, age, sex) VALUES (#{id}, #{name}, #{age}, #{sex,javaType=String,jdbcType=INTEGER}) </insert> </mapper>
- 新建 PersonMapper.xml 对应的动态代理接口 PersonMapper,具体代码如下:
package com.mapper; import com.entity.Person; /** * 类注释 * * @author Lenovo * @Title: PersonMapper * @ProjectName mybatisYG * @Description: TODO 与 PersonMapper.xml 文件同级的 动态代理接口 * @date 2019/11/1513:59 */ public interface PersonMapper { //按照 id 值查询指定的人员信息 Person selectById(int id); //插入一个人员信息 void addPerson(Person person); }
- 编写测试类,例如我们要查询,核心代码如下:
Reader reader = Resources.getResourceAsReader( "mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build( reader ); //创建 session--相当于 connection SqlSession session = sqlSessionFactory.openSession(); //动态代理 建立 PersonMapper 接口和 PersonMapper.xml 文件的映射关系 PersonMapper personMapper = session.getMapper( PersonMapper.class ); Person person = personMapper.selectById( 1 ); System.out.println( "查询出来的人员信息为:" + person ); //关闭session session.close();
经过如上步骤,即完成了一个简单的类型转换。
3.总结
总结起来,要想自定义类型转换器,需要经过如下步骤:
- 创建类型转换器的类,需要实现 TypeHandler 接口,或者继承其实现类 BaseTypeHandler
- 需要在 mybatis 的全局配置文件中配置类型转换器,配置项为:
<!--配置类型转换器--> <typeHandlers> <typeHandler handler="com.convert.StringToInt" javaType="String" jdbcType="INTEGER"></typeHandler> </typeHandlers>
三个参数的含义如下:
handler:转换器类的全路径名
javaType:实体类中的属性类型;
jdbcType:数据库表的字段类型;
- 在mapper.xml 文件中进行引用,如果是查询,需要将返回类型变为 resultMap。
<select id="selectById" resultMap="PersonResult" parameterType="int"> select * from person where id=#{id} </select> <resultMap id="PersonResult" type="Person"><!--此 id 值必须和 select 标签中的 resultMap 的值完全一致--> <!--主键是 id,其他列值为result--> <id property="id" column="id"></id><!--此为表的主键--> <result property="name" column="name"></result> <result property="age" column="age"></result> <result property="sex" column="sex" javaType="String" jdbcType="INTEGER"></result> </resultMap>