一起来学Mybatis Plus(八) & 自定义插件开发

前言

目前正在出一个Mybatis Plus系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~

之前给大家讲过Mybatis教程,而MyBatis-Plus 是一个 MyBatis 的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。大家需要注意的是它只是一个工具,大家需要掌握和重点学习的依然是Mybatis,在熟练掌握基础的情况下使用MyBatis-Plus会达到事半功倍的效果。

好了, 废话不多说直接开整吧~

自定义插件开发

之前带大家使用了它的一些内置插件,Mybatis Plus插件开发很简单,我们可以先看下之前使用的OptimisticLockerInnerInterceptor插件源码

java 复制代码
public class OptimisticLockerInnerInterceptor implements InnerInterceptor {
    ......
}

主要是通过实现InnerInterceptor接口,它的实现机制主要是通过拦截器实现的,MyBatis Plus拦截器对MyBatis的拦截器进行了一层包装,使我们处理起来更加的方便,下面一起看下它的接口

java 复制代码
public interface InnerInterceptor {
    default boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        return true;
    }

    default void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    }

    default boolean willDoUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
        return true;
    }

    default void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
    }

    default void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
    }

    default void beforeGetBoundSql(StatementHandler sh) {
    }

    default void setProperties(Properties properties) {
    }
}

可以看到对各种操作都有相应的拦截方法,下面我们就来实现一个自己的插件,以查询为例:

java 复制代码
package com.springboot.all.mybatisplus.plugin;

import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;

import java.sql.Connection;


@Slf4j
public class MybatisPlusTestPlugin extends JsqlParserSupport implements InnerInterceptor {

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = mpSh.mappedStatement();
        if (InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) {
            return;
        }
        PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
        mpBs.sql(parserMulti(mpBs.sql(), null));
    }


    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        SelectBody selectBody = select.getSelectBody();
        PlainSelect plainSelect = (PlainSelect) selectBody;
        plainSelect.setWhere(plainSelect.getWhere());

        log.info("sql ---> {}", plainSelect);
    }
}

注册插件:

java 复制代码
@Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 注册乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        // 注入分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));


        // 注入自定义插件
        interceptor.addInnerInterceptor(new MybatisPlusTestPlugin());

        return interceptor;
    }

下面测试下看看是否生效了~ 使用以下查询

java 复制代码
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.like("name", "x");
List<User> userList = userMapper.selectList(queryWrapper);
yaml 复制代码
2024-02-22 10:30:37.067  INFO 30108 --- [nio-8080-exec-1] c.s.a.m.plugin.MybatisPlusTestPlugin     : sql ---> SELECT id, name, age, version, create_at, update_at FROM sys_user WHERE (name LIKE ?)
==>  Preparing: SELECT id, name, age, version, create_at, update_at FROM sys_user WHERE (name LIKE ?)
==> Parameters: %x%(String)
<==    Columns: id, name, age, version, create_at, update_at
<==        Row: 1731552348403740673, xiaohong2, 22, 1, 2023-12-11 10:55:31, 2023-12-11 11:17:04
<==        Row: 1731552348403740674, xiaohong3, 23, 1, 2023-12-11 10:55:31, 2023-12-11 11:17:04
<==        Row: 1731552348470849537, xiaohong4, 24, 1, 2023-12-11 10:55:31, 2023-12-11 11:17:04
<==        Row: 1731552348470849538, xiaohong5, 25, 1, 2023-12-11 10:55:31, 2023-12-11 11:17:04
<==      Total: 4
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3f7e80eb]

可以看到有日志打印,说明拦截方法已经生效了。那如何在拦截器中修改sql呢?在平时业务开发中都会有这种拦截的场景,比如不同的权限返回的字段不同,查询条件也不同,通过统一拦截可以提高系统的安全性和可维护性 这里我们可以借助JsqlParserSupport提供的API来封装sql

