PageMybatisInterceptor 的原理

首先 要知道,所有的拦截器都是需要配置的,这里拦截器是在执行 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值