java 对mybatis拦截Interceptor进行权限控制(条件修改),入参修改,返回修改之入参修改版

(点击查看上篇文章)上一篇文章中的新增修改在遇到批量新增时只能到拦截第一条sql,以及批量操作时会出现

// Parameter index out of range (X > number of parameters, which is X)

特此修改

java 复制代码
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.disclosure.common.core.domain.entity.SysDept;
import com.disclosure.common.core.domain.entity.SysRole;
import com.disclosure.common.core.domain.entity.SysUser;
import com.disclosure.common.core.domain.model.LoginUser;
import com.disclosure.common.exception.ServiceException;
import com.disclosure.common.utils.SecurityUtils;
import com.github.benmanes.caffeine.cache.Cache;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.JdbcParameter;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.statement.update.UpdateSet;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;

import java.io.StringReader;
import java.util.*;
import java.util.stream.Collectors;

import static com.disclosure.business.config.InitiateInterceptField.*;

@Slf4j
@AllArgsConstructor
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class AuthorityUserFillerInterceptor implements Interceptor {

    private final Cache<Long, SysDept> systemDeptMap;
    private final Cache<Long, Set<Long>> systemRoleDeptMap;
    @Override
    @SneakyThrows
    public Object intercept(Invocation invocation) {
        Object[] args = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) args[0];
        Object parameterObjectY = args[1];
        //限制指定路径sql
        if (!mappedStatement.getId().startsWith("com.disclosure.business")) return invocation.proceed();
        //限制SQL类型
        if (!SqlCommandType.UPDATE.equals(mappedStatement.getSqlCommandType())
                && !SqlCommandType.INSERT.equals(mappedStatement.getSqlCommandType())
        ) {
            return invocation.proceed();
        }
        BoundSql boundSql = mappedStatement.getBoundSql(parameterObjectY);
        Configuration configuration = mappedStatement.getConfiguration();
        //获取用户
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser currentUser;
        if (ObjectUtil.isNull(loginUser) || ObjectUtil.isNull(currentUser = loginUser.getUser()))
            throw new ServiceException("获取不到用户数据");

        String originalSql = boundSql.getSql();
        Statement statement = CCJSqlParserUtil.parse(new StringReader(originalSql));
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (statement instanceof Update) {
            Update update = (Update) CCJSqlParserUtil.parse(originalSql);
            ArrayList<UpdateSet> updateSets = update.getUpdateSets();
            updateData(updateSets ,configuration, parameterMappings, parameterObjectY, deptId, currentUser.getDeptId(), currentUser);
            updateData(updateSets ,configuration, parameterMappings, parameterObjectY, updateBy, String.valueOf(currentUser.getUserId()), currentUser);
            originalSql = update.toString();

        } else if (statement instanceof Insert) {
            Insert insert = (Insert) CCJSqlParserUtil.parse(originalSql);
            List<Column> columns = insert.getColumns();
            List<Expression> expressions = insert.getItemsList(ExpressionList.class).getExpressions();
            //部门权限问题
            insertData(columns, expressions, configuration, parameterMappings, parameterObjectY, deptId, currentUser.getDeptId(), currentUser);
            insertData(columns, expressions, configuration, parameterMappings, parameterObjectY, createBy, String.valueOf(currentUser.getUserId()), currentUser);
            originalSql = insert.toString();
        } else {
            return invocation.proceed();
        }
        MetaObject metaObject = SystemMetaObject.forObject(boundSql);
        metaObject.setValue("sql", originalSql);

        return invocation.proceed();
    }

    private void updateData(ArrayList<UpdateSet> updateSets, Configuration configuration, List<ParameterMapping> parameterMappings,
                            Object parameterObject, String key, Object value, SysUser currentUser) {

        MetaObject metaObject = SystemMetaObject.forObject(parameterObject);
        Object substitution = metaObject.getValue(key);
        if (substitution == null) {
            if (key.equals(deptId)) {
                return;
            }
            updateSets.add(new UpdateSet() {{
                add(new Column(StrUtil.toUnderlineCase(key)), new JdbcParameter());
            }});
            parameterMappings.add(new ParameterMapping.Builder(configuration, key, value.getClass()).build());
        } else if (deptId.equals(key)) {
            departmentalPermissions(currentUser, (Long) substitution);
            return;
        }
        metaObject.setValue(key, value);


    }

    private void insertData(List<Column> columns, List<Expression> expressions, Configuration configuration, List<ParameterMapping> parameterMappings,
                            Object parameterObject, String key, Object value, SysUser currentUser) {
		//获取元数据
        MetaObject metaObject = SystemMetaObject.forObject(parameterObject);
        Object substitution = metaObject.getValue(key);
          //判断修改字段是否存在
        if (substitution == null) {
        //添加插入字段
            columns.add(new Column(StrUtil.toUnderlineCase(key)));
            //补充?占位符
            expressions.add(new JdbcParameter());
           // 添加parameterMapping映射
            parameterMappings.add(new ParameterMapping.Builder(configuration, key, value.getClass()).build());
        } else if (deptId.equals(key)) {
            departmentalPermissions(currentUser, (Long) substitution);
            return;
        }
        //往元数据插入新值
        metaObject.setValue(key, value);


    }

//用作部门权限判断可不用
    private void departmentalPermissions(SysUser currentUser, Long deptId) {
        Long currentUserDeptId = currentUser.getDeptId();
        if (deptId.equals(currentUserDeptId)) {
            return;
        }
        SysDept sysDept = systemDeptMap.getIfPresent(deptId);
        if (sysDept == null) {
            throw new ServiceException("部门不存在");
        }
        if (Arrays.asList(sysDept.getAncestors().split(",")).contains(currentUserDeptId.toString())) {
            return;
        }
        boolean contains = currentUser.getRoles().parallelStream().map(SysRole::getRoleId).map(systemRoleDeptMap::getIfPresent)
                .filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toSet()).contains(deptId);
        if (contains) {
            return;
        }
        throw new ServiceException("权限不足,无法(插入/修改)当前部门");

    }

    /**
     * 生成拦截对象的代理
     *
     * @param target 目标对象
     * @return 代理对象
     */
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    /**
     * mybatis配置的属性
     *
     * @param properties mybatis配置的属性
     */
    @Override
    public void setProperties(Properties properties) {

    }
相关推荐
码农小河6626 分钟前
基于PHP的电商后台蜜罐系统
开发语言·php
starzy199035 分钟前
深入理解Scala柯里化函数:函数链式变换
开发语言·scala
ShineWinsu1 小时前
对于Qt:QTreeWidget常见属性以及QTreeWidgetItem类的解析
开发语言·c++·qt·gui·客户端·多叉树·qtreewidget
落羽的落羽1 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习
考虑考虑2 小时前
JDK27中的Set.ofLazy
java·后端·java ee
文丑颜不良啊2 小时前
LeetCode2841~2860题目解析
java·leetcode
小南家的青蛙2 小时前
Tomcat与Jetty深度对比
java·tomcat·jetty
总要学点什么2 小时前
第108篇:三维特效-图片轨迹线效果——把贴图滚成一串箭头,想用它的本色反而整条消失
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
乌暮3 小时前
Spring AOP 与 Spring 事务:用大白话彻底理解原理与实践
java·数据库·spring boot·后端·sql·学习·spring
YDS8293 小时前
Small Spring IOC篇:容器事件及其监听器
java·spring