Mybatis 自定义类型解析器

Mybatis自定义类型解析器

引言:有很多场景,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>

以上即自定义类型解析器的所有内容

你可能感兴趣的:(Java学习,mybatis,java,数据库)