springboot2 - mybatis拦截

有不懂的地方,可以查看 pagehelper-spring-boot-starter 源码,PageHelper 就是基于 Interceptor 实现的。

业务需求

拦截 mybatis 的查询结果,对数据进行脱敏处理。

这个操作,会从根本上完成脱敏,数据刚查出来就立即脱敏。

报表系统这样做没什么问题,业务系统,一般只是希望客户端脱敏,业务上仍然使用原始数据,这样拦截 Controller 会更合适(本文不讨论这种情况)。

可以拦截的几个接口

  • Executor:拦截执行器的方法。
  • ParameterHandler:拦截参数的处理。
  • ResultHandler:拦截结果集的处理。
  • StatementHandler:拦截Sql语法构建的处理。

Interceptor

继承 Interceptor,通过 @Intercepts 注解,说明要拦截的接口、函数。

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.Properties;

/**
 * 拦截器
 *
 * @author Mr.css
 * @version 2023-06-28 15:53
 */
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
})
public class DesensitizationInterceptor implements Interceptor {

    /**
     * 数据脱敏工具类
     */
    private final ReturnValueDesensitization returnValueDesensitization = new ReturnValueDesensitization();

    /**
     * 在拦截目标对象的方法时,实际执行的增强逻辑,我们一般在该方法中实现自定义逻辑
     *
     * @param invocation -
     * @return 执行结果
     * @throws Throwable -
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object ret = invocation.proceed();
        // desensitize data
        returnValueDesensitization.process(ret);
        return ret;
    }

    /**
     * 生成代理类
     *
     * @param target 被代理的类,一般是 mybatis 默认的四大拦截
     * @return this
     */
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }


    /**
     * 可以用于读取配置文件中通过property标签配置的一些属性,设置一些属性变量
     *
     * @param properties 环境参数
     */
    @Override
    public void setProperties(Properties properties) {
        // do nothing
    }
}

注册拦截器

一种方式,是照抄PageHelper的代码,另一种,可以继承 ConfigurationCustomizer 接口。

在 ConfigurationCustomizer 接口中,可以拿到 Configuration 对象,除了拦截器,还能改动其它很多配置。

import cn.seaboot.admin.mask.ReturnValueDesensitization;
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import javax.annotation.Resource;

/**
 * mybatis 自定义配置
 *
 * @author Mr.css
 * @version 2023-06-28 14:58
 * @see MybatisAutoConfiguration
 */
@EnableConfigurationProperties({PageHelperProperties.class, SeaMybatisProperties.class})
@org.springframework.context.annotation.Configuration
public class MybatisStarter implements ConfigurationCustomizer {
    private final Logger logger = LoggerFactory.getLogger(MybatisStarter.class);

    @Resource
    private PageHelperProperties pageHelperProperties;

    @Resource
    private SeaMybatisProperties seaMybatisProperties;

    @Resource
    private ReturnValueDesensitization returnValueDesensitization;

    @Override
    public void customize(Configuration configuration) {
        logger.debug("【Mybatis】using local setting, database-id is: {}", configuration.getDatabaseId());

        {
            // using page helper
            logger.debug("【Mybatis】page-helper:{}", this.pageHelperProperties);
            Interceptor interceptor = new PageInterceptor();
            interceptor.setProperties(this.pageHelperProperties.getProperties());
            if (!containsInterceptor(configuration, interceptor)) {
                configuration.addInterceptor(interceptor);
            }
        }
        {
            if(seaMybatisProperties.isUsingDesensitize()){
                // using desensitize
                logger.debug("【Mybatis】using desensitization:{}", DesensitizationInterceptor.class);
                Interceptor interceptor = new DesensitizationInterceptor(returnValueDesensitization);
                if (!containsInterceptor(configuration, interceptor)) {
                    configuration.addInterceptor(interceptor);
                }
            }
        }
    }

    /**
     * 是否已经存在相同的拦截器
     *
     * @param configuration -
     * @param interceptor   -
     * @return -
     */
    private boolean containsInterceptor(org.apache.ibatis.session.Configuration configuration, Interceptor interceptor) {
        try {
            return configuration.getInterceptors().stream().anyMatch(config -> interceptor.getClass().isAssignableFrom(config.getClass()));
        } catch (Exception e) {
            return false;
        }
    }
}

posted on 2023-06-30 16:20  疯狂的妞妞  阅读(195)  评论(0编辑  收藏  举报

导航