Mybatis自定义插件实现

一、插件说明

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心。
通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

Mybatis官方插件说明

二、插件实现

Mybatis提供了一个接口、四个对象来对执行语句进行拦截处理,下面以工作中常用的数据脱敏需求为例做简单说明。总的来说,分为三个步骤:实现Interceptor接口并说明定义要拦截的对象、处理拦截逻辑、添加插件。

数据脱敏就是将从数据库中查询到的敏感数据以*号或其他特殊字符进行替换,然后再返回给业务层进行使用,有效的保护了用户的隐私。

1、实现Interceptor接口并说明拦截对象

package com.zero.simple.plugins;

import com.zero.simple.annotation.Desensitize;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;

/**
 * @author zero
 * @description DesensitizePlugin
 * @date 2022/4/1 10:26
 */
@Intercepts(
        @Signature(
            type = ResultSetHandler.class, 
            method = "handleResultSets", 
            args = Statement.class))
public class DesensitizePlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 1、获取查询结果
        List<Object> records = (List<Object>) invocation.proceed();
        records.forEach(this::desensitize);
        return records;
    }

    private void desensitize(Object source) {
        // 2、获取数据的类型
        Class<?> sourceClass = source.getClass();
        // 3、包装数据
        MetaObject metaObject = SystemMetaObject.forObject(source);
        Arrays.stream(sourceClass.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(Desensitize.class))
                .forEach(field -> doDesensitize(metaObject, field));

    }

    private void doDesensitize(MetaObject metaObject, Field field) {
        // 4、获取属性名
        String name = field.getName();
        // 5、获取属性值
        Object value = metaObject.getValue(name);
        if (String.class == metaObject.getGetterType(name) && value != null) {
            Desensitize desensitize = field.getAnnotation(Desensitize.class);
            DesensitizeStrategy strategy = desensitize.strategy();
            // 6、处理属性值
            String newString = strategy.getDesensitizer().apply((String) value);
            // 7、重新给属性复制
            metaObject.setValue(name, newString);
        }
    }
}

2、业务处理

2.1定义处理策略
package com.zero.simple.plugins;

/**
 * @author zero
 * @description DesensitizeStrategy
 * @date 2022/4/1 10:34
 */
public enum DesensitizeStrategy {
    // 名称脱敏
    NAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
    ;

    private final Desensitizer desensitizer;
    DesensitizeStrategy(Desensitizer desensitizer) {
        this.desensitizer = desensitizer;
    }

    public Desensitizer getDesensitizer() {
        return desensitizer;
    }
}
2.2定义脱敏注解
package com.zero.simple.annotation;

import com.zero.simple.plugins.DesensitizeStrategy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author zero
 * @description Desensitize
 * @date 2022/4/1 10:30
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Desensitize {

    DesensitizeStrategy strategy();

}
2.3定义处理接口
package com.zero.simple.plugins;

import java.util.function.Function;

/**
 * @author zero
 * @description Desensitizer
 * @date 2022/4/1 10:33
 */
public interface Desensitizer extends Function<String, String> {
}
2.4添加注解
package com.zero.simple.model;

import com.zero.simple.annotation.Desensitize;
import com.zero.simple.plugins.DesensitizeStrategy;
import lombok.Data;

/**
 * @author zero
 * @description Country
 * @date 2022/3/21 9:15
 */
@Data
public class Country {
    private Long id;
    @Desensitize(strategy = DesensitizeStrategy.NAME)
    private String countryName;
    private String countryCode;
}

3、配置文件添加插件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <properties resource="application.properties"/>
  <settings>
    <setting name="logImpl" value="LOG4J"/>
  </settings>
  <typeAliases>
    <package name="com.zero.simple.model"/>
  </typeAliases>
  <!-- 添加脱敏插件 -->
  <plugins>
    <plugin interceptor="com.zero.simple.plugins.DesensitizePlugin"/>
  </plugins>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${db.driver}"/>
        <property name="url" value="${db.url}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="mapper/CountryMapper.xml"/>
  </mappers>
</configuration>

4、测试

image.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zerooooooooooooooooo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值