mybatis 拦截器与spring等拦截器类似,都可以拦截请求获取参数对请求参数做验证、转换、补充等,拦截响应对响应结果做转换、补充。又与AOP切面类似,都主要应用于对公共操作的抽取。常见应用场景:数据安全加解密,公共通用数据维护(创建时间创建人、修改时间修改人等),数据权限校验,日志打印,分页,分表等。
MyBatis允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) // 拦截执行方法
- ParameterHandler (getParameterObject, setParameters) // 拦截参数处理器
- ResultSetHandler (handleResultSets, handleOutputParameters) // 拦截结果集处理器
- StatementHandler (prepare, parameterize, batch, update, query) // 拦截sql构建处理器
1.官网DEMO
// ExamplePlugin.java
@Intercepts({@Signature(
type= Executor.class, // 执行方法拦截
method = "update", // 拦截更新操作(包含 insert update delete)
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
private Properties properties = new Properties();
public Object intercept(Invocation invocation) throws Throwable {
// implement pre processing if need
Object returnObject = invocation.proceed();
// implement post processing if need
return returnObject;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
2.数据加解密
2.1加解密标记注解
@Documented
@Inherited
@Target({ ElementType.TYPE,ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptDecrypt {
}
2.2加解密实体
@EncryptDecrypt
public class UserPhoneEntity {
private Integer id;
private String name;
@EncryptDecrypt
private String phone;
}
2.3加密拦截器
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),})
@Component
@Slf4j
public class ParammeterInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
if (invocation.getTarget() instanceof ParameterHandler) {
// 获取参数
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
// 获取参数字段
Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
parameterField.setAccessible(true);
// 获取实际入参对象
Object parameterObject = parameterField.get(parameterHandler);
if (Objects.nonNull(parameterObject)) {
Class<?> parameterObjectClass = parameterObject.getClass();
// 实际入参对象是否需要加密判断
EncryptDecrypt classAnnotation = AnnotationUtils.findAnnotation(parameterObjectClass, EncryptDecrypt.class);
if (Objects.nonNull(classAnnotation)) {
Field[] declaredFields = parameterObjectClass.getDeclaredFields();
for (Field field : declaredFields) {
// 实际入参对象字段是否需要加密判断
EncryptDecrypt fieldAnnotation = field.getAnnotation(EncryptDecrypt.class);
if (Objects.nonNull(fieldAnnotation)) {
field.setAccessible(true);
Object o = field.get(parameterObject);
field.set(parameterObject, new String(Base64.getEncoder().encode(((String) o).getBytes())));
}
}
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object o) {
return Plugin.wrap(o, this);
}
@Override
public void setProperties(Properties properties) {
}
}
2.4解密拦截器
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
@Component
@Slf4j
public class ResultInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object result = invocation.proceed();
if (Objects.isNull(result)) {
return null;
}
if (result instanceof ArrayList) {
ArrayList resultList = (ArrayList) result;
resultList.stream().forEach(data -> decrypt(data));
} else {
decrypt(result);
}
return result;
}
private void decrypt(Object result) {
try {
Class<?> resultClass = result.getClass();
EncryptDecrypt encryptDecryptClass = AnnotationUtils.findAnnotation(resultClass, EncryptDecrypt.class);
if (Objects.nonNull(encryptDecryptClass)) {
Field[] declaredFields = resultClass.getDeclaredFields();
for (Field field : declaredFields) {
EncryptDecrypt fieldAnnotation = field.getAnnotation(EncryptDecrypt.class);
if (Objects.nonNull(fieldAnnotation)) {
field.setAccessible(true);
Object o = field.get(result);
field.set(result, new String(Base64.getDecoder().decode(((String) o).getBytes())));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
2.5加解密测试类
@RunWith(SpringRunner.class)
@ActiveProfiles("dev")
@SpringBootTest
@Slf4j
class UserPhoneMapperTest {
@Resource
private UserPhoneMapper userPhoneMapper;
@Test
void insertSelectiveTest() {
UserPhoneEntity entity = new UserPhoneEntity();
entity.setName("test");
entity.setPhone("test");
userPhoneMapper.insertSelective(entity);
}
@Test
void selectByPrimaryKeyTest() {
UserPhoneEntity userPhoneEntity = userPhoneMapper.selectByPrimaryKey(1);
System.out.print(JSON.toJSONString(userPhoneEntity));
}
}
@浅见 @如有疏漏请帮忙补充完善 @开发一家人 0000017 持续更新 感兴趣可以 点赞 收藏 评论 大家一起交流呀