我们在不使用spring来管理的时候通常把typehandler的配置放到mybatis-config.xml中,如下:
<configuration>
<typeHandlers>
<!--
当配置package的时候,mybatis会去配置的package扫描TypeHandler
<package name="com.dy.demo"/>
-->
<!-- handler属性直接配置我们要指定的TypeHandler -->
<typeHandler handler=""/>
<!-- javaType 配置java类型,例如String, 如果配上javaType, 那么指定的typeHandler就只作用于指定的类型 -->
<typeHandler javaType="" handler=""/>
<!-- jdbcType 配置数据库基本数据类型,例如varchar, 如果配上jdbcType, 那么指定的typeHandler就只作用于指定的类型 -->
<typeHandler jdbcType="" handler=""/>
<!-- 也可两者都配置 -->
<typeHandler javaType="" jdbcType="" handler=""/>
</typeHandlers>
......
</configuration>
但是对于我们现在的开发环境来说,spring太流行了,所以这里就成了一块问题。
闲话不多说,直接上spring的配置:
<!--声明TypeHandler bean-->
<bean id="myStringTypeHandler" class="util.MyStringTypeHandler"/>
<!-- 创建spring工厂 -->
<bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--data source的配置不变-->
<property name="dataSource" ref="ds"/>
<!--实体类别名-->
<property name="typeAliasesPackage" value="model"/>
<!--mapper文件注入-->
<property name="mapperLocations" value="classpath:/mybatis-mapper/*/*DaoImpl.xml"/>
<!--typeHandler注入-->
<property name="typeHandlers" ref="myStringTypeHandler"/>
</bean>
下面简单的介绍下typehandler的配置吧。
首先是官方对于这个属性的介绍:
以下是mybatis中转化string的源码:
package org.apache.ibatis.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class StringTypeHandler extends BaseTypeHandler<String> {
public StringTypeHandler() {
}
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}
BaseTypeHandler源码:
package org.apache.ibatis.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.session.Configuration;
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
protected Configuration configuration;
public BaseTypeHandler() {
}
public void setConfiguration(Configuration c) {
this.configuration = c;
}
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if(parameter == null) {
if(jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException var6) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + var6, var6);
}
} else {
this.setNonNullParameter(ps, i, parameter, jdbcType);
}
}
public T getResult(ResultSet rs, String columnName) throws SQLException {
T result = this.getNullableResult(rs, columnName);
return rs.wasNull()?null:result;
}
public T getResult(ResultSet rs, int columnIndex) throws SQLException {
T result = this.getNullableResult(rs, columnIndex);
return rs.wasNull()?null:result;
}
public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
T result = this.getNullableResult(cs, columnIndex);
return cs.wasNull()?null:result;
}
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;
}
经过查看我们发现只需要实现BaseTypeHandler这个抽象类即可,记得泛型一定是String。
以下是我自己的代码,其中oracle数据库编码为ISO-8859-1,项目编码为GBK:
package util;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.log4j.Logger;
import java.io.UnsupportedEncodingException;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 转化String的result与parameter
* 注意:实现BaseTypeHandler时,泛型必须为String
*/
public class MyStringTypeHandler extends BaseTypeHandler<String> {
private static final Logger log = Logger.getLogger(MyStringTypeHandler.class);
/**
* 转化字符串编码
* @param str
* @param oldCharset
* @param newCharset
* @return
*/
private static String convertEncoding(String str,String oldCharset,String newCharset){
String resultStr = null;
try{
if (str == null) {
return resultStr;
}
resultStr = new String(str.getBytes(oldCharset),newCharset);
}catch(UnsupportedEncodingException e){
log.error(e.getMessage(),e);
}
return resultStr;
}
public MyStringTypeHandler() {
}
@Override
public void setNonNullParameter(PreparedStatement ps, int index, String parameter, JdbcType jdbcType) throws SQLException {
parameter = convertEncoding(parameter, "GBK","ISO-8859-1");
ps.setString(index,parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return convertEncoding(rs.getString(columnName),"ISO-8859-1","GBK");
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return convertEncoding(rs.getString(columnIndex),"ISO-8859-1","GBK");
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return convertEncoding(cs.getString(columnIndex),"ISO-8859-1","GBK");
}
}
补充:以上可以解决正常的需求,但是大多码农都是不正常的,最近又遇到一个问题,也在这里加上。
当我们插入数据的时候,有些数据是可以为空的,MyBatis支持我们这样写:
<!--一个简单的插入语句-->
<insert id="insertUser">
insert into user
(id,username,password,address)
values
(#{id},
#{username}
#{password},
#{address,jdbcType=VARCHAR})
</insert>
这就会产生问题了,在我们加上了jdbcType=xxx这个配置后,MyBatis不再访问我们的TypeHandler,之后经过百度,发现可以使用如下几种方式解决:
<!--配置resultMap-->
<resultMap id="userResultMap" type="User">
<result typeHandler="StringTypeHandler" column="address" javaType="java.lang.String"
jdbcType="VARCHAR"
property="address"/>
</resultMap>
<!--调用-->
<select id="getUser" resultMap="userResultMap">
select * from user
</select>
<!--这个方法的缺点在于配置比较繁琐,返回时配置resultMap,插入时配置parameterMap,还要设置每个对象的每一个属性-->
<!--这个方法简洁了很多,但是你想想我们有一个20多个字段的表,好吧,画面太美不敢想-->
<insert id="insertUser" parameterType="User">
INSERT INTO user(username,password,address) VALUES (#{username},#{password},#{address,javaType=String,jdbcType=VARCHAR,typeHandler=StringTypeHandler(这里注意要写类全名的)})
</insert>
我推荐下面这个方法,经过注解配置,数据库类型为xxx的,java类型为xxx的,都会经过这个转换类,果然注解才是好东西哇~
另外,你注意到注解中的值被用大括号括起来了么,这说明注解值可以是一个数组,就像我们这个字符转码类,
还能这样:@MapperJdbcTypes({JdbcType.VARCHAR,JdbcType.CHAR})
和这样:@MappedTypes({String.class,Character.class})
当然,我只是举个栗子,还是要看需求的
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
//这个注解定义的是JdbcType类型,这里的类型不可自己随意定义,必须要是枚举类org.apache.ibatis.type.JdbcType所枚举的数据类型
@MappedJdbcTypes({JdbcType.VARCHAR})
//这里定义的是JavaType的数据类型,描述了哪些Java类型可被拦截
@MappedTypes({String.class})
public class StringTypeHandler extends BaseTypeHandler<String> {...}
学习知识要晓出处,以上的配置jdbcType方法学习自
http://blog.csdn.net/u012702547/article/details/54572679
如果有不对的地方,还请大神在下面评论区指导。当然,如果这些代码有什么疑问,也可以在下方留言。