TypeHandler
TypeHandler
作用
实现 Java 类型和 jdbc 类型的相互转换
类型处理器接口有一个实现类 CompositeEnumTypeHandler
和一个抽象实现类 BaseTypeHandler
BaseTypeHandler
继承 TypeReference
作用是得到获取泛型类型的能力 BaseTypeHandler
实现 TypeHandler
作用是针对不同的泛型类型的实现提供统处理一部分信息的能力,如在 setParameter
时判断空直接处理,不为空时调用具体实现类。
public interface TypeHandler<T> {
// 插入和更新时设置参数调用
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
// 通过字段名从查询结果中获取对象。when configuration useColumnLabel is false
T getResult(ResultSet rs, String columnName) throws SQLException;
// 通过字段顺序从结果中获取对象
T getResult(ResultSet rs, int columnIndex) throws SQLException;
// 通过字段顺序从结果中获取对象
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
各个类型实现类再继承 BaseTypeHandler
来达到 Java 类型和 Jdbc 类型的相互转换,也可以自己写类继承 BaseTypeHandler
来达到我们自己想要的效果,可以参考如下使用方法示例。
使用方法示例
使用typeHandler对指定字段加解密
环境: mybatis-plus
使用方法:
- 实体类:
@TableName(value = "xxx", autoResultMap = true)
- 属性
@TableField(value = "xxx", typeHandler = EncryptHandler.class)
,使用EncryptHandler
具体代码在下面
有文章说需要配置文件需要加上 mybatis-plus.type-handlers-package=com.package.handler(包名)
,这个不用。其实开启type-handlers的包扫描后,会将定义的 Java 类型作为 Key 注册成默认的类型处理器,例如List,包含 List 的实体类都会触发类型处理,也就是通用。这个时候你实体类属性上的注解写不写都会触发。
注意:使用 mabatis-plus 自带函数能用,但是自定义 sql 语句失效。 原因:自定义 sql 语句无法执行拦截器导致不能处理注解 解决方案:在mapper.xml中,如果查询语句指定了resultMap,就在resultMap中的字段上指定 typeHandler=你的handler全路径名
,如果没有自己指定resultMap,用的自动映射
创建 EncryptHandler
继承 BaseTypeHandler
package com.ibi.common.mybatisplus.handler;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.ibi.common.config.SystemConfig;
import com.ibi.common.utils.AESUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@Slf4j
public class EncryptHandler extends BaseTypeHandler<Object> {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Object parameter, JdbcType jdbcType) {
try {
if (StrUtil.isBlank((String) parameter)) {
preparedStatement.setString(i, "");
return;
}
String key = SpringUtil.getBean(SystemConfig.class).getSecretKey();
// 加密操作
String encrypt = AESUtils.encrypt((String) parameter,key);
preparedStatement.setString(i, encrypt);
} catch (Exception e) {
log.error("typeHandler加密异常:" + e);
}
}
@Override
public Object getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
String col = resultSet.getString(columnName);
try {
if (StrUtil.isBlank(col)) {
return col;
}
String key = SpringUtil.getBean(SystemConfig.class).getSecretKey();
// 对结果col进行解密操作
return AESUtils.decrypt(col,key);
} catch (Exception e) {
log.error("typeHandler解密异常:" + e);
}
return col;
}
@Override
public Object getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
String col = resultSet.getString(columnIndex);
try {
if (StrUtil.isBlank(col)) {
return col;
}
// 对结果col进行解密操作
String key = SpringUtil.getBean(SystemConfig.class).getSecretKey();
return AESUtils.encrypt( col,key);
} catch (Exception e) {
log.error("typeHandler解密异常:" + e);
}
return col;
}
@Override
public Object getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
String col = callableStatement.getString(columnIndex);
try {
if (StrUtil.isBlank(col)) {
return col;
}
String key = SpringUtil.getBean(SystemConfig.class).getSecretKey();
// 对结果col进行解密操作
return AESUtils.decrypt(col,key);
} catch (Exception e) {
log.error("typeHandler解密异常:" + e);
}
return col;
}
}
在 entry 需要加密的字段添加注解,这里需要将 tel
字段入库时加密,出库时解密。
@Data
@TableName(value = "box_customer", autoResultMap = true)
public class BoxCustomer {
/**
* 电话
*/
@TableField(typeHandler = EncryptHandler.class)
private String tel;
}
xml中使用typeHandler
示例说明: mysql 表字段类型是个 varchar,但是 java 代码对应字段是个List对象,List 对象类型肯定无法存入 mysql 中。此时需要将 List 对象转换为字符串类型,才能存入 mysql 数据库中,typeHandler就起到了这个作用。
// controller
@PostMapping("/addList")
public R<Void> addList(@RequestBody TestAddListBO bo) {
return toAjax(iBoxMyClaimService.insertListByBo(bo) ? 1 : 0);
}
// service
boolean insertListByBo(TestAddListBO bo);
// serviceImpl
@Override
public boolean insertListByBo(TestAddListBO bo) {
return baseMapper.insertListByBo(bo);
}
// mapper.java
boolean insertListByBo(@Param("bo") TestAddListBO bo);
mapper.xml
<insert id="insertListByBo">
insert into box_my_claim (
id,
create_user_name
) values ( 1, #{bo.createUserNames,typeHandler=com.ibi.ptd.message.box.handler.ListDotTypeHandler})
</insert>
TypeHandler 类方法:
package com.ibi.ptd.message.box.handler;
import cn.hutool.core.collection.CollectionUtil;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
public class ListDotTypeHandler extends BaseTypeHandler<List<String>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, CollectionUtil.join(parameter, ","));
}
@Override
public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return Arrays.asList(rs.getString(columnName).split( ","));
}
@Override
public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return Arrays.asList(rs.getString(columnIndex).split( ","));
}
@Override
public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return Arrays.asList(cs.getString(columnIndex).split( ","));
}
}
#{}
里面可以有两个参数
运行效果:
执行SQL:
入库效果:
生效原理
以插入为例
完~