mybatis自定义typeHandler

在做开发的时候,经常会遇到关于数据类型的问题,mybatis本身已经为我们提供了许多typeHandler了,系统提供的typeHandler能够满足我们日常开发中的大部分需求,但是有时候也会遇到需要自己定义typeHandler的情况,比如说我在数据库中有一个WfWorkSpace表,其中有一个字段Handler记录了当前处理人的信息,在数据库中改字段类型是varchar,但是在java代码中这个Handler的数据结构是一个实体类,如下所示:

@Data
public class Handler implements POJO {

  /**
   * 
   */
  private static final long serialVersionUID = 1L;

  private Set<UserLink> users;

  private Set<GroupLink> groups;

}

在mybatis的xml文件中有如下的映射关系

<resultMap type="com..entity.WfWorkSpace" id="wfWorkSpaceMap">
	<result column="ID" jdbcType="NUMERIC" property="id" />
        <result column="HANDLER" jdbcType="VARCHAR" property="handler" />
    
</resultMap>

WfWorkSpace实体类为:

public class WfWorkSpace extends LongIdVO {

  /**
   * 
   */
  private static final long serialVersionUID = -5555413588381268957L;

  private Long id;
 
  private Handler handler;

这个时候就需要涉及到自定义一个mybatis的typeHandler问题了

自定义typeHandler继承自BaseTypeHandler

第一步,实现一个集成自BaseTypeHandler的公共数据格式处理的类JsonTypeHandler:

public class JsonTypeHandler<T> extends BaseTypeHandler<T> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setString(i, JSON.toJSONString(parameter));
  }

  @Override
  public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return JSON.parseObject(rs.getString(columnName), getRawType());
  }

  @Override
  public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    return JSON.parseObject(rs.getString(columnIndex), getRawType());
  }

  @Override
  public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    return JSON.parseObject(cs.getString(columnIndex), getRawType());
  }
}

第二步,自定义TypeHandler类型:

@Component
@MappedTypes(Handler.class)
public class HandlerTypeHandler extends JsonTypeHandler<Handler> {

}

另外我们还可以实现下面两种场景,比如我有一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,怎么实现?再比如我有一个User类,User类中有一个属性叫做interest,这个属性用来描述用户的爱好,它的数据类型是一个List集合,那么我想在把这个List集合存入数据库的时候能够自动的变成{XXX,XXX,XXX}这样一个字符串然后存起来,当我从数据库读取的时候也是读取到这样一个字符串,读取成功之后再自动的将之转为一个List集合

1:日期转换

@MappedJdbcTypes({JdbcType.VARCHAR})
@MappedTypes({Date.class})
public class MyDateTypeHandler extends BaseTypeHandler<Date> {
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        preparedStatement.setString(i, String.valueOf(date.getTime()));
    }

    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return new Date(resultSet.getLong(s));
    }

    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return new Date(resultSet.getLong(i));
    }

    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return callableStatement.getDate(i);
    }
}

自定义好了typeHandler之后,接下来我们需要在userMapper.xml中进行简单的配置,首先我们可以像上文说的,配置resultMap,如下:

<resultMap id="userResultMap" type="com.bean.User">
        <result typeHandler="com.db.MyDateTypeHandler" column="regTime" javaType="java.util.Date"
                jdbcType="VARCHAR"
                property="regTime"/>
    </resultMap>

配置resultMap的时候我们指定了javaType和jdbcType,同时也指定了处理的typeHandler,然后在select中使用这个resultMap:

<select id="getUser" resultMap="userResultMap">
        select * from user4
    </select>

但是这种方式有一个缺点那就是只适用于查询操作,即在查询的过程中系统会启用我们自定义的typeHandler,会将秒数转为Date对象,但是在插入的时候却不会启用我们自定义的typeHandler,想要在插入的时候启用自定义的typeHandler,需要我们在insert节点中简单配置一下,如下:

<insert id="insertUser" parameterType="org.sang.bean.User">
        INSERT INTO user4(username,password,regTime) VALUES (#{username},#{password},#{regTime,javaType=Date,jdbcType=VARCHAR,typeHandler=org.sang.db.MyDateTypeHandler})
    </insert>

也可以只配置javaType和jdbcType,如下:

<insert id="insertUser2">
        INSERT INTO user4(username,password,regTime) VALUES (#{username},#{password},#{regTime,javaType=Date,jdbcType=VARCHAR})
    </insert>

或者只配置typeHandler:

<insert id="insertUser3">
        INSERT INTO user4(username,password,regTime) VALUES (#{username},#{password},#{regTime,typeHandler=com.db.MyDateTypeHandler})
    </insert>
这三种效果都是一样的,都是在插入的时候将数据Date对象转为秒数


2:List集合的转换

@MappedTypes(List.class)
@MappedJdbcTypes({JdbcType.VARCHAR})
public class MyListTypeHandler extends BaseTypeHandler<List<String>> {
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, List<String> strings, JdbcType jdbcType) throws SQLException {
        //1.List集合转字符串
        StringBuffer sb = new StringBuffer();
        for (String string : strings) {
            sb.append(string).append(",");
        }
        //2.设置给ps
        preparedStatement.setString(i, sb.toString().substring(0, sb.toString().length() - 1));
    }

    public List<String> getNullableResult(ResultSet resultSet, String s) throws SQLException {
        String[] split = resultSet.getString(s).split(",");
        return Arrays.asList(split);
    }

    public List<String> getNullableResult(ResultSet resultSet, int i) throws SQLException {
        String[] split = resultSet.getString(i).split(",");
        return Arrays.asList(split);
    }

    public List<String> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        String[] split = callableStatement.getString(i).split(",");
        return Arrays.asList(split);
    }
}

查询:

<select id="getPerson" resultType="com.bean.Person">
        select * from person
    </select>

插入:

<insert id="insertPerson">
        INSERT INTO person(interest) VALUES (#{interest,typeHandler=com.db.MyListTypeHandler})
</insert>

List集合存入数据库之后变成这样: 


读取出来之后又自动转为List集合了,下图是查询操作,实体类,和查询结果: 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值