Mybatis使用拦截器实现数据权限

2023-11-12

1.自定义注解

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
	
}

@Documented@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成文档时,会显示@B。如果@B没有被@Documented标注,最终生成的文档中就不会显示@B。这里的生成文档指的JavaDoc文档!

@Deprecated注解基本上所有框架自定义的注解都会添加,所谓javadoc其实就是JDK给我们提供的一个生成文档的工具!

@Target注解自JDK1.5之后就有了,其作用是定义在注解的上方,表明其注解的作用范围。

ElementType枚举值 作用范围
TYPE 接口、类、枚举
FIELD 字段、枚举的常量
METHOD 方法
PARAMETER 方法参数
CONSTRUCTOR 构造函数
LOCAL_VARIABLE 局部变量
ANNOTATION_TYPE 注解
PACKAGE

@Retention是用来修饰注解的,注解的注解,也称为元注解。@Retention修饰注解,用来表示注解的生命周期,生命周期的长短取决于@Retention的属性RetentionPolicy指定的值,例如@Retention(RetentionPolicy.RUNTIME)

取值 描述 作用范围 使用场景
RetentionPolicy.SOURCE 表示注解只保留在源文件,当java文件编译成class文件,就会消失 源文件 只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings
RetentionPolicy.CLASS 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期 class文件(默认) 要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife)
RetentionPolicy.RUNTIME 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 运行时也存在 需要在运行时去动态获取注解信息

生命周期选择:

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要 在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife) ,就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和@SuppressWarnings,则 可选用 SOURCE 注解。

