MyBatis Interceptor拦截器高级用法

文章描述了一种SpringBoot插件,用于拦截MyBatis的插入操作,当超级管理员执行插入时,会自动将数据复制到其他关联的国家级别用户账户中。同时,还介绍了如何拦截查询操作,添加国家ID条件。
摘要由CSDN通过智能技术生成

拦截插入操作

场景描述:插入当前数据时,同时复制当前数据插入多行。比如平台权限的用户,可以同时给其他国家级别用户直接插入数据

  实现:

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);
        }
    }

}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhouhaitao_cherry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值