目标
设置一个拦截器设置操作人为当前用户,如果是新增则设置更新时间和创建时间为当前时间,如果是更新则设置更新时间为当前时间
mybatis四大对象
- Executor:代表执行器,由它调度StatementHandler、ParameterHandler、ResultSetHandler等来执行对应的SQL,其中StatementHandler是最重要的。
- StatementHandler:作用是使用数据库的Statement(PreparedStatement)执行操作,它是四大对象的核心,起到承上启下的作用,如果我们要做一个分页插件需要在这里改下sql
- ParameterHandler:是用来处理SQL参数的。
- ResultSetHandler:是进行数据集(ResultSet)的封装返回处理的。
开始
insert,update,delete 最终都会走向Executor对象的 update 方法,所以我们只需要拦截它就行了。
类MybatisInterceptor
@Intercepts({@Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class})})
@Slf4j
@SuppressWarnings("rawtypes")
public class MybatisInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Date now = new Date();
// 这是公司项目中存放用户信息的ThreadLocal工具类,可以自行替换
Long userWid = Long.parseLong((String) WebContext.getInstance().get(WebContext.USER_WID));
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object object = invocation.getArgs()[1];
try {
if(object instanceof Map) {
Object record = ((Map) object).get("record");
if(record != null) {
//sql类型
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
if (SqlCommandType.INSERT.equals(sqlCommandType)) {
//插入操作时,自动插入当前时间和操作人
setValueNotExist(record, "createTime", now);
setValueNotExist(record, "updateTime", now);
setValueNotExist(record, "operatorWid", userWid);
} else {
if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
//update时,自动更新update_time 和操作人
setValueNotExist(record, "updateTime", now);
setValueNotExist(record, "operatorWid", userWid);
}
}
}
}
}catch (Exception e){
log.error("mybatisInterceptor error", e);
}
return invocation.proceed();
}
private void setValueNotExist(Object record, String fieldName, Object value){
Field field = ReflectUtil.getField(record.getClass(), fieldName);
if(field != null && ReflectUtil.getFieldValue(record,field) == null) {
ReflectUtil.setFieldValue(record, fieldName, value);
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
mybatis配置文件增加
<configuration>
------------------省略-----------------------------
<plugins>
<plugin interceptor="com.XXX.biz.interceptor.MybatisInterceptor"/>
</plugins>
</configuration>
这里做的比较简单,默认取的是第一个参数。我们项目使用的是mybatisGenerator生成的代码默认第一个参数就是实体类,如下
如果是自定的mapper文件,代码还需要加很多其他的判断,因此比较好的做法是实体类有个特殊的类名结尾比如entity或者实体类继承某个基类,这样能一下找到需要设置参数的类。