Mybatis之插件的浅谈

用到的很少,一般用于分页和现在sql返回数量

1. 插件是什么? 一个拦截器而已

2. 拦截什么? 只能拦截SqlSession的4大类

3. 如何使用是插件?

1. 写一个类实现Interceptor接口并使用@Signature即签名告诉插件拦截谁

2. 注册插件

<plugins>
    <plugin interceptor="com.allen.interceptor.MyPlugin">
        <property name="dbtype" value="mysql"/>
        <property name="limit" value="50"/>
    </plugin>
</plugins>
@Intercepts(
   {
       @Signature(
                type = StatementHandler.class, 
                method = "prepare", 
                args = {Connection.class}
        )
   }
)
public class MyPlugin implements Interceptor {
    // 限制表中间别名,避免表重名,所以起的怪些.
    // select * from (select * from t_role where role_name = ?) limit_Table_Name_xxx limit 50 
    private static final String LMT_TABLE_NAME = "limit_Table_Name_allen";
    // 默认限制查询返回行数
    private int limit;
    private String dbType;

    /**
     * 代提拦截对象方法的内容.
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("intercept方法 start");
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        // 分离代理对象,从而形成多次代理,通过两次循环最原始的被代理类,
        // MyBatis使用的是JDK代理.
        while (metaObject.hasGetter("h")) {
            Object object = metaObject.getValue("h");
            metaObject = SystemMetaObject.forObject(object);
        }
        // 分离最后一个代理对象的目标类
        while (metaObject.hasGetter("target")) {
            Object object = metaObject.getValue("target");
            metaObject = SystemMetaObject.forObject(object);
        }
        // 取出即将要执行的SQL.INSERT INTO t_role (role_name, note) VALUES (?, ?)
        String sql = (String) metaObject.getValue("delegate.boundSql.sql");

        String limitSql;
        // 判断参数是不是MySQL数据库且SQL有没有被插件重写过.
        if ("mysql".equals(this.dbType) && !sql.contains(LMT_TABLE_NAME) && sql.contains("select")) {
            // 去掉前后空格
            sql = sql.trim();
            // 将参数写入SQL.
            limitSql = "select * from (" + sql + ") " + LMT_TABLE_NAME + " limit " + limit;
            //重写要执行的SQL.
            metaObject.setValue("delegate.boundSql.sql", limitSql);
        }
        // 调用原来对象的方法,进入责任链的下一层级.
        System.out.println("intercept方法 end");
        return invocation.proceed();
    }

    /**
     * 生成对象的代理,这里常用MyBatis提供的Plugin类的wrap方法
     */
    @Override
    public Object plugin(Object o) {
        System.out.println("plugin方法");
        return Plugin.wrap(o, this);
    }

    /**
     * 获取插件配置的属性,我们在MyBatis的配置文件里面去配置
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("setProperties方法");
        String strLimit = properties.getProperty("limit", "50");
        this.limit = Integer.parseInt(strLimit);
        this.dbType = properties.getProperty("dbtype", "mysql");
    }
}

猜你喜欢

转载自blog.csdn.net/zhuhaoyu6666/article/details/87858766
今日推荐