java 复制代码
@Override
protected void processSelect(Select select, int index, String sql, Object obj) {
    // 解析SQL
    SelectBody selectBody = select.getSelectBody();
    PlainSelect plainSelect = (PlainSelect) selectBody;

    // 构建eq对象
    EqualsTo equalsTo = new EqualsTo(new Column("age"), new StringValue("22"));
    // 将原来的条件和新构建的条件合在一起
    AndExpression andExpression = new AndExpression(plainSelect.getWhere(), equalsTo);
    // 重新封装where条件
    plainSelect.setWhere(andExpression);

    log.info("sql ---> {}", plainSelect);
}

可以看到sql已经被拦截并修改了

vbnet 复制代码
2024-02-22 10:46:29.043  INFO 29524 --- [nio-8080-exec-1] c.s.a.m.plugin.MybatisPlusTestPlugin     : sql ---> SELECT id, name, age, version, create_at, update_at FROM sys_user WHERE (name LIKE ?) AND age = '22'
==>  Preparing: SELECT id, name, age, version, create_at, update_at FROM sys_user WHERE (name LIKE ?) AND age = '22'
==> Parameters: %x%(String)
<==    Columns: id, name, age, version, create_at, update_at
<==        Row: 1731552348403740673, xiaohong2, 22, 1, 2023-12-11 10:55:31, 2023-12-11 11:17:04
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@37ae5cdd]

其它增删改也是类似的处理,就不一一演示了

java 复制代码
@Override
protected void processInsert(Insert insert, int index, String sql, Object obj) {
    insert.getColumns().add(new Column("name"));
    ((ExpressionList) insert.getItemsList()).getExpressions().add(new StringValue("xiaoming"));
}

@Override
protected void processUpdate(Update update, int index, String sql, Object obj) {
    update.addUpdateSet(new Column("name"), new StringValue("xiaoming"));
}

@Override
protected void processDelete(Delete delete, int index, String sql, Object obj) {
    //... 和上面;类似
}

感兴趣的小伙伴可以看看开源的插件源码学习下别人是怎么处理的~

结束语

Mybatis Plus系列到这里就结束了~

本着把自己知道的都告诉大家,如果本文对有所帮助,点赞+关注鼓励一下呗~

MybatisPlus教程相关文章

往期Nginx教程相关文章

往期Docker教程相关文章

往前Shell脚本编程相关文章

往期Linux相关文章

往期面试题相关文章

项目源码(源码已更新 欢迎star⭐️)

往期设计模式相关文章

设计模式项目源码(源码已更新 欢迎star⭐️)

Kafka 专题学习

项目源码(源码已更新 欢迎star⭐️)

ElasticSearch 专题学习

项目源码(源码已更新 欢迎star⭐️)

往期并发编程内容推荐

推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)

博客(阅读体验较佳)

相关推荐
小汤猿人类17 分钟前
nacos-gateway动态路由
java·前端·gateway
GraduationDesign22 分钟前
基于SpringBoot的在线文档管理系统的设计与实现
java·spring boot·后端
TANGLONG22228 分钟前
【初阶数据结构与算法】八大排序之非递归系列( 快排(使用栈或队列实现)、归并排序)
java·c语言·数据结构·c++·算法·蓝桥杯·排序算法
言之。34 分钟前
【Java】面试题 并发安全 (1)
java·开发语言
m0_7482345234 分钟前
2025最新版Java面试八股文大全
java·开发语言·面试
van叶~41 分钟前
仓颉语言实战——2.名字、作用域、变量、修饰符
android·java·javascript·仓颉
张声录11 小时前
【ETCD】【实操篇(十九)】ETCD基准测试实战
java·数据库·etcd
xiaosannihaiyl241 小时前
Scala语言的函数实现
开发语言·后端·golang
鱼香鱼香rose1 小时前
面经hwl
java·服务器·数据库
新手小袁_J1 小时前
java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigur
java·开发语言·spring·spring cloud·bootstrap·maven·mybatis