MyBatis进阶之插件开发(自定义分页插件)

            mybatis的插件,实际上是拦截器,通过这些插件可以改变mybatis的默认行为。mybatis可以拦截的对象有:

(1)Executor ,执行的SQL 全过程,包括组装参数、组装结果返回和执行SQL的过程等都可以拦截

(2)StatementHandler ,执行SQL的过程,拦截该对象可以重写执行SQL的过程

(3)ParameterHandler ,执行SQL 的参数组装,拦截该对象可以重写组装参数的规则

(4)ResultSetHandler,执行结果的组装,拦截该对象可以重写组装结果的规则

 

下面,将自定义一个简单的分页小插件,来了解插件的开发流程。

 示例代码,已放入GitHub上:https://github.com/qiuxinfa/mybatis-study

 

1.自定义分页对象

     这里,为了简单起见,只是设置了当期页和每页的大小:

public class MyPage {
    private Integer currentPage;    //当前页是第几页
    private Integer pageSize;       //每页的大小
    //省略set、get...

}

2.自定义插件

       mybatis的插件,需要实现Interceptor接口,并且需要添加注解@Intercepts,简单解释下注解的参数:

(1)type,要拦截的对象

(2)method,要拦截的方法

(3)args,要拦截方法的参数,注意要一一对应

详细的说明,写在代码中了:

//表示拦截StatementHandler类的prepare方法
@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class})})
public class MyPageInterceptor implements Interceptor{

    private Integer defaultPageSize;     //默认每页的大小
    private Integer defaultCurrentPage;  //默认页数
    //实现拦截逻辑
    public Object intercept(Invocation invocation) throws Throwable {
        //获取目标对象
        StatementHandler  statementHandler = (StatementHandler) invocation.getTarget();
        //获取元数据
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        //获取绑定的sql
        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
        //获取参数对象
        Object parameterObject = boundSql.getParameterObject();
        //获取传入分页参数
        MyPage myPage = this.getPage(parameterObject);
        String sql = (String) metaObject.getValue("delegate.boundSql.sql");
        boolean isSelect = sql.trim().toLowerCase().startsWith("select");
        //如果不是查询语句,则直接进入下一个操作
        if(!isSelect){
            return invocation.proceed();
        }
        System.out.println("原来的sql:"+sql);
        //修改sql
        String page_sql = "select * from ("+sql+") page_table limit ?,?";
        //设置修改过的sql
        metaObject.setValue("delegate.boundSql.sql",page_sql);
        //如果没有传入相应的分页参数,则设置为默认值
        if (myPage.getCurrentPage() == null){
            //设置默认值
            myPage.setCurrentPage(this.defaultCurrentPage);
        }
        if (myPage.getPageSize() == null){
            //设置默认值
            myPage.setPageSize(this.defaultPageSize);
        }
        //获取参数
        PreparedStatement ps = (PreparedStatement) invocation.proceed();
        // 获取sql的总参数个数
        int paramCount = ps.getParameterMetaData().getParameterCount();
        // 设置分页参数
        ps.setInt(paramCount - 1, (myPage.getCurrentPage() - 1) * myPage.getPageSize());
        ps.setInt(paramCount, myPage.getPageSize());
        return ps;
    }

    //返回被拦截对象的代理对象
    public Object plugin(Object target) {
        System.out.println("开始包装目标对象");
        return Plugin.wrap(target,this);
    }

    //设置插件配置的参数
    public void setProperties(Properties properties) {
        this.defaultCurrentPage = Integer.valueOf(properties.getProperty("default.currentPage", "1"));
        this.defaultPageSize = Integer.valueOf(properties.getProperty("default.pageSize", "3"));
    }


    /**
     * 获取分页参数
     *
     * @param parameterObject
     * @return
     */
    private MyPage getPage(Object parameterObject) {
        if (parameterObject == null) {
            return null;
        }

        if (parameterObject instanceof Map) {
            // 如果传入的参数是map类型的,则遍历map取出Page对象
            Map parameMap = (Map) parameterObject;
            Set keySet = parameMap.keySet();
            for (String key : keySet) {
                Object value = parameMap.get(key);
                if (value instanceof MyPage) {
                    // 返回MyPage对象
                    return (MyPage) value;
                }
            }
        } else if (parameterObject instanceof MyPage) {
            // 如果传入的是Page类型,则直接返回该对象
            return (MyPage) parameterObject;
        }

        // 初步判断并没有传入MyPage类型的参数,返回null
        return null;
    }
    
}

3.配置插件

    需要在mybatis的主配置文件mybatis-config.xml中,添加插件配置:

    
        
        
            
            
            
        
    

4.测试

添加测试类:

public class PluginDemo {
    public static void main(String[] args) throws IOException{
        //读取配置信息
        InputStream  inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //根据配置信息,创建SqlSession工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //SqlSession工厂创建SqlSession
        SqlSession sqlSession = factory.openSession();
        //获取接口的代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //执行相应的接口方法
        MyPage myPage = new MyPage();
        List users = mapper.getAllUserByPage(myPage);
        System.out.println(users);
        //关闭连接
        sqlSession.close();
    }
}

看测试结果:

MyBatis进阶之插件开发(自定义分页插件)_第1张图片

 

这里在调用方法时,并没有给分页对象传递参数,所以使用的是默认的参数。

可以发现,已经实现了拦截。

你可能感兴趣的:(mybatis)