PaginationInterceptor.java 8.9 KB
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
/**
* Copyright (c) 2011-2020, hubin (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.baomidou.mybatisplus.plugins;

import com.baomidou.mybatisplus.entity.CountOptimize;
import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.plugins.pagination.DialectFactory;
import com.baomidou.mybatisplus.plugins.pagination.IDialect;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.baomidou.mybatisplus.toolkit.IOUtils;
import com.baomidou.mybatisplus.toolkit.SqlUtils;
import com.baomidou.mybatisplus.toolkit.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

/**
* <p>
* 分页拦截器
* </p>
*
* @author hubin
* @Date 2016-01-23
*/
@Intercepts({
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class }),
@Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
public class PaginationInterceptor implements Interceptor {

/* 溢出总页数,设置第一页 */
private boolean overflowCurrent = false;
/* Count优化方式 */
private String optimizeType = "default";
/* 方言类型 */
private String dialectType;
/* 方言实现类 */
private String dialectClazz;

public Object intercept(Invocation invocation) throws Throwable {

Object target = invocation.getTarget();
if (target instanceof StatementHandler) {
StatementHandler statementHandler = (StatementHandler) target;
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds");

/* 不需要分页的场合 */
if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
return invocation.proceed();
}

/* 定义数据库方言 */
IDialect dialect = getiDialect();

/*
* <p> 禁用内存分页 </p> <p> 内存分页会查询所有结果出来处理(这个很吓人的),如果结果变化频繁这个数据还会不准。
* </p>
*/
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
String originalSql = (String) boundSql.getSql();
metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);

/**
* <p>
* 分页逻辑
* </p>
* <p>
* 查询总记录数 count
* </p>
*/
if (rowBounds instanceof Pagination) {
Pagination page = (Pagination) rowBounds;
boolean orderBy = true;
if (page.isSearchCount()) {
/*
* COUNT 查询,去掉 ORDER BY 优化执行 SQL
*/
CountOptimize countOptimize = SqlUtils.getCountOptimize(originalSql, optimizeType, dialectType,
page.isOptimizeCount());
orderBy = countOptimize.isOrderBy();
}
/* 执行 SQL */
String buildSql = SqlUtils.concatOrderBy(originalSql, page, orderBy);
originalSql = dialect.buildPaginationSql(buildSql, page.getOffsetCurrent(), page.getSize());
}

/**
* 查询 SQL 设置
*/
metaStatementHandler.setValue("delegate.boundSql.sql", originalSql);
} else {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object parameterObject = null;
RowBounds rowBounds = null;
if (invocation.getArgs().length > 1) {
parameterObject = invocation.getArgs()[1];
rowBounds = (RowBounds) invocation.getArgs()[2];
}
/* 不需要分页的场合 */
if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
return invocation.proceed();
}

BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
/*
* <p> 禁用内存分页 </p> <p> 内存分页会查询所有结果出来处理(这个很吓人的),如果结果变化频繁这个数据还会不准。
* </p>
*/
String originalSql = (String) boundSql.getSql();

/**
* <p>
* 分页逻辑
* </p>
* <p>
* 查询总记录数 count
* </p>
*/
if (rowBounds instanceof Pagination) {
Connection connection = null;
try {
connection = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();
Pagination page = (Pagination) rowBounds;
if (page.isSearchCount()) {
/*
* COUNT 查询,去掉 ORDER BY 优化执行 SQL
*/
CountOptimize countOptimize = SqlUtils.getCountOptimize(originalSql, optimizeType, dialectType,
page.isOptimizeCount());
page = this.count(countOptimize.getCountSQL(), connection, mappedStatement, boundSql, page);
/** 总数 0 跳出执行 */
if (page.getTotal() <= 0) {
return invocation.proceed();
}
}
} finally {
IOUtils.closeQuietly(connection);
}
}
}

return invocation.proceed();

}

/**
* 获取数据库方言
*
* @return
* @throws Exception
*/
private IDialect getiDialect() throws Exception {
IDialect dialect = null;
if (StringUtils.isNotEmpty(dialectType)) {
dialect = DialectFactory.getDialectByDbtype(dialectType);
} else {
if (StringUtils.isNotEmpty(dialectClazz)) {
try {
Class<?> clazz = Class.forName(dialectClazz);
if (IDialect.class.isAssignableFrom(clazz)) {
dialect = (IDialect) clazz.newInstance();
}
} catch (ClassNotFoundException e) {
throw new MybatisPlusException("Class :" + dialectClazz + " is not found");
}
}
}
/* 未配置方言则抛出异常 */
if (dialect == null) {
throw new MybatisPlusException("The value of the dialect property in mybatis configuration.xml is not defined.");
}
return dialect;
}

/**
* 查询总记录条数
*
* @param sql
* @param connection
* @param mappedStatement
* @param boundSql
* @param page
*/
public Pagination count(String sql, Connection connection, MappedStatement mappedStatement, BoundSql boundSql, Pagination page) {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = connection.prepareStatement(sql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), sql, boundSql.getParameterMappings(),
boundSql.getParameterObject());
ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, boundSql.getParameterObject(),
countBS);
parameterHandler.setParameters(pstmt);
rs = pstmt.executeQuery();
int total = 0;
if (rs.next()) {
total = rs.getInt(1);
}
page.setTotal(total);
/*
* 溢出总页数,设置第一页
*/
if (overflowCurrent && (page.getCurrent() > page.getPages())) {
page = new Pagination(1, page.getSize());
page.setTotal(total);
}
} catch (Exception e) {
// ignored
} finally {
IOUtils.closeQuietly(pstmt, rs);
}
return page;
}

public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
}
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}

public void setProperties(Properties prop) {
String dialectType = prop.getProperty("dialectType");
String dialectClazz = prop.getProperty("dialectClazz");
if (StringUtils.isNotEmpty(dialectType)) {
this.dialectType = dialectType;
}
if (StringUtils.isNotEmpty(dialectClazz)) {
this.dialectClazz = dialectClazz;
}
}

public void setDialectType(String dialectType) {
this.dialectType = dialectType;
}

public void setDialectClazz(String dialectClazz) {
this.dialectClazz = dialectClazz;
}

public void setOverflowCurrent(boolean overflowCurrent) {
this.overflowCurrent = overflowCurrent;
}

public void setOptimizeType(String optimizeType) {
this.optimizeType = optimizeType;
}
}