2.实现拦截器

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class PermissionInterceptor implements Interceptor {

    private static final Log log = LogFactory.get(PermissionInterceptor.class);

    /**
     * 拦截sql
     *
     * @param invocation q
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();

        // 通过MetaObject优雅访问对象的属性,这里是访问statementHandler的属性;:MetaObject是Mybatis提供的一个用于方便、
        // 优雅访问对象属性的对象,通过它可以简化代码、不需要try/catch各种reflect异常,同时它支持对JavaBean、Collection、Map三种类型对象的操作。
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                new DefaultReflectorFactory());

        // 先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler,然后就到BaseStatementHandler的成员变量mappedStatement
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");

        // id为执行的mapper方法的全路径名,如com.cq.UserMapper.insertUser, 便于后续使用反射
        String id = mappedStatement.getId();

        Permission permission = null;
        // 通过类全路径获取Class对象
        Class<?> classType = Class.forName(id.substring(0, id.lastIndexOf(".")));
        // 获取当前所拦截的方法名称
        String mName = id.substring(id.lastIndexOf(".") + 1);
        // 遍历类中所有方法名称,并if匹配上当前所拦截的方法
        for (Method method : classType.getDeclaredMethods()) {
            if (mName.equals(method.getName())) {
                // 判断方法上是否带有自定义@InterceptAnnotation注解
                permission = method.getAnnotation(Permission.class);
            }
        }

        if (permission == null) {
            return invocation.proceed();
        }

        BoundSql boundSql = statementHandler.getBoundSql();
        // 获取到原始sql语句
        String sql = boundSql.getSql().toLowerCase();
        log.info("SQL:{}", sql);


        // 增强sql
        // 通过反射,拦截方法上带有自定义@InterceptAnnotation注解的方法,并增强sql
        String mSql = sqlAnnotationEnhance(permission, sql);

        //通过反射修改sql语句
        Field field = boundSql.getClass().getDeclaredField("sql");
        field.setAccessible(true);
        field.set(boundSql, mSql);
        // 打印:增强后的SQL:select * from scenario_storage limit 2
        log.info("增强后的SQL:{}", mSql);
        return invocation.proceed();
    }


    /**
     * 通过反射,拦截方法上带有自定义@InterceptAnnotation注解的方法,并增强sql
     *
     * @param permission 自定义注解
     * @param sql        所执行的sql语句
     */
    private String sqlAnnotationEnhance( Permission permission, String sql) {
        
    	//todo 增强sql

        return sql;
    }

    
    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mybatis使用拦截器实现数据权限 的相关文章

随机推荐

  • verdi显示数据

    在波形数据上点右键 2 s complement 就是大家计算机课上学的 补码 1 s complement 是课上讲的 反码 signed magnitude 最高位是符号位 0 正数 1 负数 低位是绝对值 另外 ncverilog v
  • FFmpeg命令行工具学习(五):FFmpeg 调整音视频播放速度

    转自 https www cnblogs com renhui p 10709074 html FFmpeg对音频 视频播放速度的调整的原理不一样 下面简单的说一下各自的原理及实现方式 一 调整视频速率 调整视频速率的原理为 修改视频的pt
  • QT之实现简陋聊天

    相关知识 QT 数据库 TCP IP Socket 1 登陆界面 包含登陆和注册两种功能 思路如下 难点 建立服务器和数据库 数据库保存数据 服务器与数据库产生联系 解决 数据库与服务器放在同一个类中 登陆和注册时 客户端与服务端连接 传输
  • 数据结构与算法(Java描述)-19、哈夫曼树、哈夫曼编码算法

    一 哈夫曼树的基本概念 在一棵二叉树中 定义从A结点到B结点所经过的分支序列叫做从A结点到B结点的路径 从A结点到B结点所经过的分支个数叫做从A结点到B结点的路径长度 从二叉树的根结点到二叉树中所有叶结点的路径长度之和称作该二叉树的路径长度
  • ctfshow 网络迷踪做题记录(1)

    ctfshow 网络迷踪做题记录 1 新手上路 找桥的名字 附件为一张海边图片 百度识图为蜈支洲岛 得到地点名 但还需要具体桥的名字 再用搜索引擎搜索关键字 就可以看到结果中的 情人桥 初学乍练 题目描述 提交这架飞机的目的地 附件图片为一
  • 十分钟让你搞懂会用Spring Retry

    一 项目的配置 为了启用 Spring Retry 的支持 首先要在pom xml 文件中添加以下依赖项
  • 良许Linux

    一个系统管理员可能会同时管理着多台服务器 这些服务器也许会放在不同的地方 要亲自一台一台的去访问来管理它们显然不是最好的方法 通过远程控制的方法应该是最有效的 Linux系统的远程管理工具大概有几种 telnet ssh vnc等 其中ss
  • motionface respeak新的aigc视频与音频对口型数字人

    在当今的数字化时代 人工智能 AI 正在逐渐渗透到我们生活的方方面面 其中 AI技术在视频制作和处理领域的应用也日益广泛 本文将探讨如何利用AI技术实现视频中人脸与音频同步对口型的方法 旨在进一步丰富视频制作的效果和表现形式 数字人一件对口
  • 由于无法验证发布者,Windows已经阻止此软件

    Windows系统都很注重系统的安全性 在提高安全性的同时 也给我们某些应用带来不便 比如在日常工作中经常会到某些网站上进行登录 需要安装该站点的ActiveX控件 否则无法正常加载 这时可能会弹出 由于无法验证发行者 所以WINDOWS已
  • matlab中由离散点生成云图,[转载]在matlab中由离散点生成云图

    首先 有离散点的数据如下 x 376 82 377 56 379 74 421 20 419 41 417 82 418 80 458 86 457 72 459 55 461 64 500 27 501 51 499 48 498 02
  • U盾的工作原理

    你的数字证书有一对 一份在U盾里的私钥 一份在银行的公钥 其实两份银行都有 U盾的原理很类似于双向认证的TLS SSL 或者其它用到RSA的双向证书验证手段 以下步骤可能和U盾实际执行的有所区别 但本质相同 银行先给你一个 冲击 它包含了随
  • No module named ‘cv2‘ 解决办法 (No module named ‘numpy‘ 等所有报错均可解决)

    更多视觉额自动驾驶项目请见 自动驾驶项目 实在不行可以私信我解决 0 常规解决方案 1 当出现No module named cv2 解决方案 pip install opencv python i https pypi tuna tsin
  • 等价类划分法设计测试用例

    等价类划分法 一 方法简介 1 定义 是把所有可能输入的数据 即程序的输入域划分策划国内若干部分 子集 然后从每一个子集中选取少数具有代表性的数据作为测试用例 方法是一种重要的 常用的黑盒测试用例设计方法 2 划分等价类 等价类是指某个输入
  • C++ 使用类成员函数的地址

    include
  • Linux基础笔记3

    操作系统基本认识 Linux 是什么 百度百科是这样定义 Linux Linux 全称GNU Linux 是一种免费使用和自由传播的类UNIX操作系统 其内核由林纳斯 本纳第克特 托瓦兹于1991年10月5日首次发布 它主要受到Minix和
  • 栈的实现(C语言版)

    大家好 这篇我们继续讲解数据结构里的栈 文章目录 栈的概念 栈的实现 栈的结构 栈的初始化 栈的销毁 栈是否为空 删除函数 取栈顶的数据 栈里数据的个数 插入函数 栈的概念 栈 一种特殊的线性表 其只允许在固定的一端进行插入和删除元素操作
  • js+canvas仿微信《弹一弹》小游戏

    前言 半年前用js和canvas仿了热血传奇网游 地址 基本功能写完之后 剩下的都是堆数据 堆时间才能完成的任务了 没什么新鲜感 因此进度极慢 这次看到微信 弹一弹 比较火 因为涉及到物理引擎 为了真实 于是动手试了一下 一共用了10个小时
  • 软工导论知识框架(二)结构化的需求分析

    本章节涉及很多重要图表的制作 如ER图 数据流图 状态转换图 数据字典的书写等 对初学者来说比较生僻 本贴只介绍基础的轮廓 后面会有单独的帖子详解各图表如何绘制 一 结构化的软件开发方法 结构化的分析 设计 实现 二 需求分析的重要性 1
  • QT5 出现一些问题的解决 办法

    版本 Qt Creator 5 4 0 mingw QT编写串口助手 1 extra qualification Widget on member ConvertHexChar fpermissive error extra qualifi
  • Mybatis使用拦截器实现数据权限

    1 自定义注解 Documented Target ElementType METHOD Retention RetentionPolicy RUNTIME public interface Permission Documented和 D