一、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、送票