Mybatis学习- 拦截器-实现分页

来源:互联网 发布:淘宝商城女装朵以 编辑:程序博客网 时间:2024/05/21 08:58

本文的程序基本上都不是我自己实现的,网上有好多现成的例子。我只是根据自己理解,对整个过程进行了说明。


        Mybatis采用责任链模式,通过动态代理组织多个拦截器(插件),通过这些拦截器可以改变Mybatis的默认行为(诸如SQL重写之类的),由于插件会深入到Mybatis的核心,因此在编写自己的插件前最好了解下它的原理,以便写出安全高效的插件。Mybatis支持对Executor、StatementHandler、PameterHandler和ResultSetHandler进行拦截,也就是说会对这4种对象进行代理。

        对于分页,通过Mybatis学习- 拦截器-基本的图中,可以看到比较适合在StatementHandler上进行拦截。这样,我们通过获得其boundsql对象(就是sql语句+查询参数 的对象);然后判断boundsql对象的参数中有没有分页信息,如果有,则把分页信息取出来,然后重新组织boundsql的sql语句(因为,分页信息是动态的,所以对于mybatis来说这部分的参数mybatis处理不了,所以我们要取出来,然后根据这些信息去修改boundsql中的sql部分)。

好了,根据上面的思路,首先我们要获得StatementHandler:

if (ivk.getTarget() instanceof RoutingStatementHandler) {RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget();BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate");

上面这个代码,表示我们首先获得RoutingStatementHandler,这个Handler也是继承了StatementHandler接口,但是基本不做具体的事情,只是再把请求转发给其他的StatementHandler。默认的BaseStatementHandler(具体执行查询的handler)怎样获得? 用delegate!就是说RoutingStatementHandler的delegate成员。

         得到了BaseStatementHandler,你就可以在这上面做些事情了。获取boundsql,然后修改boundsql:

Object parameterObject = boundSql.getParameterObject();
获取boundsql的参数,执行某些检查,看看里面有没有包含分页参数?

        没有,则return ivk.proceed(); 继续执行链;

有,则需要根据分页信息,修改boundsql中的sql,然后return ivk.proceed();


这里修改sql有点技巧,因为不同的rdbms分页的语法都有些不同,所以我们实现诸如下面的代码:

private String generatePagesSql(String sql, PageView page) {if (page != null && dialectObject != null) {//pageNow默认是从1,而已数据库是从0开始计算的.所以(page.getPageNow()-1)int pageNow = page.getPageNow();return dialectObject.getLimitString(sql, (pageNow<=0?0:pageNow-1)* page.getPageSize(), page.getPageSize());}return sql;}

让具体重新拼装sql的工作交给dialectObject.getLimitString(sql, (pageNow<=0?0:pageNow-1)* page.getPageSize(), page.getPageSize());去做。

        然后我们根据不同的rdbms实现不同的dialectObject.getLimitString就可以了。


        好,现在总结一下。

        你想实现分页,获取StatementHandler-> BOUNDSQL-->加工boundsql-->return ivk.proceed();

        

        下面提出一个问题: 如果我们已经实现了处理链,对请求进行拦截,并根据请求的参数进行处理,那么我们需要发什么样的请求?

        就是说我们的Mapper文件应该怎样写?我们的Mapper接口应该怎样写?我们调用的时候应该传什么参数?

先看Mapper文件:

    <select id="query" resultMap="BaseResultMap" parameterType="java.util.HashMap" >    select     *    from bai_user    <where><if test="t.USERNAME != null and t.USERNAME != ''">username like '%${t.USERNAME}%'</if></where>  </select>

parameterType应该是一个Map类型,这样我们可以定义一个pageview,然后放在里面,到了boundsql中在根据名字取出来。

再看Mapper接口:

Mapper文件中我们传递的是Map,但我们Map中的参数类型不确定,有的是数值,有的是字符串,有的是pageview对象。所以变成如下格式:

List<baiuser> query(HashMap<Object, Object> map);

再看怎样调用。写一个测试类:

package example10.test;import java.util.HashMap;import java.util.Map;import java.util.List;import org.junit.Test;import org.junit.Before;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.alibaba.fastjson.JSON;import example10.dao.baiuserMapper;import example10.model.baiuser;import example10.util.PageView;public class baiuserTest {private baiuserMapper userDao;    @Beforepublic void before(){@SuppressWarnings("resource")ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath:example10/conf/spring.xml"});userDao = (baiuserMapper) context.getBean("baiuserMapper");}    @Testpublic void test(){HashMap<Object, Object> map = new HashMap<Object, Object>();baiuser user1 = new baiuser();user1.setUSERNAME("bai");PageView pageView = new PageView();map.put("paging", pageView);map.put("t", user1);//return getSqlSession().selectList(baiuserMapper.query ,map);List<baiuser> user = userDao.query(map);System.out.println(JSON.toJSONString(user));}}



       示例代码:

http://download.csdn.net/detail/u013269938/7302953



0 0