【Mybatis系列】之插件—自动填充字段插件,再也不需要手动填写或者耦合业务了!

Mybatis是一个非常流行的Java ORM框架,它为开发者提供了一种简单的方式来操作关系型数据库。Mybatis插件是Mybatis的一个重要扩展功能,它允许开发者通过自定义插件来增强Mybatis的功能。在这篇文章中,我们将介绍如何使用Mybatis插件来实现自动填充字段的功能。

为什么不用mybatis-plus

相信大家在增删改查的时候都会有一个自动填充字段的需求,一翻网上的”攻略“,大部分文章都会告诉你用mybatis-plus。但是如果我们想要对mybatis有一个较深的了解,那么应该多用mybatis而不是mybatis-plus,一来因为面试的时候面试官可不会问你mybatis-plus那么几个简单的CRUD操作,二来强迫自己使用mybatis的话能够让自己学习到更多底层的原理和知识,对自己的发展是非常有益的。
那么,文归正题。

这个自定义插件主要用来做什么?

我们今天主要是要写一个mybatis插件,这个插件的任务就是能够让我们在进行insert和update操作的时候自动地对某些自定义的字段进行自定义的填充。
网上有很多的教程也是教你如何使用mybatis拦截器来实现字段的自动填充,但是,很多都是将自动填充的逻辑写死在拦截方法中,没办法做到自定义。
比如说,我有一个实体,我要在插入或者更新的时候自动填充它的createTime和updateTime。那么好,我吭哧吭哧写了一个拦截器,里面告诉mybatis说我要填充createTime和updateTime。但是第二天,主管告诉我,createId和updateId也要能够自动填充,行,再往逻辑里加。
这样一来,问题就出现了,当有新的自动填充的需求的时候,我都需要去修改代码逻辑,而且还要兼顾原有的实体类。这样到了后期,代码会非常难维护和修改。

让自填字段配置化

在经历了以上的问题后,我们肯定会想,能不能够用配置文件来定义这些自填充字段,并且不会影响到没有这些字段的实体的插入和更新?
答案是肯定的。

话不多说,先上代码

@Intercepts({
		@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MybatisInsertAutoFillPlugin implements Interceptor {
	private String[] fields;

	private String[] values;

	private String[] expressions;

	@Override
	public Object plugin(Object target) {
		return Interceptor.super.plugin(target);
	}

	@Override
	public void setProperties(Properties properties) {
		this.fields = properties.stringPropertyNames().toArray(new String[0]);
		expressions = new String[fields.length];
		values = new String[fields.length];
		for (int i = 0; i < expressions.length; i++) {
			expressions[i] = properties.getProperty(fields[i]);
			values[i] = "?";
		}
	}

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
		SqlCommandType commandType = mappedStatement.getSqlCommandType();
		if (commandType == SqlCommandType.INSERT) {
			Object p = invocation.getArgs()[1];
			SpelExpressionParser parser = new SpelExpressionParser();
			for (int i = 0; i < this.fields.length; i++) {
				ReflectUtil.setFieldValue(p, this.fields[i], parser.parseExpression(this.expressions[i]).getValue());
			}
		}
		return invocation.proceed();
	}
}

使用的时候,只需要在安装mybatis插件的时候定义我们要自填充的字段就可以了。
如下配置文件所示,我们在plugins标签中引入我们的自填充插件MybatisInsertAutoFillPlugin,然后在它下面的property中填写要填充的字段名和要填充的值。

<?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>
    <!--开启驼峰命名-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <plugins>
        <plugin interceptor="com.yahaha.cloud.core.plugin.MybatisPagePlugin">
            <property name="dialect" value="mysql"/>
        </plugin>
        <plugin interceptor="com.yahaha.cloud.core.plugin.MybatisInsertAutoFillPlugin">
            <property name="createTime" value="T(java.time.LocalDateTime).now()"/>
            <property name="updateTime" value="T(java.time.LocalDateTime).now()"/>
        </plugin>
        <plugin interceptor="com.yahaha.cloud.core.plugin.MybatisUpdateAutoFillPlugin">
            <property name="updateTime" value="T(java.time.LocalDateTime).now()"/>
        </plugin>
    </plugins>
</configuration>

代码不长,也很容易懂。

1、读取自定义填充字段

首先就是 setProperties方法,这个方法就是用来读取配置文件中plugin下的property的,我们在这个方法里将填充字段名和它们的值表达式进行了存储,分别存到了fields数组和expressions数组中,至于values,是没有用的(懒得删了)。

2、解析表达式

重点就是intercept方法了,首先我们拿到mappedStatement对象,你可以把它认为是对mapper.xml文件中定义的sql语句的描述对象。
然后通过mappedStatement获取commandType,这个commandType就是表示你这条sql语句是什么类型的,如select、update、insert、delete。接下来我们用
if (commandType == SqlCommandType.INSERT)来判断这条sql是不是插入sql。
如果是,就创建一个SpelExpressionParser对象,这个对象是用来做什么的呢?看回xml配置文件,里面我们对createTime的值的定义并不是一个固定值,而是一个表达式,因为我们需要即时地计算当前的时间,而这个SpelExpressionParser对象就是用来解析这条表达式的。
此时我们的createTime就可以获得LocalDateTime.now()的返回值了。

3、填充字段值

我们拦截的是Executor的update方法,这个方法有两个传参,第一个就是mappedStatement,就是我们要执行的当前sql的描述对象,第二个就是这条sql语句的动态参数。
我们用Object p = invocation.getArgs()[1]来获取这个动态参数对象,然后用反射的方法填充其中字段的值,ReflectUtil是我自己写的一个反射工具类,如果有需要的话,可以通过这个链接去下载。
Java反射工具类
当然,使用一些第三方的反射工具类也是可以的。
最后调用proceed方法,完成我们的拦截任务。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yahahaCoding

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

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

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

打赏作者

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

抵扣说明:

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

余额充值