1.写在前面:
资料来自互联网,在此只是做一个汇总备忘,在做公司JAP数据脱敏,加解密用到了,就想如果是mybatis该怎么做方便,这里就找资料做一下备忘。
2.JAP 转换:
在java JPA注解中,有个@Convert注解,其中需要传入一个Class作为convert参数,该class需要实现AttributeConverter<X,Y>接口。下面来看看AttributeConverter接口的作用。
AttributeConverter<X,Y>
实体属性类型转换器。主要使用场景:
- 持久化enum
- 加解密数据
- 持久化日期
代码中数据类型,到数据库中类型,可能不一致或者需要做一个修饰转换,JPA里需要实现 AttributeConverter<X,Y>
该接口中现两个方法:
- y convertToDatabaseColumn(x) 作用:将实体属性x转化为y存储到数据库中,即插入和更新操作时执行;
- x convertToEntityAttribute(y) 作用:将数据库中的字段y转化为实体属性x,即查询操作时执行。
例如 :实体枚举类型到数据库种类型的相互转换:
@Entity
@Table(name = "t_demo")
public class DemoEntity {
@Convert(converter = StatusAttributeConverter.class)
private String status; //状态:1 启用,-1 禁用,-2 已删除
}
//-----------------------------------------------
public class StatusAttributeConverter implements AttributeConverter<String, Integer> {
@Override
public Integer convertToDatabaseColumn(String status) {
try {
return Integer.parseInt(status); //如果是数字,则直接返回(这里可以遍历StatusEnum的value来进一步验证)
} catch (NumberFormatException e) {
for (StatusEnum type : StatusEnum.values()) { //如果不是数字,则通过StatusEnum来找到描述对应的数字
if (status.equals(type.getDescription())) {
return type.getValue();
}
}
}
throw new RuntimeException("Unknown StatusEnum: " + status); //如果StatusEnum里不存在代表数字或描述,则抛出异常
}
@Override
public String convertToEntityAttribute(Integer value) {
for (StatusEnum type : StatusEnum.values()) { //将数字转换为描述
if (value.equals(type.getValue())) {
return type.getDescription();
}
}
throw new RuntimeException("Unknown database value: " + value);
}
}
//-----------------------------------------------
public enum StatusEnum {
ENABLE(1, "启用"), DISABLE(-1, "禁用"), DELETED(-2, "已删除");
StatusEnum(Integer value, String description) {
this.value = value;
this.description = description;
}
}
3.mybatis 字段类型转换
调研发现,有两种套路可寻,使用mybatis的拦截插件和自定义TypeHandler,这里先介绍TypeHandler的方式,需要自己代码实践验证。摘自:https://blog.csdn.net/acm_lkl/article/details/78609341
- TypeHandler接口方式
首先实现 TypeHandler 接口里面 getXXX,setXXX 方法,注意实现类上面的注解:@MappedJdbcTypes,@MappedTypes,MappedJdbcTypes是配置jdbc类型,这里的Jdbc类型必须org.apache.ibatis.type.JdbcType中的枚举类型, MappedTypes定义的是需要被拦截的java类型,TypeHandler T泛型,是传入的java类型。
例如:
package com.sankuai.lkl.typeHandler;
import com.sun.deploy.util.StringUtils;
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.Arrays;
import java.util.List;
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes({List.class})
public class ListTypeHandler implements TypeHandler<List<String>> {
@Override
public void setParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException {
String hobbys = StringUtils.join(parameter, ",");
try {
ps.setString(i, hobbys);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public List<String> getResult(CallableStatement cs, int columnIndex) throws SQLException {
String hobbys = cs.getString(columnIndex);
return Arrays.asList(hobbys.split(","));
}
@Override
public List<String> getResult(ResultSet rs, int columnIndex) throws SQLException {
return Arrays.asList(rs.getString(columnIndex).split(","));
}
@Override
public List<String> getResult(ResultSet rs, String columnName) throws SQLException {
return Arrays.asList(rs.getString(columnName).split(","));
}
}
然后,在mybaites配置文件 mybatis-config.xml里面,注册typehandler:
<typeHandlers>
<typeHandler jdbcType="VARCHAR" javaType="list"
handler="com.sankuai.lkl.typeHandler.ListTypeHandler"/>
</typeHandlers>
最后,在实体类sql mapping xml里面配置,字段的typehandler:
<insert id="insertPerson" parameterType="person">
INSERT INTO person (id,name,sex,hobbys,data_time) values(#{id},#{name},#{sex},#{hobbys,typeHandler=com.sankuai.lkl.typeHandler.ListTypeHandler},#{date})
</insert>
<resultMap id="personMap" type="person">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="hobbys" column="hobbys" typeHandler="com.sankuai.lkl.typeHandler.ListTypeHandler"/>
<result property="date" column="data_time"/>
</resultMap>