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

 

posted @ 2019-09-17 18:02 梦醒点灯 阅读(...) 评论(...) 编辑 收藏