引言:有很多场景,Mybatis提供的自动类型解析并不能够满足功能需求,例如你期望将一个
List
存入数据库中,这时就需要自己配置一个类型解析器。
这里首先进行我的业务场景说明:
我需要实现如下 sql 字段属性与实体类的转换:
`subject` set('CHINESE','MATH','ENGLISH','PHYSICS','CHEMISTRY','BIOLOGY','GEOGRAPHY','HISTORY','POLITICS','ART') NOT NULL,
我期望它转换成一个 List
的实体类属性:
private List<Subject> subject; //科目
这里的 Subject
是我的一个枚举类型,代码如下:
public enum Subject {
CHINESE,//语文
MATH,//数学
ENGLISH,//英语
PHYSICS,//物理
CHEMISTRY,//化学
BIOLOGY,//生物
GEOGRAPHY,//地理
HISTORY,// 历史
POLITICS,//政治
ART// 艺术
}
首先,需要自定义一个类型解析器满足自己的需要:
import com.qinghe.enums.Subject;
import com.qinghe.util.StringToEnumList;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* auther:XingTL
* date:2020/6/10 20:10
*/
/**
* 自定义类型解析器
* 用于 Mybatis List 到数据库 subject 字段的映射
*/
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(List.class)
public class SubjectTypeHandler implements TypeHandler<List<Subject>> {
//调用工具类方法 复用代码
private static final StringToEnumList<Subject> toEnumList = new StringToEnumList<>(Subject.class);
/**
* 设置参数
*
* @param ps 数据库中存放字段
* @param i
* @param parameter 对象中字段
* @param jdbcType
* @throws SQLException
*/
@Override
public void setParameter(PreparedStatement ps, int i, List<Subject> parameter, JdbcType jdbcType) throws SQLException {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < parameter.size(); j++) {
sb.append(parameter.get(j));
System.out.println(parameter.get(j));
if (j != parameter.size() - 1) {
sb.append(",");
}
}
ps.setString(i, sb.toString());
}
//按列名,拿到值封装成javabean对象
@Override
public List<Subject> getResult(ResultSet rs, String columnName) throws SQLException {
//需要根据从数据库中拿到的枚举的状态码返回一个枚举对象
String string = rs.getString(columnName);
return toEnumList.stringToEnumList(string);
}
//按索引,拿到值封装成javabean对象
@Override
public List<Subject> getResult(ResultSet rs, int columnIndex) throws SQLException {
String string = rs.getString(columnIndex);
return toEnumList.stringToEnumList(string);
}
//存储过程拿到值,封装
@Override
public List<Subject> getResult(CallableStatement cs, int columnIndex) throws SQLException {
String string = cs.getString(columnIndex);
return toEnumList.stringToEnumList(string);
}
}
这里的StringToEnumList
类是我自定义的一个实体类,用来封装String
转化为各种Enum
类型的List
,增强代码的复用,下次如果需要转化另一个不同类型的枚举类型,就只需要改变传入的泛型。
StringToEnumList
工具类代码如下:
import java.util.ArrayList;
import java.util.List;
/**
* string 转 enum list 工具类
* 给 Mybatis自定义类型解析器使用
* @param
*
* auther:XingTL
* date:2020/6/10 21:31
*/
public class StringToEnumList<T extends Enum<T>> {
private final Class<T> enumType;
public StringToEnumList(Class<T> enumType){
this.enumType = enumType;
}
public List<T> stringToEnumList(String string){
String[] split = string.split(",");
ArrayList<T> list = new ArrayList<>();
for (String s :split) {
list.add(T.valueOf(enumType,s));
// System.out.println(Subject.valueOf(s));//打印查看
}
return list;
}
}
需要在Mybatis配置文件中加入内容:
<typeHandlers>
<typeHandler jdbcType="VARCHAR" javaType="java.util.List"
handler="com.qinghe.myTypeHandler.SubjectTypeHandler"/>
typeHandlers>
如果使用SSM整合了Mybatis,就在配置SqlSessionFactory
里添加字段:
<!-- 配置mybatis的sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mappers.xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<!-- 扫描mybatis-config文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 扫描domain包,使用别名,或者在mybatis-config中配置,二选一 -->
<property name="typeAliasesPackage" value="com.qinghe.domain"/>
<!--typeHandler注入-->
<!-- 这里是要配置多个的情况下,如果单个的话直接在 property 标签里 ref 即可 -->
<property name="typeHandlers">
<list>
<ref bean="subjectTypeHandler"/>
<!-- <ref bean="stringArrayTypeHandler"/>-->
<!-- <ref bean="stringListTypeHandler"/>-->
</list>
</property>
</bean>
之后就是在mapper.xml
中使用了 :
配置查询返回
<resultMap id="BaseResultMap" type="com.qinghe.domain.StuRelease" >
//....
<result column="subject" property="subject" jdbcType="VARCHAR" typeHandler="com.qinghe.myTypeHandler.SubjectTypeHandler"/>
//.....
resultMap>
其余的操作需要在sql中写清TypeHandler 如下插入操作:
<insert id="insert" parameterType="com.qinghe.domain.StuRelease" >
insert into stu_release ( ...,subject, ...)
values ( ..., #{subject,typeHandler=com.qinghe.myTypeHandler.SubjectTypeHandler},...)
insert>
以上即自定义类型解析器的所有内容