> 文章列表 > mybatisPlus拦截器使用demo

mybatisPlus拦截器使用demo

mybatisPlus拦截器使用demo

概述

顾名思义,就是一个拦截器,和springmvc的拦截器,servlet的过滤器差不多,就是在执行前拦了一道,里面可以做一些自己的事情。

平时用的mybatisPlus较多,直接以com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
为例。其内部维护了一个拦截器List,在拦截的时候for循环依次去调用这些拦截器,这时候的执行顺序就是list中的元素下标

mybatisPlus拦截器使用demo

mybatis官方介绍中可以拦截的类型共4种:

  1. Executor(拦截执行器的方法),method=update包括了增删改,可以从MappedStatement中获取实际执行的是哪种类型
  2. ParameterHandler(拦截参数的处理)
  3. ResultSetHandler(拦截结果集的处理)
  4. 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*/@Overridepublic 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的classfinal String className = getMapperClassName(msId);//mapper使用的更新方法final String methodName = getMapperMethodName(msId);//实体类的classClass<?> 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) {//fieldField field = fieldInfo.getField();//获取columnString column = fieldInfo.getColumn();//旧的valueObject 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) {//fieldField field = fieldInfo.getField();//获取columnString 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为EQif(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;
}