Guns——使用Mybatis-plus的分页插件(五)

1.介绍常规分页方法

  • 物理分页: 物理分页依赖的是某一物理实体,这个物理实体就是数据库,比如MySQL数据库提供了limit关键字,程序员只需要编写带有limit关键字的SQL语句,数据库返回的就是分页结果。
  • 逻辑分页:逻辑分页依赖的是程序员编写的代码。数据库返回的不是分页结果,而是全部数据,然后再由程序员通过代码获取分页数据,常用的操作是一次性从数据库中查询出全部数据并存储到List集合中,因为List集合有序,再根据索引获取指定范围的数据。
  • 注意:一般使用的是物理分页,因为使用逻辑分页一次性获取数据过多,不易把控

2.前台使用bootstrap table

  • 由于bootstao table内容较多,在这里不介绍bootstrap table,只是想说明使用此table会自动传递部分参数Guns——使用Mybatis-plus的分页插件(五)_第1张图片
  •  回过神来发现还是需要了解了解比较好,首先需要添加js的依赖,这里不说明
  • 首先这里使用的是html+js的写法,首先html上编写
 <#table id="OptLogTable"/>
  • 接着开始使用js的方法初始化table,在这里只是展示了最核心的初始化数据
init: function () {
            var tableId = this.bstableId;
            var me = this;
            this.btInstance =
                $('#' + tableId).bootstrapTable({
                    contentType: "application/x-www-form-urlencoded",
                    url: this.url,				//请求地址
                    method: this.method,		//ajax方式,post还是get
                    ajaxOptions: {				//ajax请求的附带参数
                        data: this.data
                    },
                    toolbar: "#" + this.toolbarId,//顶部工具条
                    striped: true,     			//是否显示行间隔色
                    cache: false,      			//是否使用缓存,默认为true
                    sortable: true,      		//是否启用排序
                    sortOrder: "desc",     		//排序方式
                    pageNumber: 1,      		//初始化加载第一页,默认第一页
                    pageSize: 14,      			//每页的记录行数(*)
                    pageList: [14, 50, 100],  	//可供选择的每页的行数(*)
                    queryParamsType: 'limit', 	//默认值为 'limit' ,在默认情况下 传给服务端的参数为:offset,limit,sort
                    queryParams: function (param) {
                        return $.extend(me.queryParams, param);
                    }, // 向后台传递的自定义参数
                    sidePagination: this.paginationType,   //分页方式:client客户端分页,server服务端分页(*)
                    search: false,      		//是否显示表格搜索,此搜索是客户端搜索,不会进服务端
                    strictSearch: true,			//设置为 true启用 全匹配搜索,否则为模糊搜索
                    showColumns: true,     		//是否显示所有的列
                    showRefresh: true,     		//是否显示刷新按钮
                    minimumCountColumns: 2,    	//最少允许的列数
                    clickToSelect: true,    	//是否启用点击选中行
                    searchOnEnterKey: true,		//设置为 true时,按回车触发搜索方法,否则自动触发搜索方法
                    columns: this.columns,		//列数组
                    pagination: true,			//是否显示分页条
                    height: this.height,
                    icons: {
                        refresh: 'glyphicon-repeat',
                        toggle: 'glyphicon-list-alt',
                        columns: 'glyphicon-list'
                    },
                    iconSize: 'outline'
                });
            return this;
        },

3.配置相关bean

  • 其实就是在配置类上增加一个拦截器进行拦截分页,这是关键操作
    /**
     * mybatis-plus分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

4.创建拦截器需要的page对象

  • 在这里依据前端传来的参数进行page的生产
/**
 * BootStrap Table默认的分页参数创建
 *
 * @author fengshuonan
 * @date 2017-04-05 22:25
 */
public class PageFactory {

