SpringBoot之Mybatis手写分页组件

#mybatis分页组件实现原理 分页原理很简单,只要实现Mybatis的Interceptor就可以使用,这个组件的作者很给力,写的很详细,就不详细描述了。

Mybatis分页组件实现

#手写组件实现的一个类

@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等语句,在执行分页查询前,组件会自动组装分页

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

#推荐一款非好用的Mybatis分页组件 该 @Liuzh_533 作者的项目,非常好推荐一下。 GIT地址https://github.com/pagehelper/Mybatis-PageHelper

转载于:https://my.oschina.net/u/1456911/blog/821999

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中手写分页,可以借助MyBatis的Interceptor来实现。首先,你需要创建一个自定义的Interceptor类,实现MyBatis的Interceptor接口。这个类会在执行查询之前对查询语句进行拦截和修改,以实现分页功能。 在你的Mapper类中,需要在需要分页的接口方法中添加一个分页参数Pageable pageable。Pageable是一个接口,它包含了分页所需的信息,例如当前页码、每页显示数量等。你可以根据具体需求选择使用哪些属性。 然后,在mapper.xml文件中,你不需要再手动写"limit 0,10"等语句了。Interceptor会自动根据Pageable参数组装分页的SQL语句,将其添加到原始的查询语句中。 以下是一个实现分页的示例代码: 1. 创建一个自定义的Interceptor类,实现MyBatis的Interceptor接口,并重写intercept()方法。在该方法中,可以通过获取Pageable参数,从而修改原始的查询语句,实现分页功能。 ```java public class PaginationStatementInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { // 获取Mapper方法的参数 Object[] args = invocation.getArgs(); // 遍历参数,找到Pageable参数 for (Object arg : args) { if (arg instanceof Pageable) { Pageable pageable = (Pageable) arg; // 根据Pageable参数修改查询语句,实现分页 // ... break; } } // 执行原始的查询方法 return invocation.proceed(); } // 其他方法... } ``` 2. 在Spring Boot的配置文件中,将自定义的Interceptor配置到MyBatis的配置中。可以通过@Configuration类来实现。 ```java @Configuration public class MyBatisConfiguration { @Autowired private SqlSessionFactory sqlSessionFactory; @Bean public PaginationStatementInterceptor paginationStatementInterceptor() { PaginationStatementInterceptor interceptor = new PaginationStatementInterceptor(); // 配置Interceptor的其他参数... return interceptor; } @PostConstruct public void addInterceptor() { // 获取MyBatis的Configuration对象 Configuration configuration = sqlSessionFactory.getConfiguration(); // 添加自定义的Interceptor configuration.addInterceptor(paginationStatementInterceptor()); } // 其他配置... } ``` 通过以上步骤,你就可以在Spring Boot中实现手写分页功能了。只需要在需要分页的Mapper接口方法中添加Pageable参数,并在mapper.xml中不再需要手动写分页语句,Interceptor会自动帮你实现分页。 希望以上信息对你有所帮助。如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值