PageMybatisInterceptor 的原理

来源:互联网 发布:网络问卷调查赚钱 编辑:程序博客网 时间:2024/04/29 20:56
首先 要知道,所有的拦截器都是需要配置的,这里拦截器是在执行 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。
0 0
原创粉丝点击