Mybatis插件的实现

Mybatis插件开发(一个接口四大对象)

与其说是插件,不如说是拦截器更准确,其主要步骤就是实现interceptor接口,然后实现其中的intercept方法,

这里面的Invocation参数里面的proceed方法就是具体执行SQL的方法。

拦截只要是拦截四大对象:

1、Executor:拦截的是具体的update、querry等方法

2、ParameterHandler 参数处理

3、ResultSetHandler  sql语法构建

4、StatementHandler  sql语法构建

 

开发一款脱敏插件

需求:将表中的某些敏感字段变为***,只显示最后一个字符

建立user表

package com.mybatis.mybatisplugin.plugin;

import org.springframework.stereotype.Repository;
import java.io.Serializable;
import java.util.Date;

/**
 * @author:
 * @date:2022/3/6
 */
@Repository
public class User implements Serializable {
    private static final long serialVersionUID = -40356785423868312L;

    /**
     * 主键
     */
    private Long id;
    /**
     * 用户名
     */
    @Tuomin(type = TuominType.USERNAME)
    private String userName;
    /**
     * 昵称
     */
    private String nickName;
    /**
     * 密码
     */
    private String password;
    /**
     * 账号状态(0正常 1停用)
     */
    private String status;
    /**
     * 邮箱
     */
    private String email;
    /**
     * 手机号
     */
    private String phonenumber;
    /**
     * 用户性别(0男,1女,2未知)
     */
    private String sex;
    /**
     * 头像
     */
    private String avatar;
    /**
     * 用户类型(0管理员,1普通用户)
     */
    private String userType;
    /**
     * 创建人的用户id
     */
    private Long createBy;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 更新人
     */
    private Long updateBy;
    /**
     * 更新时间
     */
    private Date updateTime;
    /**
     * 删除标志(0代表未删除,1代表已删除)
     */
    private Integer delFlag;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", nickName='" + nickName + '\'' +
                ", password='" + password + '\'' +
                ", status='" + status + '\'' +
                ", email='" + email + '\'' +
                ", phonenumber='" + phonenumber + '\'' +
                ", sex='" + sex + '\'' +
                ", avatar='" + avatar + '\'' +
                ", userType='" + userType + '\'' +
                ", createBy=" + createBy +
                ", createTime=" + createTime +
                ", updateBy=" + updateBy +
                ", updateTime=" + updateTime +
                ", delFlag=" + delFlag +
                '}';
    }
}

建立枚举类,因为脱敏的方式有很多种,这里我只有一种

package com.mybatis.mybatisplugin.plugin;

/**
 * @author:
 * @date:2022/5/26
 */


public enum TuominType{
    USERNAME(s -> s.replaceAll("\\S{2}","**"));
;
    private final Desensitizer desensitizer;
    TuominType(Desensitizer d) {
        this.desensitizer = d;
    }

    public Desensitizer getDesensitizer() {
        return desensitizer;
    }
}

 里面的Desensitizer继承了Function接口

package com.mybatis.mybatisplugin.plugin;

import java.util.function.Function;

/**
 * @author:
 * @date:2022/5/26
 */
public interface Desensitizer extends Function<String,String> {

}

 创建注解类,只能在属性上标注,被注解的属性字段就有脱敏功能

package com.mybatis.mybatisplugin.plugin;

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

/**
 * @author:
 * @date:2022/5/26
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Tuomin{
    TuominType type();
}

 创建具体的脱敏类,实现interceptor接口

package com.mybatis.mybatisplugin.plugin;

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 org.apache.ibatis.session.ResultHandler;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author:
 * @date:2022/5/25
 */
@Intercepts(@Signature(type = ResultSetHandler.class,method = "handleResultSets",args = Statement.class))
@Component
public class TuominPlugin implements Interceptor {
    @Override
    public Object intercept(final Invocation invocation) throws Throwable {
        List<Object> proceed = (List<Object>) invocation.proceed();
        proceed.forEach(this::tuomin);
        return proceed;
    }

    private void tuomin(final Object source) {
        Class<?> sourceClass = source.getClass();
        MetaObject metaObject = SystemMetaObject.forObject(source);
        Stream.of(sourceClass.getDeclaredFields())
                .filter(filed->filed.isAnnotationPresent(Tuomin.class))
                .forEach(field -> doTuomin(metaObject,field));
    }

    private void doTuomin(final MetaObject metaObject, final Field field) {
        String name = field.getName();
        Object value = metaObject.getValue(name);
        if(String.class == metaObject.getGetterType(name) && value !=null)
        {
            //拿到脱敏注解本身
            Tuomin annotation = field.getAnnotation(Tuomin.class);
            TuominType type = annotation.type();
            Object o = type.getDesensitizer().apply((String) value);
            System.out.println(o);
            metaObject.setValue(name,o);
        }


    }
}

测试效果:

posted @ 2022-05-26 17:11  莫得感情的肝帝  阅读(47)  评论(0编辑  收藏  举报