package org.dromara.common.mybatis.aspect; import lombok.extern.slf4j.Slf4j; import org.dromara.common.mybatis.annotation.DataPermission; import org.springframework.aop.support.StaticMethodMatcherPointcut; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 数据权限匹配切点 * * @author 秋辞未寒 */ @Slf4j @SuppressWarnings("all") public class DataPermissionPointcut extends StaticMethodMatcherPointcut { @Override public boolean matches(Method method, Class targetClass) { // 优先匹配方法 // 数据权限注解不对继承生效,所以检查当前方法是否有注解即可,不再往上匹配父类或接口 if (method.isAnnotationPresent(DataPermission.class)) { return true; } // MyBatis 的 Mapper 就是通过 JDK 动态代理实现的,所以这里需要检查是否匹配 JDK 的动态代理 Class targetClassRef = targetClass; if (Proxy.isProxyClass(targetClassRef)) { // 数据权限注解不对继承生效,但由于 SpringIOC 容器拿到的实际上是 MyBatis 代理过后的 Mapper,而 targetClass.isAnnotationPresent 实际匹配的是 Proxy 类的注解,不会查找代理类。 // 所以这里不能用 targetClass.isAnnotationPresent,只能用 AnnotatedElementUtils.hasAnnotation 或 targetClass.getInterfaces()[0].isAnnotationPresent 去做匹配,以检查被代理的 MapperClass 是否具有注解 // 原理:JDK 动态代理本质上就是对接口进行实现然后对具体的接口实现做代理,所以直接通过接口可以拿到实际的 MapperClass targetClassRef = targetClass.getInterfaces()[0]; } return targetClassRef.isAnnotationPresent(DataPermission.class); } }