Mybatis—插件(拦截器)

1.自定义插件

  • type: 拦截对象
    • Executor: 执行SQL全过程,包含组装参数,组装结果集返回和执行SQL,比较广泛
    • StatementHandler: 执行SQL的过程,最常用的拦截
    • ParameterHandler: 拦截执行SQL的参数组装,可以重写组装参数规则
    • ResultSetHandler: 拦截执行结果的组装,可以重写组装结果的规则
  • method: 拦截方法,必须对应拦截对象中的方法
  • args: 参数,必须和接口中的拦截方法参数列表相同

2.自定义插件打印SQL执行情况

@Intercepts({@Signature(
    type= StatementHandler.class,
    method = "prepare",
    args = {Connection.class, Integer.class})})
public class ExamplePlugin implements Interceptor {
    private Logger log = Logger.getLogger(ExamplePlugin.class);
    private Properties properties = new Properties();

    //实现拦截逻辑
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取执行目标类
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        //封装获取工具类对象
        MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
        //获取绑定SQL对象
        BoundSql boundSql = (BoundSql)metaStatementHandler.getValue("delegate.boundSql");
        //获取参数对象
        Object parameterObject = boundSql.getParameterObject();
        log.warn("|--参数名称\t|\t参数值|");
        //使用注解@Parm或Map传递多个参数本质都是map类型
        if (parameterObject instanceof Map){
            Map<String, Object> paraMap = (Map<String, Object>)parameterObject;
            for (Map.Entry<String, Object> entry : paraMap.entrySet()) {
                log.warn("|--"+ entry.getKey() +"\t|\t"+ entry.getValue() +"--|");
            }
        }else{
            log.warn("参数列表:" + (Book) parameterObject);
        }
        //获取执行SQL语句
        String sql = boundSql.getSql();
        long start = System.currentTimeMillis();
        //执行原始SQL
        Object obj = invocation.proceed();
        log.warn("执行SQL: [ "+ sql +" ], 耗时:" + (System.currentTimeMillis() - start) +"ms");
        return obj;
    }

    //生成代理对象
    @Override
    public Object plugin(Object target) {
        //系统默认方法生成代理对象
        Object wrap = Plugin.wrap(target, this);
        return wrap;
    }

    //设置参数
    @Override
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

**

3.自定义分页插件

@Intercepts({@Signature(
    type= StatementHandler.class,
    method = "prepare",
    args = {Connection.class, Integer.class})})
    public class ExamplePlugin implements Interceptor {
        private Logger log = Logger.getLogger(ExamplePlugin.class);
        private Integer defaultPageNum;
        private Integer defaultPageSize;
        private Boolean defaultIsUsePage;

    //实现拦截逻辑
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
        BoundSql boundSql = (BoundSql)metaStatementHandler.getValue("delegate.boundSql");
        String sql = boundSql.getSql();
        //获取分页参数列表
        PageParams pageParams = parameterList(boundSql);
        Integer pageNum = pageParams.getPageNum() == null ? defaultPageNum : pageParams.getPageNum();
        Integer pageSize = pageParams.getPageSize() == null ? defaultPageSize : pageParams.getPageSize();
        Boolean isUsePage = pageParams.getPageSize() == null ? defaultIsUsePage : pageParams.getIsUsePage();
        //是否执行分页操作
        if(!sql.trim().toLowerCase().startsWith("select") || !isUsePage){
            return invocation.proceed();
        }
        log.warn("PageNum="+ pageNum +", pageSize="+ pageSize +", isUsePage="+ isUsePage);
        return preparedSQL(invocation, metaStatementHandler, sql, pageNum, pageSize);
    }

    //生成代理对象
    @Override
    public Object plugin(Object target) {
        //系统默认方法生成代理对象
        Object wrap = Plugin.wrap(target, this);
        return wrap;
    }

    //设置参数
    @Override
    public void setProperties(Properties properties) {
        this.defaultPageNum = Integer.parseInt(properties.getProperty("default.pageNum", "1"));
        this.defaultPageSize = Integer.parseInt(properties.getProperty("default.pageSize", "10"));
        this.defaultIsUsePage = Boolean.parseBoolean(properties.getProperty("default.isUsePage", "true"));
    }

    //预编译新SQL
    private Object preparedSQL(Invocation invocation, MetaObject metaStatementHandler, String sql, int pageNum, int pageSize) throws InvocationTargetException, IllegalAccessException, SQLException {
        String newSql = "select * from (" + sql + ") tmp_table limit ?, ?";
        log.warn("newSql: "+ newSql);
        //替换将要执行的SQL
        metaStatementHandler.setValue("delegate.boundSql.sql", newSql);
        //执行SQL
        Object obj = invocation.proceed();
        preparePageDataParams((PreparedStatement) obj, pageNum, pageSize);
        return obj;
    }


    //设置分页参数
    private void preparePageDataParams(PreparedStatement ps, int pageNum, int pageSize) throws SQLException {
        //获取参数数量
        int parameterCount = ps.getParameterMetaData().getParameterCount();
        //设置参数
        ps.setInt(parameterCount - 1, (pageNum - 1) * pageSize); //offset
        ps.setInt(parameterCount, pageSize); //显示行数
    }

    //获取参数
    private PageParams parameterList(BoundSql boundSql){
        PageParams pageParams = null;
        Object parameterObject = boundSql.getParameterObject();
        if (parameterObject instanceof Map) {
            Map<String, Object> paraMap = (Map<String, Object>)parameterObject;
            for(Object value: paraMap.values()){
                if (value instanceof PageParams) {
                    pageParams = (PageParams) value;
                }
            }
        }else{
            pageParams = (PageParams) parameterObject;
        }
        return pageParams;
    }
}


@Data
public class PageParams {
    //页码
    private Integer pageNum;
    //每页行数
    private Integer pageSize;
    //是否使用分页
    private Boolean isUsePage;
}

4.使用分页插件PageHelper

  • 添加依赖
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.0</version>
</dependency>
  • 配置
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!--reasonable:分页合理化参数,默认值为false,直接根据参数进行查询
            当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum >pages(超过总数时),会查询最后一页-->
        <!--<property name="reasonable" value="true"/>-->
    </plugin>
</plugins>
  • 程序中使用
    -对使用分页的SQL语句前执行PageHelper.startPage(pageNum, pageSize)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值