    public Page defaultPage() {
        HttpServletRequest request = HttpContext.getRequest();
        int limit = Integer.valueOf(request.getParameter("limit"));     //每页多少条数据
        int offset = Integer.valueOf(request.getParameter("offset"));   //每页的偏移量(本页当前有多少条)
        String sort = request.getParameter("sort");         //排序字段名称
        String order = request.getParameter("order");       //asc或desc(升序或降序)
        if (ToolUtil.isEmpty(sort)) {
            Page page = new Page<>((offset / limit + 1), limit);
            page.setOpenSort(false);
            return page;
        } else {
            Page page = new Page<>((offset / limit + 1), limit, sort);
            if (Order.ASC.getDes().equals(order)) {
                page.setAsc(true);
            } else {
                page.setAsc(false);
            }
            return page;
        }
    }
}

5.实战演练

从下面可以看到我们直接通过PageFactory的方法创建一个Page,并将Page传到 对应的dao,拦截器会根据此Page参数判断是否需要分页


    /**
     * 查询操作日志列表
     */
    @RequestMapping("/list")
    @Permission(Const.ADMIN_NAME)
    @ResponseBody
    public Object list(@RequestParam(required = false) String beginTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String logName, @RequestParam(required = false) Integer logType) {
        Page page = new PageFactory().defaultPage();
        List> result = operationLogService.getOperationLogs(page, beginTime, endTime, logName, BizLogType.valueOf(logType), page.getOrderByField(), page.isAsc());
        page.setRecords(new LogWarpper(result).wrap());
        return new PageInfoBT<>(page);
    }
  • 从mapper.xml 上来看我们确实看不到有分页操作的痕迹,所以证明是拦截器帮我们操作了
  • 但是分页拦截器只是帮我们分页,并没有帮我们排序或者按字段排序,所以我们可以看到这一部分需要我们手工写入xml文件里面

6.原理

总的来说就是判断字段是否有传入page对象,如果有则改变sql语句,之后再继续执行业务逻辑

 @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        this.sqlParser(metaObject);
        // 先判断是不是SELECT操作
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
            return invocation.proceed();
        }
        RowBounds rowBounds = (RowBounds) metaObject.getValue("delegate.rowBounds");
        /* 不需要分页的场合 */
        if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
            // 本地线程分页
            if (localPage) {
                // 采用ThreadLocal变量处理的分页
                rowBounds = PageHelper.getPagination();
                if (rowBounds == null) {
                    return invocation.proceed();
                }
            } else {
                // 无需分页
                return invocation.proceed();
            }
        }
        // 针对定义了rowBounds,做为mapper接口方法的参数
        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
        String originalSql = boundSql.getSql();
        Connection connection = (Connection) invocation.getArgs()[0];
        DBType dbType = StringUtils.isNotEmpty(dialectType) ? DBType.getDBType(dialectType) : JdbcUtils.getDbType(connection.getMetaData().getURL());
        if (rowBounds instanceof Pagination) {
            Pagination page = (Pagination) rowBounds;
            boolean orderBy = true;
            if (page.isSearchCount()) {
                SqlInfo sqlInfo = SqlUtils.getOptimizeCountSql(page.isOptimizeCountSql(), sqlParser, originalSql);
                orderBy = sqlInfo.isOrderBy();
                this.queryTotal(overflowCurrent, sqlInfo.getSql(), mappedStatement, boundSql, page, connection);
                if (page.getTotal() <= 0) {
                    return invocation.proceed();
                }
            }
            String buildSql = SqlUtils.concatOrderBy(originalSql, page, orderBy);
            originalSql = DialectFactory.buildPaginationSql(page, buildSql, dbType, dialectClazz);
        } else {
            // support physical Pagination for RowBounds
            originalSql = DialectFactory.buildPaginationSql(rowBounds, originalSql, dbType, dialectClazz);
        }

        /*
         * 

禁用内存分页

*

内存分页会查询所有结果出来处理(这个很吓人的),如果结果变化频繁这个数据还会不准。

*/ metaObject.setValue("delegate.boundSql.sql", originalSql); metaObject.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaObject.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); return invocation.proceed(); }

 

 

 

 

 

 

你可能感兴趣的:(spring)