一文教你学会自己编写Mybatis插件(拦截器)实现自定义需求

前言

最近在考虑写什么的时,想到自己在项目中使用过的mybatis的插件,就想趁这个机会聊一聊我们接触频繁的Mybatis.

如果是使用过Mybatis的小伙伴,那么我们接触过的第一个Mybatis的插件自然就是分页插件(Mybatis-PageHelper)啦。

你有了解过它是如何实现的吗?你有没有自己编写 Mybatis 插件去实现一些自定义需求呢?

插件是一种常见的扩展方式,大多数开源框架也都支持用户通过添加自定义插件的方式来扩展或改变框架原有的功能。

Mybatis 中也提供了插件的功能,虽然叫插件,但是实际上是通过拦截器( Interceptor )实现的,通过拦截某些方法的调用,在执行目标逻辑之前插入我们自己的逻辑实现。另外在 MyBatis 的插件模块中还涉及责任链模式和 JDK 动态代理~

文章大纲:

一、应用场景

  1. 一些字段的自动填充
  2. SQL语句监控、打印、数据权限等
  3. 数据加解密操作、数据脱敏操作
  4. 分页插件
  5. 参数、结果集的类型转换

这些都是一些可以使用Mybatis插件实现的场景,当然也可以使用其他的方式来实现,只不过拦截的地方不一样罢了,有早有晚。

二、Mybatis实现自定义拦截器

我们用自定义拦截器实现一个相对简单的需求,在大多数表设计中,都会有create_time和update_time等字段,在创建或更新时需要更新相关字段。

如果是使用过MybatisPlus的小伙伴,可能知道在MybatisPlus中有一个自动填充功能,通过实现MetaObjectHandler接口中的方法来进行实现(主要的实现代码在com.baomidou.mybatisplus.core.MybatisParameterHandler中).

但使用Mybatis,并没有相关的方法或 API 可以直接来实现。所以我们这次就用以此处作为切入点,自定义拦截器来实现类似的自动填充功能。

编写步骤

  1. 编写一个拦截器类实现 Interceptor 接口
  2. 添加拦截注解 @Intercepts
  3. 在xml文件中配置拦截器或者添加到Configuration中

基础的环境我就不再贴出来啦哈,直接上三个步骤的代码

2.1、编写拦截器

 

typescript

复制代码

package com.nzc.interceptor; ​ import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; 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.springframework.beans.factory.annotation.Value; ​ import java.lang.reflect.Field; import java.util.*; ​ /** * @author 宁在春 * @version 1.0 * @description: 通过实现拦截器来实现部分字段的自动填充功能 * @date 2023/4/6 21:49 */ @Intercepts({        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) }) @Slf4j public class MybatisMetaInterceptor implements Interceptor { ​    @Override    public Object intercept(Invocation invocation) throws Throwable {        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];        String sqlId = mappedStatement.getId();        log.info("------sqlId------" + sqlId);        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();        Object parameter = invocation.getArgs()[1];        log.info("------sqlCommandType------" + sqlCommandType);        log.info("拦截查询请求 Executor#update 方法" + invocation.getMethod());        if (parameter == null) {            return invocation.proceed();       }        if (SqlCommandType.INSERT == sqlCommandType) { ​            Field[] fields = getAllFields(parameter);            for (Field field : fields) {                log.info("------field.name------" + field.getName());                try {                    // 注入创建时间                    if ("createTime".equals(field.getName())) {                        field.setAccessible(true);                        Object local_createDate = field.get(parameter);                        field.setAccessible(false);                        if (local_createDate == null || local_createDate.equals("")) {                            field.setAccessible(true);                            field.set(parameter, new Date());                            field.setAccessible(false);                       }                   }               } catch (Exception e) {               }           }       }        if (SqlCommandType.UPDATE == sqlCommandType) {            Field[] fields = getAllFields(parameter);            for (Field field : fields) {                log.info("------field.name------" + field.getName());                try {                    if ("updateTime".equals(field.getName())) {                        field.setAccessible(true);                        field.set(parameter, new Date());                        field.setAccessible(false);                   }               } catch (Exception e) {                    e.printStackTrace();               }           }       }        return invocation.proceed();   } ​    @

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值