SpringBoot之Mybatis手寫分頁組件

#mybatis分頁組件實現原理 分頁原理很簡單,只要實現Mybatis的Interceptor就可使用,這個組件的做者很給力,寫的很詳細,就不詳細描述了。git

Mybatis分頁組件實現github

#手寫組件實現的一個類sql

@Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
		RowBounds.class, ResultHandler.class }) })
public class PaginationStatementInterceptor implements Interceptor {
	private final static Logger logger = LoggerFactory.getLogger(PaginationStatementInterceptor.class);

	private Dialect dialect;

	static int MAPPED_STATEMENT_INDEX = 0;
	static int PARAMETER_INDEX = 1;
	static int ROWBOUNDS_INDEX = 2;
	static int RESULT_HANDLER_INDEX = 3;

	public Object intercept(Invocation invocation) throws Throwable {
		final Object[] queryArgs = invocation.getArgs();
		Object parameter = queryArgs[PARAMETER_INDEX];
		Pageable pageRequest = findPageableObject(parameter);
		if (pageRequest != null) {
			final MappedStatement ms = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
			if (parameter instanceof ParamMap) {
				ParamMap<?> paramMap = (ParamMap<?>) parameter;
				if (paramMap.size() == 4) {
					parameter = ((ParamMap<?>) parameter).get("param1");
					queryArgs[PARAMETER_INDEX] = parameter;
				}
			}
			final BoundSql boundSql = ms.getBoundSql(parameter);
			String sql = boundSql.getSql().trim().replaceAll(";$", "");
			int total = this.queryTotal(sql, ms, boundSql);
			if (pageRequest.getSort() != null) {
				Iterator<Order> it = pageRequest.getSort().iterator();
				if (it.hasNext()) {
					sql = "select o.* from ( " + sql + " ) o order by ";
				}
				for (int i = 0; it.hasNext(); i++) {
					if (i > 0) {
						sql += " , ";
					}
					Order order = it.next();
					sql += order.getProperty() + " " + order.getDirection().name();
				}
			}

			String limitSql = dialect.getLimitString(sql, pageRequest.getOffset(), pageRequest.getPageSize());
			queryArgs[ROWBOUNDS_INDEX] = new RowBounds(RowBounds.NO_ROW_OFFSET, RowBounds.NO_ROW_LIMIT);
			queryArgs[MAPPED_STATEMENT_INDEX] = copyFromNewSql(ms, boundSql, limitSql);

			Object ret = invocation.proceed();
			@SuppressWarnings("unchecked")
			Page<Object> page = new PageImpl<Object>((List<Object>) ret, pageRequest, total);
			List<Page<?>> ls = new ArrayList<Page<?>>(1);
			ls.add(page);
			return ls;
		}
		return invocation.proceed();
	}

	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	public void setProperties(Properties properties) {
		String dialectClass = properties.getProperty("dialectClass");
		try {
			setDialect((Dialect) Class.forName(dialectClass).newInstance());
		} catch (Exception e) {
			throw new RuntimeException("cannot create dialect instance by dialectClass:" + dialectClass, e);
		}
	}

	public Dialect getDialect() {
		return dialect;
	}

	public void setDialect(Dialect dialect) {
		this.dialect = dialect;
	}

	
	private Pageable findPageableObject(Object params) {

		if (params == null) {
			return null;
		}

		// 單個參數 表現爲參數對象
		if (Pageable.class.isAssignableFrom(params.getClass())) {
			return (Pageable) params;
		}

		// 多個參數 表現爲 ParamMap
		else if (params instanceof ParamMap) {
			ParamMap<?> paramMap = (ParamMap<?>) params;
			for (Map.Entry<String, ?> entry : paramMap.entrySet()) {
				Object paramValue = entry.getValue();
				if (paramValue != null && Pageable.class.isAssignableFrom(paramValue.getClass())) {
					return (Pageable) paramValue;
				}
			}
		}

		return null;
	}

