一、Mybatis拦截器概述

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, 
  • getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 的发行包中的源代码。 假设你想做的不仅仅是监控方法的调用,那么你应该很好的了解正在重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候要特别当心。

通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定了想要拦截的方法签名即可。

二、分页功能的核心参数

1、所有的Bean都继承自BaseBean,BaseBean中包含分页对象Page。

2、Page中包含分页的核心属性:

//当前页码
private int currentPage;
//每页显示多少条
private int pageNumber;
//总条数(查询而来)
private int totalNumber;
//总页码(计算而来)
private int totalPage;

 三、分页拦截器

1、分页拦截器代码如下

@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class PageInterceptor implements Interceptor{

	public Object intercept(Invocation arg0) throws Throwable {
		StatementHandler statementHandler = (StatementHandler)arg0.getTarget();
		MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,new DefaultReflectorFactory());
		MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
		String id = mappedStatement.getId();
		if(id.endsWith("ByPage")) {
			BoundSql boundSql = statementHandler.getBoundSql();
			String sql = boundSql.getSql();
			String countSql = "select count(*) from(" + sql + ")t";
			Connection conn = (Connection)arg0.getArgs()[0];
			PreparedStatement statement = conn.prepareStatement(countSql);
			ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
			parameterHandler.setParameters(statement);
			ResultSet rs = statement.executeQuery();
			BaseBean bean = (BaseBean)boundSql.getParameterObject();
			Page page = bean.getPage();
			if(rs.next()) {
				page.setTotalNumber(rs.getInt(1));
			}
			String pageSql = sql + " limit " + (page.getCurrentPage() - 1) * page.getPageNumber() + "," + page.getPageNumber();
			metaObject.setValue("delegate.boundSql.sql", pageSql);
		}
		return arg0.proceed();
	}

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

	public void setProperties(Properties arg0) {
		
	}

}

2、实现Interceptor接口

Interceptor接口中有三个方法,这三个方法的执行顺序是这样的:

先通过setProperties(Properties arg0),获取配置文件里的属性值(可以在注册拦截器的时候,把相关参数配置进去)

再通过plugin(Object arg0),这里用到Java中的动态代理,对拦截到的对象进行过滤

最后通过intercept(Invocation arg0),执行拦截的逻辑

3、@Intercepts注解

这个注解准确的描述了,要拦截StatementHandler.class类中的prepare(Connection)方法

4、代码中用到的反射

为了获取到StatementHandler中的   MappedStatement属性    和    ParameterHandler属性

这两个属性都是protected的,因此需要通过  Java的反射机制   获取

MetaObject对象是Mybatis中封装的具有反射功能的对象,因此可以通过MetaObject来获取

四、注册分页拦截器

在Mybatis配置文件中注册分页拦截器:

<plugins>
		<plugin interceptor="org.imooc.dao.interceptor.PageInterceptor"/>
	</plugins>

五、总结

Mybatis插件用到了Java的动态代理模式,这一模式类似于代购这样的行为

1、成立代购公司

2、注册

3、申报资产

4、使用资产

5、定位客户群体

6、开始代购

  • a、过滤客户
  • b、获取购票信息
  • c、购票
  • d、送票

mybatis拦截器Executor和StatementHandler的区别_分页

mybatis拦截器Executor和StatementHandler的区别_拦截器_02

mybatis拦截器Executor和StatementHandler的区别_拦截器_03

mybatis拦截器Executor和StatementHandler的区别_拦截器_04