首先 要知道,所有的拦截器都是需要配置的,这里拦截器是在执行 mapper 的方法的时候,执行的。 <bean name="paginationInterceptor" class="com.common.mvc.mybatis.PageMybatisInterceptor"></bean> <!--Session Factory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations"> <list> <value>classpath:mapper/*/*.xml</value> <value>classpath:mybatis/mapping/*.xml</value> </list> </property> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageHelper"> <property name="properties"> <value> dialect=mysql pageSizeZero=true reasonable=true </value> </property> </bean> <ref bean="paginationInterceptor" /> </array> </property> </bean> 通过这个配置,在服务器启动的时候,会生成一个映射(key=mapper 的方法名,value=拦截器列表) 这样 ,在某个服务内,调用mapper方法的时候,都会调用 拦截器的intercept()方法。 我们的拦截器: public class PageMybatisInterceptor implements Interceptor { private static final Logger logger = LoggerFactory.getLogger(PageMybatisInterceptor.class); public static final ThreadLocal<Page> localPage = new ThreadLocal<Page>(); /** * 开始分页 * @param pageNum * @param pageSize */ public static void startPage(Integer pageNum, Integer pageSize) { if(pageNum==null) pageNum = Page.DEFAULT_PAGE_NUM; if(pageSize==null) pageSize = Page.DEFAULT_PAGE_SIZE; localPage.set(new Page(pageNum, pageSize)); } /** * 结束分页并返回结果,该方法必须被调用,否则localPage会一直保存下去,直到下一次startPage * @return */ public static Page endPage() { Page page = localPage.get(); localPage.remove(); return page; } @Override public Object intercept(Invocation invocation) throws Throwable { if (localPage.get() == null) { return invocation.proceed(); } if (invocation.getTarget() instanceof StatementHandler) { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环 // 可以分离出最原始的的目标类) while (metaStatementHandler.hasGetter("h")) { Object object = metaStatementHandler.getValue("h"); metaStatementHandler = SystemMetaObject.forObject(object); } // 分离最后一个代理对象的目标类 while (metaStatementHandler.hasGetter("target")) { Object object = metaStatementHandler.getValue("target"); metaStatementHandler = SystemMetaObject.forObject(object); } MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); //分页信息if (localPage.get() != null) { Page page = localPage.get(); BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); // 分页参数作为参数对象parameterObject的一个属性 String sql = boundSql.getSql(); // 重写sql String pageSql = buildPageSql(sql, page); //重写分页sql metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); Connection connection = (Connection) invocation.getArgs()[0]; // 重设分页参数里的总页数等 setPageParameter(sql, connection, mappedStatement, boundSql, page); // 将执行权交给下一个拦截器 return invocation.proceed(); } else if (invocation.getTarget() instanceof ResultSetHandler) { Object result = invocation.proceed(); Page page = localPage.get(); page.setResult((List) result); return result; } return null; } 可以 想一下, 如果在调用mapper 之前调用 PageMybatisInterceptor.startPage(pageNum, pageSize); 就会存在一个ThreadLocal 对象,并且 里面存储了 pagenum 和pagesize 这样在调用 intercept ()方法的时候,先判断 是否存在 threadLocal , 如果不存在,就不用 添加切面,如果存在 就先更改语句,在调用mapper。
PageMybatisInterceptor 的原理
最新推荐文章于 2024-06-19 16:56:30 发布