首页 > 其他分享 >mybatis拦截器 + 自定义注解 + 获取注解的属性

mybatis拦截器 + 自定义注解 + 获取注解的属性

时间:2022-12-23 18:12:02浏览次数:39  
标签:拦截器 自定义 import SM4MACFieldAnnotation ibatis org apache 注解

背景

mybatis拦截器 + 自定义注解——这种方式可以为我们解决很多事情,带来很多便利,但有时候会在自定义注解上配置一些属性,并且拦截器上要拿到这些属性的值。
这个时候,我们要怎样获取到这些值呢:

代码示例

  • SM4MACFieldAnnotation 定义一个注解,用于字段进行数据防篡改的校验。然后要指定一些字段进行加密。
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface SM4MACFieldAnnotation {

    /**
     * 加密字段对应的字段
     */
    String[] fieldKey() default {};
}
  • 定义拦截器 SM4MACInterceptor
    这个类上也还说明了,怎样获取mapper类的方法上的注解。
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.util.Properties;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@Intercepts({
        @Signature(type = ParameterHandler.class,
                method = "setParameters",
                args = PreparedStatement.class),
})
public class SM4MACInterceptor implements Interceptor {

    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();

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

        // 重点!!! 获取Mapper方法上的注解
        ParameterHandler resultSetHandler = (ParameterHandler) invocation.getTarget();
        MetaObject metaResultSetHandler = MetaObject.forObject(resultSetHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, REFLECTOR_FACTORY);
        MappedStatement mappedStatement = (MappedStatement) metaResultSetHandler.getValue("mappedStatement");
        SM4MACFieldAnnotation annotation = getSM4MACFieldAnnotation(mappedStatement);
        // 注解上配置的加密字段,拿到 !
        String[] fields = annotation.fieldKey();
        // 省略根据 fields 后做的加密,然后再做对象参数的反射......

        // 执行
        Object result = invocation.proceed();

        // 返回结果
        return result;
    }

    /**
     * 获取方法上的SM4MACFieldAnnotation注解
     *
     * @param mappedStatement MappedStatement
     * @return EncryptResultFieldAnnotation注解
     */
    private SM4MACFieldAnnotation getSM4MACFieldAnnotation(MappedStatement mappedStatement) {
        SM4MACFieldAnnotation annotation = null;
        try {
            String id = mappedStatement.getId();
            String className = id.substring(0, id.lastIndexOf("."));
            String methodName = id.substring(id.lastIndexOf(".") + 1);
            final Method[] method = Class.forName(className).getMethods();
            for (Method me : method) {
                if (me.getName().equals(methodName) && me.isAnnotationPresent(SM4MACFieldAnnotation.class)) {
                    return me.getAnnotation(SM4MACFieldAnnotation.class);
                }
            }
        } catch (Exception ex) {
            log.error("", ex);
        }
        return annotation;
    }

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

    @Override
    public void setProperties(Properties properties) {

    }
}

最后看一下,在mapper 方法上,添加注解的方法
要根据 bizId, name 这两个字段,进行加密,并做防篡改操作。
因为并不是每个方法都需要进行篡改操作,防篡改的字段也各不一样,所以必须要使用注解

@Mapper
public interface SM4MACProcessedMapper {

    @SM4MACFieldAnnotation(fieldKey = {"bizId", "name"})
    int insertSelective(ProcessedPo processedPo);

}

总结

以上,记录一下,在mapper 上怎样获利注解。
因为 mapper 接口上的注解和 通过 AOP获取注解的做法完全不一样。在AOP上拿到注解太简单了,但 mapper想拿到注解真的耗了不小的力气。


并且,还有一个点,要注意一下~!!!

mybatis 拦截的 @Signature 它的参数,
@Intercepts({
@Signature(type = ParameterHandler.class,
method = "setParameters",
args = PreparedStatement.class),
})

这里的 type 有对应的不同的类型,获取注解也不尽相同,比如这里是希望对参数进行操作,所以这里的type 是定义为了 ParameterHandler, 方法是 setParameters,
然后获取注解的时候,
ParameterHandler resultSetHandler = (ParameterHandler) invocation.getTarget(); 这个 getTarget 是和 type 对应的。

如果是对请求的结果进行操作,比如解密什么的,那这个签名,和这个 invocation.getTarget(); 也是不一样的,要注意些。

如果是要对返回的结果进行操作:
拦截器的注解是这样子写的:

@Intercepts({
        @Signature(
                type = ResultSetHandler.class,
                method = "handleResultSets",
                args = {Statement.class}
        )
})

// 方法要这样写: 
// 获取到返回结果
        ResultSetHandler resultSetHandler = (ResultSetHandler) invocation.getTarget();
        MetaObject metaResultSetHandler = MetaObject.forObject(resultSetHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, REFLECTOR_FACTORY);
        MappedStatement mappedStatement = (MappedStatement) metaResultSetHandler.getValue("mappedStatement");
        ......

知道这个就行,不同阶段,要使用不同的 Handler..... emmmm.....

标签:拦截器,自定义,import,SM4MACFieldAnnotation,ibatis,org,apache,注解
From: https://www.cnblogs.com/aaacarrot/p/17001276.html

相关文章

  • 【数据结构】五分钟带你了解及自定义有向图
    前言什么是有向图在数学中,一个图(Graph)是表示物件与物件之间的关系的方法,是图论的基本研究对象。一个图看起来是由一些小圆点(称为顶点或结点)和连结这些圆点的直线或曲线(......
  • WPF自定义界面WindowChrome
    默认WPF的界面其实也还行,就是满足不了日渐增长的需求,界面还是需要有更高的自定义程度,包括标题栏也要能够塞下更多的操作控件。默认窗口介绍#新建WPF项目,给里面内容设置......
  • Bash自定义函数numbeep:Cygwin、Mintty窗口重复响铃并闪烁以提示新信息
    概述:有时候会碰到这样的场景,在Cygwin或MSYS2环境下工作,执行一个耗时较长的任务(eg:gcc编译、rsync同步等等...),我们不想长时间保持窗口激活状态在前台苦等任务运行结束,窗口切......
  • SpringBoot2.x系列教程25--整合SpringMVC之欢迎页面与自定义Favicon
    SpringBoot2.x系列教程25--整合SpringMVC之欢迎页面与自定义Favicon作者:一一哥一.SpringBoot设置欢迎页面1.默认欢迎页的源码在SpringBoot中,默认的欢迎界面是index.html,那......
  • SpringBoot2.x系列教程10--小花样之SpringBoot配置自定义Banner
    SpringBoot系列教程10--小花样之SpringBoot配置自定义Banner作者:一一哥一.SpringBoot常用配置本章节主要介绍一下SpringBoot中的一些常用配置,比如:自定义Banner、配......
  • @JsonInclude @JsonFormat 注解
    1.使用@JsonInclude(JsonInclude.Include.NON_NULL)注解可以返回制定格式的json数据:如果属性返回值为空,则不返回任何内容,这是由于@JsonInclude(JsonInclude.Include.N......
  • FastDFS客户端与自定义文件存储系统
    本文的前提是已经启动FastDFS的tracker和storage安装安装提供给大家的fdfs_client-py-master.zip到虚拟环境中 pipinstallfdfs_client-py-master.zip 链接:ht......
  • 自定义python Django文件存储系统
    在学习Django框架的时候,我们已经讲过,Django自带文件存储系统,但是默认文件存储在本地,在本项目中,我们需要将文件保存到FastDFS服务器上,所以需要自定义文件存储系统。自定义......
  • 基于注解的 IOC 配置
    使用步骤1、导入依赖<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</ve......
  • Vue 自定义事件
    组件的自定义事件使用场景A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)绑定自定义事件在父组件中:<HelloWorld@customEv......