有的时候我们需要对一些数据库的字段进行加密,例如身份证号码,手机号码之类的。如果我们每次插入都调一次encode方法,在查询出来之后再调一次decode方法太过于麻烦,那么我们使用mybatis提供的TypeHandler来解决这个问题。
TypeHandler 提供了4个方法,第一个是处理方法是处理sql参数的,后面三个是处理返回值的
public interface TypeHandler<T> {
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
Mybatis 提供了一个抽象类 BaseTypeHandler 实现了 TypeHandler 接口,我们可以直接继承这个抽象类。我使用的是mybatis-plus 所以我直接使用了 mybatis-plus 的实现 AbstractJsonTypeHandler。 如果不是mybatis-plus可以直接使用 BaseTypeHandler
public abstract class AbstractJsonTypeHandler<T> extends BaseTypeHandler<T> {
public AbstractJsonTypeHandler() {
}
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, this.toJson(parameter));
}
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return StringUtils.isBlank(json) ? null : this.parse(json);
}
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
return StringUtils.isBlank(json) ? null : this.parse(json);
}
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
return StringUtils.isBlank(json) ? null : this.parse(json);
}
protected abstract T parse(String json);
protected abstract String toJson(T obj);
}
public class EncryptTypeHandler extends AbstractJsonTypeHandler<String> {
/**
* 处理结果集
* @param json
* @return
*/
@Override
protected String parse(String json) {
try {
return EncryUtil.decrypt(json);
} catch (Exception e) {
return json;
}
}
/**
* 处理参数
* @param obj
* @return
*/
@Override
protected String toJson(String obj) {
try {
return EncryUtil.encrypt(obj);
} catch (Exception e) {
return obj;
}
}
}
我们需要在对应的数据库实例类加上 autoResultMap = true,然后在需要加密的字段上 加上 typeHandler = EncryptTypeHandler.class 即可实现统一的加密和解密了
@Getter
@Setter
@Accessors(chain = true)
@TableName(value = "user",autoResultMap = true)
public class User extends BaseEntity {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("user_id")
private Long userId;
@TableField(value = "real_name",typeHandler = EncryptTypeHandler.class)
private String realName;
@TableField(value = "id_card_no",typeHandler = EncryptTypeHandler.class)
private String idCardNo;
}
有的时候我们需要通过xml 写sql 时,可能时导致Handler,我们需要加上对应的Handler
<update id="updateUser" parameterType="com.wa.user.entity.UserEntity">
UPDATE user
<set>
<if test="realName != null and realName != ''">
real_name= #{realName,typeHandler=com.wa.user.mybatis.EncryptTypeHandler},
</if>
<if test="idCardNo != null and idCardNo != ''">
id_card_no= #{idCardNo,typeHandler=com.wa.user.mybatis.EncryptTypeHandler},
</if>
update_time= now()
</set>
WHERE id= #{id}
</update>