概述
顾名思义,就是一个拦截器,和springmvc的拦截器,servlet的过滤器差不多,就是在执行前拦了一道,里面可以做一些自己的事情。
平时用的mybatisPlus较多,直接以com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
为例。其内部维护了一个拦截器List,在拦截的时候for循环依次去调用这些拦截器,这时候的执行顺序就是list中的元素下标
mybatis官方介绍中可以拦截的类型共4种:
Executor
(拦截执行器的方法),method=update
包括了增删改,可以从MappedStatement
中获取实际执行的是哪种类型ParameterHandler
(拦截参数的处理)ResultSetHandler
(拦截结果集的处理)StatementHandler
(拦截Sql语法构建的处理)
平时业务中拦截较多的就是增删改查,经典的就是分页拦截器–查询拦截器。
mybatisPlus拦截器Demo
参考了mybatisPlus的com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor
写完拦截器后记得要放到mybatisPlus的拦截器集合中去。
package com.xxx.xxx.xxx;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.segments.NormalSegmentList;
import com.baomidou.mybatisplus.core.conditions.update.Update;
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
import com.baomidou.mybatisplus.core.mapper.Mapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MyInnerInterceptor implements InnerInterceptor {
/**
*
* @param executor Executor(可能是代理对象)
* @param ms MappedStatement
* @param parameter parameter
* @throws SQLException
*/
@Override
public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
SqlCommandType sqlCommandType = ms.getSqlCommandType();
String msId = ms.getId();
if(!Objects.equals(SqlCommandType.UPDATE, sqlCommandType)){
return;
}
//更新
if (parameter instanceof Map) {
Map<String, Object> map = (Map<String, Object>) parameter;
//被更新的实体类的对象在mybatis这里都是用et做别名
Object et = map.getOrDefault("et", null);
//对应mapper的class
final String className = getMapperClassName(msId);
//mapper使用的更新方法
final String methodName = getMapperMethodName(msId);
//实体类的class
Class<?> entityClass = getEntityClass(className);
//获取实体类的字段信息
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
//当前实体类的属性集合
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
// updateById(et), update(et, wrapper);
if(Objects.nonNull(et)){
try {
for (TableFieldInfo fieldInfo : fieldList) {
//field
Field field = fieldInfo.getField();
//获取column
String column = fieldInfo.getColumn();
//旧的value
Object oldValue = field.get(et);
}
} catch (IllegalAccessException e) {
throw ExceptionUtils.mpe(e);
}
// update(LambdaUpdateWrapper) or update(UpdateWrapper)
}else if (map.entrySet().stream().anyMatch(t -> Objects.equals(t.getKey(), "ew"))) {
Object ew = map.get("ew");
if (!(ew instanceof AbstractWrapper && ew instanceof Update)) {
return;
}
final Map<String, Object> paramNameValuePairs = ((AbstractWrapper<?, ?, ?>) ew).getParamNameValuePairs();
for (TableFieldInfo fieldInfo : fieldList) {
//field
Field field = fieldInfo.getField();
//获取column
String column = fieldInfo.getColumn();
Wrapper<?> wrapper = (Wrapper<?>) ew;
//查询更新条件中指定的列名对应的值
String valueKey = getValueKey(column, wrapper);
final Object conditionValue = paramNameValuePairs.get(valueKey);
}
}
}
}
/**
* 查询更新条件中指定的列名对应的值
* 即查询 where xxx = value 这个条件中的 xxx 对应的 value
* @param column
* @param wrapper
* @return
*/
private String getValueKey(String column, Wrapper<?> wrapper){
Pattern pattern = Pattern.compile("#\\{ew\\.paramNameValuePairs\\.(" + "MPGENVAL" + "\\d+)\\}");
final NormalSegmentList segments = wrapper.getExpression().getNormal();
String fieldName = null;
ISqlSegment eq = null;
String valueKey = null;
for (ISqlSegment segment : segments) {
String sqlSegment = segment.getSqlSegment();
//如果字段已找到并且当前segment为EQ
if(Objects.nonNull(fieldName) && segment == SqlKeyword.EQ){
eq = segment;
//如果EQ找到并且value已找到
}else if(Objects.nonNull(fieldName) && Objects.nonNull(eq)){
Matcher matcher = pattern.matcher(sqlSegment);
if(matcher.matches()){
valueKey = matcher.group(1);
return valueKey;
}
//处理嵌套
}else if (segment instanceof Wrapper){
if(null != (valueKey = getValueKey(column, ((Wrapper<?>) segment)))){
return valueKey;
}
//判断字段是否是要查找字段
}else if(Objects.equals(column, sqlSegment)){
fieldName = sqlSegment;
}
}
return valueKey;
}
private String getMapperMethodName(String msId){
return msId.substring(msId.lastIndexOf('.') + 1);
}
private String getMapperClassName(String msId){
return msId.substring(0, msId.lastIndexOf('.'));
}
/**
* 通过mapper上实体类信息获取实体类class
* @param className
* @return
*/
private Class<?> getEntityClass(String className){
try {
return ReflectionKit.getSuperClassGenericType(Class.forName(className), Mapper.class, 0);
} catch (ClassNotFoundException e) {
throw ExceptionUtils.mpe(e);
}
}
}
注册拦截器
@Bean
public MyInnerInterceptor myInnerInterceptor(ApplicationContext applicationContext){
MyInnerInterceptor myInnerInterceptor = new MyInnerInterceptor();
MybatisPlusInterceptor bean = applicationContext.getBean(MybatisPlusInterceptor.class);
bean.addInnerInterceptor(myInnerInterceptor);
return myInnerInterceptor;
}