拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。mybatis拦截器一般用于分页插件、输出日志、sql等。使用的方法如下:

首先要实现mybatis的Interceptor接口,

实现它的三个方法:


Object intercept(Invocation invocation) throws Throwable;

Object plugin(Object target);

void setProperties(Properties properties);


plugin方法是拦截器用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理。当返回的是代理的时候我们可以对其中的方法进行拦截来调用intercept方法,当然也可以调用其他方法,这点将在后文讲解。

setProperties方法是用于在Mybatis配置文件中指定一些属性的。

plugin方法中我们可以决定是否要进行拦截进而决定要返回一个什么样的目标对象。而intercept方法就是要进行拦截的时候要执行的方法。

下面例子本来相用于记录日志到数据库,但是由于mybatis底层无法注入spring的对象,所以,只能用于输出日志。

@Intercepts({@Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class})})
public class LogInterceptor implements Interceptor {
    /**
     * 注解拦截接口的方法
     * Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
     * ParameterHandler (getParameterObject, setParameters)
     * ResultSetHandler (handleResultSets, handleOutputParameters)
     * StatementHandler (prepare, parameterize, batch, update, query)
     */

    private static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class);

    private Properties properties;

    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        // 获取执行的方法
        if (args.length > 1) {
            // 传入的对象
            Object obj = args[1];
            if (obj instanceof Log) {
                // 若是日志对象 则直接跳过
                return invocation.proceed();
            }
            saveLog(args[0], obj);
        }
        return invocation.proceed();
    }

    private void saveLog(Object arg, Object obj) {
        Log log = new Log();
        log.setCreateTime(DateUtils.now());
        log.setModifyTime(DateUtils.now());
        MappedStatement mappedStatement = (MappedStatement) arg;
        // 执行的方法名
        String name = mappedStatement.getSqlCommandType().name();
        String change = JsonMapper.toJson(obj);
        if (name.startsWith("INSERT")) {
            log.setType("新增" + obj.getClass().getSimpleName());
            log.setNewContent(change);
        } else if (name.startsWith("UPDATE")) {
            log.setType("修改" + obj.getClass().getSimpleName());
            log.setNewContent(change);
        } else if (name.startsWith("DELETE")) {
            log.setType("删除" + obj.getClass().getSimpleName());
            log.setOldContent(change);
        }

        LOGGER.info("----------------------------------------------");
        LOGGER.info(JsonMapper.toJson(log));
        LOGGER.info("----------------------------------------------");
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

}


类上面必须添加@Intercepts注解, @Signature,代表拦截点,

@Intercepts({@Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class})})


method表示需要拦截的方法,mybatis有

update, query, flushStatements, commit, rollback, getTransaction, close, isClosed

方法,其中,update包括新增、修改、删除等方法,query用于查询,其它的基本用不到。

type表示拦截的接口类型,有Executor、StatementHandler、ParameterHandler和ResultSetHandler。

args表示拦截的参数类型,有MappedStatement、Object、RowBounds和ResultHandler等等.


        编写完拦截器,需要在配置文件中注册拦截器,在sqlMapConfig配置文件中加上

<?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="cacheEnabled" value="true"/>
      <setting name="lazyLoadingEnabled" value="true"/>
      <setting name="multipleResultSetsEnabled" value="true"/>
      <setting name="useColumnLabel" value="true"/>
      <setting name="useGeneratedKeys" value="false"/>
    </settings>
    
    <plugins>
        <plugin interceptor="com.tc.itfarm.commons.interceptor.LogInterceptor"></plugin>
    </plugins>
</configuration>

启动项目测试即可,输出的日志如下:

2016-08-28 14:48:02  [ http-apr-8888-exec-8:70630 ] - [ INFO ]  ----------------------------------------------
 2016-08-28 14:48:02  [ http-apr-8888-exec-8:70634 ] - [ INFO ]  {"recordId":null,"type":"修改User","oldContent":null,"newContent":"{\"recordId\":1,\"username\":\"wdd\",\"telephone\":\"18888888888\",\"sex\":2,\"password\":null,\"age\":22,\"status\":1,\"address\":\"安徽灵璧1\",\"photo\":null,\"email\":\"asdds\",\"qq\":\"812908087\",\"nickname\":\"爱吃猫的鱼1\",\"registerTime\":null,\"modifyTime\":1472366881824}","userId":null,"username":null,"createTime":1472366881824,"modifyTime":1472366881824}
 2016-08-28 14:48:02  [ http-apr-8888-exec-8:70634 ] - [ INFO ]  ----------------------------------------------

若要插入到数据库,必须new一个dao对象操作