主要内容
类型别名和类型处理器
这两个东西其实并没有什么关系,唯一的关系就是它们两都和类型有关,放到一起介绍只是因为它们的名称相似。
类型别名
类型别名,顾名思义,就是为一个类型另起一个名称,通常为了简化全限定类型名称的长度,没有什么技术性质可言。例如映射文件中没有配置类型别名的时候我们使用的是类的完全限定名称:
1 |
<select id="selectUser" resultType="cn.sharpcode.po.User" /> |
如果只有一个地方引用这个类,那么问题不大,否则每个引用的地方都使用全限定名称,那么工作量也不少,类型别名就是为了减少代码量的编写而存在的。mybatis中已经预定义了你能想到的大部分类型。
定义类型别名
通过typeAlias定义类型别名
类型别名在主配置文件(mybatis-config.xml)中定义,通过typeAlias元素可以简单地定义类型别名:
1 2 3 4 5 6 |
<configuration> <!-- 此处省略不必要的配置 --> <typeAliases> <typeAlias type="cn.sharpcode.po.User" alias="user" /> </typeAliases> </configuration> |
为cn.sharpcode.po.User定义user别名,其他地方就可以直接使用简写user,而不必再使用全限定名称。
1 |
<select id="selectUser" resultType="user" /> |
如果需要定义的类型别名过多,那么工作量也是巨大的,一个一个定义太浪费时间,因此,定义类型别名的另一种方法是使用包扫描的方式。
通过包扫描定义类型别名
1 2 3 4 5 |
<configuration> <typeAliases> <package name="cn.sharpcode.po" /> </typeAliases> </configuration> |
我们没有显式为pojo起名称,那么mybatis会按照驼峰式命名
自动为pojo定义别名,即第一个字母小写。当然,我们也可以显式指定别名,方法是在pojo中使用注解:
1 2 3 4 5 6 7 8 |
package cn.sharpcode.po; import org.apache.ibatis.type.Alias; @Alias("user") public class User { //一些属性和方法 } |
即使要在每个pojo中使用注解,但是比起之前的方法来说,工作量已经少很多了。
类型处理器
mybatis的主要作用就是操作数据库,那么,不可避免的问题就是java中的数据类型和数据库的数据类型不兼容。类型处理器的作用就是定义一系列方法,实现java类型到数据库类型的转换,或者反过来数据库类型到java类型的转换。
和类型别名一样,类型处理器已经预定义了大部分类型转换器,我们的程序大部分时候使用这些类型处理器已经可以很好地工作,但是,不可避免,我们总会遇到需要自定义类型处理器的时候。例如把用户输入的非法时间格式转换为合法的时间格式。我们都知道,sql不支持含有字符串”/”的时间格式,例如dd/MM/yyyy,入库之前需要把格式改成dd-MM-yyyy或yyyy-MM-dd。
可以通过两种方法实现自定义类型处理器,实现TypeHandler接口和继承BaseTypeHandler类,我们选择继承BaseTypeHandler,因为它已经为我们实现了一些细节性的东西,例如参数为null。
下面是一个完整的自定义类型处理器:
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 |
public class DateStringTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { String format = "dd/MM/yyyy"; SimpleDateFormat dateFormat = new SimpleDateFormat(format); if (parameter.contains("/")){ Date parse = null; try { parse = dateFormat.parse(parameter); } catch (ParseException e) { e.printStackTrace(); } dateFormat = new SimpleDateFormat("yyyy-MM-dd"); String now = dateFormat.format(parse); ps.setString(i, now); } } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } } |
使用自定义类型处理器
1. 在mybatis-config.xml中配置typeHandler:
1 2 3 |
<typeHandlers> <typeHandler handler="cn.sharpcode.typehandlers.DateStringTypeHandler" javaType="string" jdbcType="DATE" /> </typeHandlers> |
jdbcType中的值必须大写
2.在UserMapper中指定typeHandler
1 2 3 4 5 6 7 8 9 10 11 |
<?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="cn.sharpcode.mapper.UserMapper"> <insert id="insertTime"> UPDATE user SET regtime = #{regtime, javaType=string,jdbcType=DATE, typeHandler=cn.sharpcode.typehandlers.DateStringTypeHandler} WHERE id = 2 </insert> </mapper> |
现在再来看自定义类型处理器的代码,因为我们处理的是数据写入数据库的问题,所以只关注setNonNullParameter方法。
参数preparedStatement就是UserMapper中的UPDATE user SET regtime = #{regtime} WHERE id = 2。
除了我们自己编写的时间格式转换代码之外,setNonNullParameter方法的核心就是preparedStatement.setString(i, now)
;它的作用是把转换好的参数注入到sql语句的#{regtime}
占位符中。
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Test public void testTypeHandler() throws IOException, ParseException { String resource = "mybatis-config.xml"; InputStream resourceAsStream = Resources.getResourceAsStream(resource); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = build.openSession(); String now = "08/07/2017"; sqlSession.insert("cn.sharpcode.mapper.UserMapper.insertTime", now); sqlSession.close(); } |
转载请注明:Pure nonsense » mybatis类型别名(typeAlias)和类型处理器(typeHandler)