文档章节

SpringBoot之Mybatis手写分页组件

竹隐江南
 竹隐江南
发布于 2017/01/10 13:26
字数 821
阅读 230
收藏 1

#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

© 著作权归作者所有

竹隐江南

竹隐江南

粉丝 16
博文 18
码字总数 23717
作品 0
海淀
高级程序员
私信 提问
Spring boot Mybatis 整合(完整版)

个人开源项目 springboot+mybatis+thymeleaf+docker构建的个人站点开源项目(集成了个人主页、个人作品、个人博客) 朋友自制的springboot接口文档组件swagger2 更多干货 SpringBoot系列目录...

舒运
2018/07/09
369
0
从SpringBoot整合Mybatis分析自动配置

前言 SpringBoot凭借"约定大于配置"的理念,已经成为最流行的web开发框架,所以有必须对其进行深入的了解;本文通过整合Mybatis类来分析SpringBoot提供的自动配置(AutoConfigure)功能,在此之...

ksfzhaohui
07/02
101
0
ApiBoot 2.0.6 发布,API 接口服务基础框架

ApiBoot 是一款基于 SpringBoot 1.x、SpringBoot 2.x 的接口服务集成基础框架, 内部提供了框架的封装集成、使用扩展、自动化完成配置,让接口开发者可以选着性完成开箱即用, 不再为搭建接口...

恒宇少年
04/28
1K
0
SpringBoot整合mybatis的mybatis-spring的配置方式

我大概是15年初的时候,接触了SpringBoot,不过只开发了一个小项目,就没再使用过。时隔两年,SpringBoot变的热火朝天,我也不得不认真学习一下了,以下个人心得,愿对新手有所帮助。 Spring...

边鹏_尛爺鑫
2018/01/05
5.7K
16
SpringBoot 学习二:操作数据库

本文将从以下几个方面介绍: 前言 配置数据源 SpringBoot 整合 Mybatis SpringBoot 整合 JdbcTemplate SpringBoot 整合 Redis 前言 在上篇文章 SpringBoot 学习一 中已经学习了 SpringBoot的...

tsmyk0715
2018/09/26
569
0

没有更多内容

加载失败,请刷新页面

加载更多

Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
今天
6
0
计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
昨天
6
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
昨天
7
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
昨天
6
0
【技术分享】TestFlight测试的流程文档

上架基本需求资料 1、苹果开发者账号(如还没账号先申请-苹果开发者账号申请教程) 2、开发好的APP 通过本篇教程,可以学习到ios证书申请和打包ipa上传到appstoreconnect.apple.com进行TestF...

qtb999
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部