我们可以在IBATIS中加入我们自定义类的支持。
IBATIS 提供给了我们两个 接口:
1,TypeHandlerCallback (一般我们扩展这个接口,说实话它和TypeHandler有什么非常大的区别我还没看出来,希望有人能帮我解答 )
2,TypeHandler
这里我研究了 TypeHandlerCallback 写了下代码:
承接上一篇IBATIS中的代码修改了下babyDO类如下:
package com.yajun.dataobject; import java.util.Date; import org.apache.commons.lang.time.DateFormatUtils; import com.yajun.enumdemo.SexEnum; /** * Baby DO类 * * @author yajun * */ public class BabyDO { private int id; private String name; private SexEnum sex; private Date birthday; private String hobby; public String getName() { return name; } public void setName(String name) { this.name = name; } public SexEnum getSex() { return sex; } public void setSex(SexEnum sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "name :" + name + "\t" + "sex:" + sex.getValue() + "\t" + "birthday:" + DateFormatUtils.format(birthday, "yyyy-MM-dd") + "\t" + "hobby:" + hobby; } }
这里把Baby里面的性别写成了 Enum 类:
package com.yajun.enumdemo; /** * 性别枚举 * * @author yajun * */ public enum SexEnum { /** 男性 */ Male("male"), /** 女性 */ Female("female"), /** 人妖 */ Monster("monster"); private String value; private SexEnum(String value) { this.value = value; } public String getValue() { return value; } }
创建了处理这个enum类的handler ,继承了TypeHandlerCallback
package com.yajun.typehandler; import java.sql.SQLException; import com.ibatis.sqlmap.client.extensions.ParameterSetter; import com.ibatis.sqlmap.client.extensions.ResultGetter; import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback; import com.yajun.enumdemo.SexEnum; /** * 性别类型转换 * * @author yajun * */ public class SexEnumTypeHandlerCallBack implements TypeHandlerCallback { /** * 根据查询出来的变量值转换成相应的枚举值 */ public Object getResult(ResultGetter getter) throws SQLException { String s = getter.getString(); for (SexEnum sex : SexEnum.values()) { if (sex.getValue().equals(s)) { return sex; } } return null; } /** * 在设置参数前先转换成参数需要的类型 */ public void setParameter(ParameterSetter setter, Object parameter) throws SQLException { SexEnum sex = (SexEnum) parameter; setter.setString(sex.getValue()); } /** * 值类型转换 */ public Object valueOf(String s) { return Enum.valueOf(SexEnum.class, (String) s); } }
在resutlMap中加入一下配置:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="babyStore"> <typeAlias alias="baby" type="com.yajun.dataobject.BabyDO"/> <resultMap id="baby-Result" class="baby"> <result property="id" column="id" jdbcType="Integer" javaType="integer"/> <result property="name" column="name" jdbcType="VARCHAR" javaType="string"/> <result property="sex" column="sex" jdbcType="VARCHAR" javaType="com.yajun.enumdemo.SexEnum" typeHandler="com.yajun.typehandler.SexEnumTypeHandlerCallBack" /> <result property="birthday" column="birthday" jdbcType="DATE" javaType="date"/> <result property="hobby" column="hobby" jdbcType="VARCHAR" javaType="string"/> </resultMap> <select id="getBabyByParams" resultMap="baby-Result"> select * from Baby <dynamic prepend="where"> <isPropertyAvailable property="name" prepend="and"> name = #name# </isPropertyAvailable> <isPropertyAvailable property="sex" prepend="and"> sex = #sex,jdbcType=VARCHAR,javaType=com.yajun.enumdemo.SexEnum# </isPropertyAvailable> <isPropertyAvailable property="BirthdayBondStart" prepend="and"> <![CDATA[ birthday >= cast(#BirthdayBondStart# as datetime) ]]> </isPropertyAvailable> <isPropertyAvailable property="BirthdayBondEnd" prepend="and"> <![CDATA[ birthday <= cast(#BirthdayBondEnd# as datetime) ]]> </isPropertyAvailable> <isPropertyAvailable property="hobby" prepend="and"> hobby like '%'||#hobby#||'%' </isPropertyAvailable> </dynamic> </select> </sqlMap>
上面注意到两个地方必须有:
1,
result property="sex" column="sex" jdbcType="VARCHAR" javaType="com.yajun.enumdemo.SexEnum" typeHandler="com.yajun.typehandler.SexEnumTypeHandlerCallBack" 这句话中 jdbcType,javaType,TypeHandler 3个属性一个不能少,否则无效 。这里主要指明在返回结果的时候要用自定义的javaType包装
2,
sex = #sex,jdbcType=VARCHAR,javaType=com.yajun.enumdemo.SexEnum# 这里面的jdbcType,javaType 一个不能少,否则不能执行 setParameter方法。 这里主要指明在传入参数的时候需要自定义的javaType 进行包装
编写测试类:
package com.yajun; import java.sql.SQLException; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.time.DateFormatUtils; import com.yajun.dataobject.BabyDO; import com.yajun.enumdemo.SexEnum; import com.yajun.impl.BabyDAOImpl; /** * IBATIS 查找DEMO * * @author yajun * */ public class Demo { private BabyDAOImpl babyDAO = new BabyDAOImpl(); public static void main(String[] args) throws SQLException { Demo demo = new Demo(); System.out.println("============根据性别查找========"); demo.queryBySex(SexEnum.Male); } private void queryBySex(SexEnum sex) throws SQLException { Map<String, Object> params = new HashMap<String, Object>(); params.put("sex", sex); List<BabyDO> list = babyDAO.query(params); for (BabyDO baby : list) { System.out.println(baby); } } }
运行结果:
============根据性别查找========
name :吴亚军 sex:male birthday:2009-08-08 hobby:hao se
追踪了下ibatis的源代码关键点如下:
SqlExecutor 类的 executeQuery方法中的重点代码:
// 这里在设置参数 (执行了 TypeHandler 的setParameter()方法) statementScope.getParameterMap().setParameters(statementScope, ps, parameters); errorContext.setMoreInfo("Check the statement (query failed)."); // 开始执行 ps.execute(); errorContext.setMoreInfo("Check the results (failed to retrieve results)."); // 包装返回结果 (执行了 TypeHandler 的 getResult()方法) // Begin ResultSet Handling rs = handleMultipleResults(ps, statementScope, skipResults, maxResults, callback);
也就在这里面进行了的, 可以参考下图: