mybatis拦截器实现通用权限字段添加的方法

实现效果

日常sql中直接使用权限字段实现权限内数据筛选,无需入参,直接使用,使用形式为:

select * from crh_snp.channelinfo where short_code in (${commonEnBranchNo})

注意事项说明

1、添加插件若使用xml形式mybatis可在配置文件中plugins标签中添加,本项目实际使用的为注解形式mybatis,需要通过SqlSessionFactoryBean代码方式添加或者SqlSessionFactoryBean的xml配置形式,代码在jar包中无法操作,只能使用xml配置形式,故需要覆盖SqlSessionFactoryBean配置

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="mapperLocations">
   <list>
     <value>classpath*:xmlmapper/*.xml</value>
     <value>classpath*:resources/xmlmapper/*.xml</value>
   </list>
  </property>
  <property name="plugins">
   <array>
     <bean class="com.cairh.xpe.snp.backend.interceptor.MybatisInterceptor"/>
   </array>
  </property>
</bean>

2、jdbc的jar包中配置了sqlSessionFactory,本项目中配置进行覆盖,注意spring中同名类后加载的会覆盖先加载的类,需要保证本项目配置的类后加载。spring配置文件扫描会先加载本工程项目bean,可通过新增额外的配置文件放在原配置文件后实现后加载,如

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   classpath*:spring-beans.xml
   classpath*:spring-person.xml
  </param-value>
</context-param>

3、注意添加的参数需要${}形式使用,#{}会经过预编译获取到的sql参数为问号,无法直接替换

拦截器实现类

@Intercepts({
  @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class MybatisInterceptor implements Interceptor {

//  private Logger logger = LoggerFactory.getLogger(getClass());

  @Override
  public Object intercept(Invocation invocation) throws Throwable {

    if (invocation.getTarget() instanceof Executor && invocation.getArgs().length==4) {
      String sql = getSqlByInvocation(invocation);
      //将操作员可操作的渠道、用户id及营业部作通用字段放到sql中统一解析
      if(sql.contains("commonEnShortCode")){
        sql = addPremissionParam(sql);
        resetSql2Invocation(invocation, sql);
      }
    }

    return invocation.proceed();
  }

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

  @Override
  public void setProperties(Properties properties) {}

  /**
   * 通用权限字段添加,目前支持:commonEnShortCode、commonEnBrokerUserId、commonEnBranchNo
   * @param sql
   * @return
   */
  private String addPremissionParam(String sql) {
    CrhUser crhUser = (CrhUser) RequestUtil.getRequest().getAttribute(CrhUser.CRH_USER_SESSION);
    BackendRoleServiceImpl backendRoleService = (BackendRoleServiceImpl)SpringContext.getBean("backendRoleServiceImpl");
    if(sql.contains("commonEnBranchNo")){
      List<String> enBranchNoList = backendRoleService.getEnBranchNo(crhUser.getUser_id());
      String enBranchNoSql = "select to_char(column_value) from TABLE(SELECT F_TO_T_IN('"+ StringUtils.join(enBranchNoList,",")+"') FROM DUAL)";
      sql = sql.replace("${commonEnBranchNo}", enBranchNoSql);
    }
    return sql;
  }

  /**
   * 获取当前sql
   * @param invocation
   * @return
   */
  private String getSqlByInvocation(Invocation invocation) {
    final Object[] args = invocation.getArgs();
    MappedStatement ms = (MappedStatement) args[0];
    Object parameterObject = args[1];
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    return boundSql.getSql();
  }

  /**
   * 将sql重新设置到invocation中
   * @param invocation
   * @param sql
   * @throws SQLException
   */
  private void resetSql2Invocation(Invocation invocation, String sql) throws SQLException {
    final Object[] args = invocation.getArgs();
    MappedStatement statement = (MappedStatement) args[0];
    Object parameterObject = args[1];
    BoundSql boundSql = statement.getBoundSql(parameterObject);
    MappedStatement newStatement = newMappedStatement(statement, new BoundSqlSource(boundSql));
    MetaObject msObject = MetaObject.forObject(newStatement, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),new DefaultReflectorFactory());
    msObject.setValue("sqlSource.boundSql.sql", sql);
    args[0] = newStatement;
  }

  private MappedStatement newMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
    MappedStatement.Builder builder =
        new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
    builder.resource(ms.getResource());
    builder.fetchSize(ms.getFetchSize());
    builder.statementType(ms.getStatementType());
    builder.keyGenerator(ms.getKeyGenerator());
    if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
      StringBuilder keyProperties = new StringBuilder();
      for (String keyProperty : ms.getKeyProperties()) {
        keyProperties.append(keyProperty).append(",");
      }
      keyProperties.delete(keyProperties.length() - 1, keyProperties.length());
      builder.keyProperty(keyProperties.toString());
    }
    builder.timeout(ms.getTimeout());
    builder.parameterMap(ms.getParameterMap());
    builder.resultMaps(ms.getResultMaps());
    builder.resultSetType(ms.getResultSetType());
    builder.cache(ms.getCache());
    builder.flushCacheRequired(ms.isFlushCacheRequired());
    builder.useCache(ms.isUseCache());

    return builder.build();
  }
}
public class BoundSqlSource implements SqlSource {

  private BoundSql boundSql;

  public BoundSqlSource(BoundSql boundSql) {
    this.boundSql = boundSql;
  }

  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    return boundSql;
  }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • MyBatis Excutor 拦截器的巧妙用法

    这里要讲的巧妙用法是用来实现在拦截器中执行额外 MyBatis 现有方法的用法. 并且会提供一个解决拦截Executor时想要修改MappedStatement时解决并发的问题. 这里假设一个场景: 实现一个拦截器,记录 MyBatis 所有的 insert,update,delete 操作,将记录的信息存入数据库. 这个用法在这里就是将记录的信息存入数据库. 实现过程的关键步骤和代码: 1.首先在某个 Mapper.xml 中定义好了一个往日志表中插入记录的方法,假设方法为id="insert

  • Mybatis拦截器实现分页

    最终dao层结果: public interface ModelMapper { Page<Model> pageByConditions(RowBounds rowBounds, Model record); } 接下来一步一步来实现分页. 一.创建Page对象: public class Page<T> extends PageList<T> { private int pageNo = 1;// 页码,默认是第一页 private int pageSize = 1

  • MyBatis拦截器:给参数对象属性赋值的实例

    该拦截器的作用:在进行增加.修改等操作时,给数据模型的一些通用操作属性(如:创建人.创建时间.修改人.修改时间等)自动赋值. 该实现是在DAO层拦截,即存入DB前最后一层.后经分析,不是很合理,改为在service层拦截,用spring AOP来实现了,该代码遂弃用.不过已经测试可用,记录备忘. package com.development; import java.lang.reflect.InvocationTargetException; import java.util.Date; i

  • MyBatis拦截器原理探究

    MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用.默认情况下,MyBatis 允许使用插件来拦截的方法调用包括: Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) P

  • MyBatis拦截器实现分页功能实例

    由于业务关系 巴拉巴拉巴拉 好吧 简单来说就是 原来的业务是 需要再实现类里写 selectCount 和selectPage两个方法才能实现分页功能 现在想要达到效果是 只通过一个方法就可以实现 也就是功能合并 所以就有了下面的实践 既然是基于MyBatis 所以就先搭建一个Mybatis的小项目 1.01导入 mybatis和mysql的包 1.02.配置文件 Configuration.xml 中添加 <environments default="development"&

  • Mybatis拦截器的实现介绍

     MyBatis介绍 MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis .它支持普通 SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的

  • MyBatis拦截器实现分页功能的实现方法

    MyBatis拦截器实现分页功能的实现方法 前言: 首先说下实现原理.使用拦截器拦截原始的sql,然后加上分页查询的关键字和属性,拼装成新的sql语句再交给mybatis去执行. 除了业务代码之外,需要写的东西不多,提几个关键的: 1.分页对象Page类.给该对象设置一个当前页数(前端给).总记录数(拦截器内赋值)2个参数,他就能帮你计算出分页sql语句用的2个参数. /** * 分页对应的实体类 */ public class Page { /** * 总条数 */ private int t

  • mybatis拦截器实现通用权限字段添加的方法

    实现效果 日常sql中直接使用权限字段实现权限内数据筛选,无需入参,直接使用,使用形式为: select * from crh_snp.channelinfo where short_code in (${commonEnBranchNo}) 注意事项说明 1.添加插件若使用xml形式mybatis可在配置文件中plugins标签中添加,本项目实际使用的为注解形式mybatis,需要通过SqlSessionFactoryBean代码方式添加或者SqlSessionFactoryBean的xml配

  • Mybatis拦截器实现数据权限的示例代码

    在我们日常开发过程中,通常会涉及到数据权限问题,下面以我们常见的一种场景举例: 一个公司有很多部门,每个人所处的部门和角色也不同,所以数据权限也可能不同,比如超级管理员可以查看某张 表的素有信息,部门领导可以查看该部门下的相关信息,部门普通人员只可以查看个人相关信息,而且由于角色的 不同,各个角色所能查看到的数据库字段也可能不相同,那么此处就涉及到了数据权限相关的问题.那么我们该如 何处理数据权限相关的问题呢?我们提供一种通过Mybatis拦截器实现的方式,下面我们来具体实现一下 pom.xml

  • MyBatis拦截器的实现原理

    目录 前言 1.使用方法 2.MyBatis对象的创建 3.代理对象的创建 3.1 拦截器的获取 3.2 代理对象的创建 4. 拦截器的执行过程 5. 拦截器的执行顺序 前言 Mybatis拦截器并不是每个对象里面的方法都可以被拦截的.Mybatis拦截器只能拦截Executor.StatementHandler.ParameterHandler.ResultSetHandler四个类里面的方法,这四个对象在创建的时候才会创建代理. 用途:实际工作中,可以使用Mybatis拦截器来做一些SQL权

  • mybatis拦截器无法注入spring bean的问题解决

    公司要整合rabbitmq与mybatis拦截器做一个数据同步功能. 整合过程中大部分环节都没什么问题,就是遇到了mybatis拦截器 @Intercepts(@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})) @Component public class MyBatisInterceptor implements Interceptor

  • 使用mybatis拦截器处理敏感字段

    目录 mybatis拦截器处理敏感字段 前言 思路解析 代码 趟过的坑(敲黑板重点) mybatis Excutor 拦截器的使用 这里假设一个场景 实现过程的关键步骤和代码 重点 mybatis拦截器处理敏感字段 前言 由于公司业务要求,需要在不影响已有业务上对 数据库中已有数据的敏感字段加密解密,个人解决方案利用mybatis的拦截器加密解密敏感字段 思路解析 利用注解标明需要加密解密的entity类对象以及其中的数据 mybatis拦截Executor.class对象中的query,upd

  • MyBatis拦截器的原理与使用

    目录 二.拦截器注册的三种方式 1.XML注册 2.配置类注册 3.注解方式 三.ParameterHandler参数改写-修改时间和修改人统一插入 四.通过StatementHandler改写SQL 一.拦截对象和接口实现示例 MyBatis拦截器的作用是在于Dao到DB中间进行额外的处理.大部分情况下通过mybatis的xml配置sql都可以达到想要的DB操作效果,然而存在一些类似或者相同的查询条件或者查询要求,这些可以通过拦截器的实现可以提升开发效率,比如:分页.插入和更新时间/人.数据权

  • MyBatis-Plus拦截器实现数据权限控制的示例

    目录 前言背景 上代码(基础版) 进阶版 前言背景 平时开发中遇到根据当前用户的角色,只能查看数据权限范围的数据需求.列表实现方案有两种,一是在开发初期就做好判断赛选,但如果这个需求是中途加的,或不希望每个接口都加一遍,就可以方案二加拦截器的方式.在mybatis执行sql前修改语句,限定where范围. 当然拦截器生效后是全局性的,如何保证只对需要的接口进行拦截和转化,就可以应用注解进行识别 因此具体需要哪些步骤就明确了 创建注解类 创建拦截器实现InnerInterceptor接口,重写查询

  • 简单了解mybatis拦截器实现原理及实例

    这篇文章主要介绍了简单了解mybatis拦截器实现原理及实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 例行惯例,先看些基本概念: 1 拦截器的作用就是我们可以拦截某些方法的调用,在目标方法前后加上我们自己逻辑 2 Mybatis拦截器设计的一个初衷是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑. 自定义拦截器 /** * mybatis 自定义拦截器 * 三步骤: * 1 实现 {@link Intercept

随机推荐