6

如何实现一个mybaits 分页插件

 2 years ago
source link: https://segmentfault.com/a/1190000041084762
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如何实现一个mybaits 分页插件

在java web项目中经常会用到分页这个功能,而以常用的的持久层框架mybatis为例,并没有提供原生的物理分页功能相关接口,不过mybaits 提供了相应的插件功能可以方便我们做一些相应的扩展 ,这里我们数据库选为mysql ,一般情况下会直接使用第三放的插件 如 mybatis-helper , mybatis-plus ,他们都提供了分页这个功能,知其然知其所以然,如果不使用这些类库我们要如何做呢?

首先在mysql讲到分页我们会想到limit 关键字;然后呢前台用到分页 还需要有一个总页数 ,总页数的背后是总条数和每页多少条;关键点:通过插件实现 分页+总条数
这是一个简单的demo

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Delegate;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author yangrd
 * @date 2021/12/7
 */
@RequiredArgsConstructor

@Component
@Intercepts({@Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})})
public class MyTestInterceptor implements Interceptor {

    private final JdbcTemplate jdbcTemplate;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        BoundSql boundSql = (BoundSql) invocation.getArgs()[5];

        String tempSql = boundSql.getSql();

        MapperMethod.ParamMap<Object> parameterObject = (MapperMethod.ParamMap<Object>) boundSql.getParameterObject();
        List<String> argNames = boundSql.getParameterMappings().stream().map(ParameterMapping::getProperty).collect(Collectors.toList());
        Object[] args = argNames.stream().map(parameterObject::get).toArray();

        Long count = count(tempSql, args);

        Field field = BoundSql.class.getDeclaredField("sql");
        field.setAccessible(true);
        field.set(boundSql, String.format("%s limit 1, 10", tempSql));

        return Page.of(count, (ArrayList<?>) invocation.proceed());
    }

    @Data
    @AllArgsConstructor(staticName = "of")
    public static class Page<T> implements List<T> {

        private Long total;

        @Delegate
        private List<T> list;

    }

    private Long count(String tempSql, Object[] args) {

        String countSql = String.format("select count(*) from (%s) t", tempSql);
        return jdbcTemplate.queryForObject(countSql, Long.class, args);
    }
}

这是一个极其简单的demo 权当抛砖引玉 ,如判断是否需要分页、第几页、 每页多条数这些地方还需要完善,但它向我们展示了 mybatis中如何分页的核心原理,我想我们在这里结束了这个示例,但在这个示例之外如果能给你带来一些思考自然是极好的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK