拦截插入操作
场景描述:插入当前数据时,同时复制当前数据插入多行。比如平台权限的用户,可以同时给其他国家级别用户直接插入数据
实现:
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.Properties;
/**
* @author xxx
* @version 1.0
* @description 超级管理员创建基础资料,自动创建其他国家相应数据
* @create 2024/3/2/002 13:48
*/
@Slf4j
@Component
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class InsertionLinkageInterceptor implements Interceptor {
@Value("${product.country-id.tables}")
private String countryIdTables;
@Resource
private UserService userService;
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 只有超级管理员需要拦截
if (!userService.isSuperAdmin()) {
return invocation.proceed();
}
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
// 拦截插入操作
if (ms.getSqlCommandType() == SqlCommandType.INSERT) {
Object parameter = args[1];
Class<?> aClass = parameter.getClass();
TableName annotation = aClass.getAnnotation(TableName.class);
String tableName = annotation.value();
// 此处业务逻辑判断 此处做了一个表格名动态配置,可自行修改 //TODO
if (!countryIdTables.contains(tableName)) {
return invocation.proceed();
}
CountryBaseInfoDO parameterDO = (CountryBaseInfoDO) args[1];
parameterDO.setCountryId(userService.getUserCountryId());
parameterDO.setCode(IdUtils.generateCode());
Constructor<?> constructor = aClass.getConstructor();
CountryBaseInfoDO paramObject;
List<Long> countryList = userService.getUserCountryIds();
for (Long countryId : countryList) {
paramObject = (CountryBaseInfoDO) constructor.newInstance();
BeanUtils.copyProperties(parameterDO, paramObject);
paramObject.setCountryId(countryId);
Executor executor = (Executor) invocation.getTarget();
executor.update(ms, paramObject);
}
}
// 继续执行原始方法
return invocation.proceed();
}
}
有些实体可能需要自行创建
拦截更新操作
更新数据时候,可能不止更新当前表,可能需要同时更新其他行数据
拦截查询
查询数据时候,可能需要同时默认加上某个条件
实现:
@Slf4j
@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class CommonQueryInterceptor implements Interceptor {
private final static String FIELD_COUNTRY_ID = "country_id";
@Value("${product.country-id.tables}")
private String countryIdTables;
@Resource
private UserService userService;
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 超级管理员查看所有
if (!userService.isSuperAdmin()) {
return invocation.proceed();
}
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
//获取StatementHandler构造器
StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate");
BoundSql boundSql = delegate.getBoundSql();
String sql = boundSql.getSql();
Statement statement = CCJSqlParserUtil.parse(sql);
// 通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");
SqlCommandType commandType = mappedStatement.getSqlCommandType();
if (SqlCommandType.SELECT.equals(commandType)) {
Select select = (Select) statement;
PlainSelect selectBody = (PlainSelect) select.getSelectBody();
Table fromItem = (Table) selectBody.getFromItem();
String name = fromItem.getName();
// 不在配置的表中,直接返回
if (!countryIdTables.contains(name)) {
return invocation.proceed();
}
appendCondition(selectBody);
ReflectUtil.setFieldValue(boundSql, "sql", statement.toString());
// 超级管理员插入时候同步插入所有国家的数据
} else if (SqlCommandType.UPDATE.equals(commandType)) {
String extraCondition = " or id in(" + userService.getNeedUpdateIds() + ")";
sql = sql + extraCondition;
ReflectUtil.setFieldValue(boundSql, "sql", sql);
}
return invocation.proceed();
}
/**
* 追加条件
*/
private void appendCondition(PlainSelect selectBody) {
try {
// 获取where条件
String stringExpression;
try {
EqualsTo where = (EqualsTo) selectBody.getWhere();
stringExpression = where.getStringExpression();
} catch (Exception e) {
stringExpression = selectBody.getWhere().toString();
}
//如果字段搜索条件为空则搜索字段为空或指定数据
StringBuilder sqlFilter = new StringBuilder(128);
if (!stringExpression.contains(FIELD_COUNTRY_ID)) {
sqlFilter.append("(country_id in ( ").append(userService.getNeedUpdateIds()).append(")) ");
buildWhereClause(selectBody, sqlFilter.toString());
}
} catch (Exception e) {
log.error("appendCondition error", e);
//多表查询时由于不是最后一层,获取不到Table,继续获取子表
// SubSelect ss = (SubSelect) selectBody.getFromItem();
// PlainSelect subSelect = (PlainSelect) ss.getSelectBody();
// appendCondition(subSelect);
}
}
private void buildWhereClause(PlainSelect select, String dataFilter) throws JSQLParserException {
if (select.getWhere() == null) {
select.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter));
} else {
AndExpression and = new AndExpression(
CCJSqlParserUtil.parseCondExpression(dataFilter), select.getWhere());
select.setWhere(and);
}
}
}