	private int queryTotal(String sql, MappedStatement mappedStatement, BoundSql boundSql) throws SQLException {
		Connection connection = null;
		PreparedStatement countStmt = null;
		ResultSet rs = null;
		try {

			connection = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();

			String countSql = /*
								 * "select count(1) as cnt from (" + sql + ")  c";
								 */ this.dialect.getCountString(sql);

			countStmt = connection.prepareStatement(countSql);
			BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql,
					boundSql.getParameterMappings(), boundSql.getParameterObject());

			setParameters(countStmt, mappedStatement, countBoundSql, boundSql.getParameterObject());

			rs = countStmt.executeQuery();
			int totalCount = 0;
			if (rs.next()) {
				totalCount = rs.getInt(1);
			}

			return totalCount;
		} catch (SQLException e) {
			logger.error("查詢總記錄數出錯", e);
			throw e;
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					logger.error("exception happens when doing: ResultSet.close()", e);
				}
			}

			if (countStmt != null) {
				try {
					countStmt.close();
				} catch (SQLException e) {
					logger.error("exception happens when doing: PreparedStatement.close()", e);
				}
			}

			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					logger.error("exception happens when doing: Connection.close()", e);
				}
			}
		}
	}

	private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
			Object parameterObject) throws SQLException {
		ParameterHandler parameterHandler = /*
											 * mappedStatement.getLang().
											 * createParameterHandler(
											 * mappedStatement, parameterObject,
											 * boundSql);
											 */new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
		parameterHandler.setParameters(ps);
	}

	private MappedStatement copyFromNewSql(MappedStatement ms, BoundSql boundSql, String sql) {
		BoundSql newBoundSql = copyFromBoundSql(ms, boundSql, sql);
		return copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));
	}

	public static class BoundSqlSqlSource implements SqlSource {
		BoundSql boundSql;

		public BoundSqlSqlSource(BoundSql boundSql) {
			this.boundSql = boundSql;
		}

		public BoundSql getBoundSql(Object parameterObject) {
			return boundSql;
		}
	}

	private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) {
		BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(),
				boundSql.getParameterObject());
		for (ParameterMapping mapping : boundSql.getParameterMappings()) {
			String prop = mapping.getProperty();
			if (boundSql.hasAdditionalParameter(prop)) {
				newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
			}
		}
		return newBoundSql;
	}

	// see: MapperBuilderAssistant
	private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
		Builder builder = new Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());

		builder.resource(ms.getResource());
		builder.fetchSize(ms.getFetchSize());
		builder.statementType(ms.getStatementType());
		builder.keyGenerator(ms.getKeyGenerator());
		if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
			StringBuffer keyProperties = new StringBuffer();
			for (String keyProperty : ms.getKeyProperties()) {
				keyProperties.append(keyProperty).append(",");
			}
			keyProperties.delete(keyProperties.length() - 1, keyProperties.length());
			builder.keyProperty(keyProperties.toString());
		}

		// setStatementTimeout()
		builder.timeout(ms.getTimeout());

		// setStatementResultMap()
		builder.parameterMap(ms.getParameterMap());

		// setStatementResultMap()
		builder.resultMaps(ms.getResultMaps());
		builder.resultSetType(ms.getResultSetType());

		// setStatementCache()
		builder.cache(ms.getCache());
		builder.flushCacheRequired(ms.isFlushCacheRequired());
		builder.useCache(ms.isUseCache());

		return builder.build();
	}
}

如何使用,這個手寫的分頁組件

在你的Mapper類中,須要分頁的接口裏加入分頁參數Pageable pageable,而後mapper.xml中就不須要寫limit 0,10等語句,在執行分頁查詢前,組件會自動組裝分頁mybatis

Page<BaseType> queryBaseTypePageList(Map<String,Object> map,Pageable pageable);

#推薦一款非好用的Mybatis分頁組件 該 @Liuzh_533 做者的項目,很是好推薦一下。 GIT地址https://github.com/pagehelper/Mybatis-PageHelperapp

相關文章
相關標籤/搜索