背景需求
项目中使用的持久层框架Mybatis,我们使用MongoDB记录所有的更新历史记录,方便项目出问题时便于分析。将所有的数据的更新,即新增修改删除的记录,都记录在MongoDB中,可以通过RockMongo这个工具查找。
实现
自己写了一个拦截器,用于拦截Executor执行器的Update方法。通过解析参数,在目标方法即Update方法执行前后对数据进行处理,最终将数据记录到MongoDB中。
package com.sk.sams.common.mybatis.changemonitor;
import java.util.List;
import java.util.Properties;
import org.apache.ibatis.executor.Executor;
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 com.sk.sams.common.mybatis.changemonitor.domain.ChangeData;
import com.sk.sams.common.mybatis.changemonitor.listener.ChangeEventListener;
import com.sk.sams.common.mybatis.changemonitor.mybatis.MybatisInvocation;
import com.sk.sams.common.mybatis.changemonitor.parse.DataPaser;
import com.sk.sams.common.mybatis.changemonitor.parse.ParseFactory;
/**
* 拦截器,拦截Executor的Update方法,即数据库的更新操作,Insert,Update,Delete都会拦截
* @author sailing.yang
*
*/
@Intercepts(value = {
@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class ChangeMinitorInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 拦截目标
Object target = invocation.getTarget();
Object result = null;
if (target instanceof Executor) {
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameter = args[1];
String commandName = ms.getSqlCommandType().name();
ChangeEventListener changeEventListener = ChangeEventListener.getInstance();
DataPaser dataPaser = ParseFactory.getInstance().creator(commandName);
MybatisInvocation mybatisInvocation = new MybatisInvocation(args, ms, parameter, (Executor) target);
// 方法执行之前解析数据
List<ChangeData> changeTable = dataPaser.parseBefore(commandName, mybatisInvocation);
// 执行Update方法,除了查询之外的Insert,Delete,Update都是属于Update方法
result = invocation.proceed();
// 方法执行之后处理数据
changeTable = dataPaser.parseAfter(mybatisInvocation, changeTable);
if (changeTable != null) {
changeEventListener.listenModification(commandName, changeTable);
}
}
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties arg0) {
}
}
这个拦截器需要配置在mybatis的配置文件中:
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 该参数默认为false -->
<!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
<!-- 和startPage中的pageNum效果一样 -->
<property name="offsetAsPageNum" value="true" />
<!-- 该参数默认为false -->
<!-- 设置为true时,使用RowBounds分页会进行count查询 -->
<property name="rowBoundsWithCount" value="true" />
<!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->
<!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型) -->
<property name="pageSizeZero" value="true" />
<!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 -->
<!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 -->
<!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 -->
<property name="reasonable" value="false" />
<!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 -->
<!-- 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 -->
<!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值 -->
<!-- 不理解该含义的前提下,不要随便复制该配置 -->
<property name="params" value="pageNum=start;pageSize=limit;" />
</plugin>
<plugin interceptor="com.sk.sams.common.mybatis.changemonitor.ChangeMinitorInterceptor" />
</plugins>
MongoDB效果
如果想要源码,请去这里下载,需要5积分哟。