##实现环境 Spring + Mybatis + MySQL ##实现原理 分页拦截器,主要是对参数中含有Page对象的函数进行分页处理,主要利用拦截器拦截到当前带有Page对象作为参数的方法,获取到Connection,StateMent,以及执行的SQL,进一步进行操作,实现获取总页数,结果的一种方式 ##实现代码
-
工具类
使用反射机制,获取对象中的属性,和设置属性值
代码如下:ReflectUtil.java
import java.lang.reflect.Field; /**
-
Desc : TODO Author: 山野痞夫 Date : 2015年8月25日 Time: : 上午9:56:23 / public class ReflectUtil { /*
- 利用反射获取指定对象的指定属性
- @param obj 目标对象
- @param fieldName 目标属性
- @return 目标属性的值 */ public static Object getFieldValue(Object obj, String fieldName) { Object result = null; final Field field = ReflectUtil.getField(obj, fieldName); if (field != null) { field.setAccessible(true); try { result = field.get(obj); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return result; }
/**
- 利用反射获取指定对象里面的指定属性
- @param obj目标对象
- @param fieldName 目标属性
- @return 目标字段 */ private static Field getField(Object obj, String fieldName) { Field field = null; for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) { try { field = clazz.getDeclaredField(fieldName); break; } catch (NoSuchFieldException e) { e.printStackTrace(); } } return field; }
/**
- 利用反射设置指定对象的指定属性为指定的值
- @param obj 目标对象
- @param fieldName目标属性
- @param fieldValue 目标值 */ public static void setFieldValue(Object obj, String fieldName, String fieldValue) { final Field field = ReflectUtil.getField(obj, fieldName); if (field != null) { try { field.setAccessible(true); field.set(obj, fieldValue); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } }
-
-
拦截器的实现类
实现拦截器接口
代码如下:SpringMybatisPageInterceptor.java
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.ibatis.executor.statement.RoutingStatementHandler; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; 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 com.icaopan.util.ReflectUtil; /**
-
Desc : Mybatis分页拦截器 Author: 山野痞夫 Date : 2015年8月25日 Time: : 下午4:14:14 */ @Intercepts({ @Signature(method = "prepare", type = StatementHandler.class, args = { Connection.class }) }) public class SpringMybatisPageInterceptor implements Interceptor {
/** 拦截器 */ public Object intercept(Invocation invocation) throws Throwable { //拦截执行的Handler final RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget(); //获取分页拦截器必要的参数 final StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate"); //获取执行的SQL final BoundSql boundSql = delegate.getBoundSql(); //获取执行的参数 final Object obj = boundSql.getParameterObject(); //获取StateMent final MappedStatement mappedStatement=(MappedStatement)ReflectUtil.getFieldValue(delegate, "mappedStatement"); //判断参数是否有Page参数,如果有则按照 if (obj instanceof Page) { Page resultPage = new Page(); final Page page = (Page) obj; final String sql = boundSql.getSql(); //计算总的条目数 final String countSQL = getMysqlCountSql(new StringBuffer(sql)); int totalCount = getCounts(mappedStatement, countSQL ,boundSql,page); //获取分页后的结果 final String pageSql = this.getMysqlPageSql(page, new StringBuffer(sql)); ReflectUtil.setFieldValue(boundSql, "sql", pageSql); page.setTotal(totalCount); } return invocation.proceed();
}
/** 定义使用的拦截器 */ public Object plugin(Object obj) { return Plugin.wrap(obj, this); }
/** 获取属性信息 */ public void setProperties(Properties properties) {
}
/**
- 组装分页SQL
- @param page 分页javaBean
- @param sqlBuffer 组装好的分页SQL
- @return */ private String getMysqlPageSql(Page page, StringBuffer sqlBuffer) { sqlBuffer.append(" limit ").append(page.getLimitStart()).append(",").append(page.getLimitend()); return sqlBuffer.toString(); }
/**
- 组装查询数量的SQL
- @param sqlBuffer 组装好的分页SQL
- @return / private String getMysqlCountSql(StringBuffer sqlBuffer) { StringBuffer buffer = new StringBuffer(); buffer.append("select count() from ("); buffer.append(sqlBuffer); buffer.append(") as total"); return buffer.toString(); }
/**
- 获取总页数
- @param mappedStatement
- @param countSQL
- @return */ private int getCounts(MappedStatement mappedStatement, String countSQL ,BoundSql boundSql , Page page) { final ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, page, boundSql); Connection connection = null; ResultSet rs = null; PreparedStatement countStmt = null; int totpage = 0; try { //获取连接 connection = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection(); //预处理SQL countStmt = connection.prepareStatement(countSQL); //给预处理SQL 赋值 parameterHandler.setParameters(countStmt); //查询预处理的SQL rs = countStmt.executeQuery(); if (rs.next()) { totpage = rs.getInt(1); } } catch (SQLException e) { e.printStackTrace(); } finally { //关闭释放资源 try { if(rs!=null)rs.close(); if(countStmt!=null)countStmt.close(); if(connection!=null)connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return totpage; } }
-
-
Spring文件配置
<!-- 此处替换成自己的包地址 -->
<bean id="statementHandlerInterceptor" class="com.*.page.SpringMybatisPageInterceptor" /> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 , web数据库 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自动扫描mapping.xml文件 --> <property name="mapperLocations" value="classpath:web/*/*.xml"></property> <!-- 加载分页插件 --> <property name="plugins"> <array> <ref local="statementHandlerInterceptor" /> </array> </property> </bean>
-
Page代码
import java.util.List; import java.util.Map; /** * @Title: page.java * @Package com.icaopan.page * @Description: TODO(分页参数) * @author 山野痞夫 * @date 2015年6月13日 下午2:24:52 * @version V1.0 */ public class Page { private int current = 1; //当前页 private int rowCount = 10;//页数 @SuppressWarnings("rawtypes") private List rows; //查询出来的数据 private Map<String,Object> params; //参数 private int limitend; //计算后的结束页 public int getCurrent() { return current; } public void setCurrent(int current) { this.current = current; } public int getRowCount() { return rowCount; } public void setRowCount(int rowCount) { this.rowCount = rowCount; } public List getRows() { return rows; } public void setRows(List rows) { this.rows = rows; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public int getLimitStart() { return (current-1)*rowCount; } public void setLimitStart(int limitStart) { this.limitStart = limitStart; } public int getLimitend() { return rowCount; } public void setLimitend(int limitend) { this.limitend = limitend; } public Map<String, Object> getParams() { return params; } public void setParams(Map<String, Object> params) { this.params = params; } }
##后记 1.在拦截器实现中有的地方比较挫,希望大家进行指正。 2.个人邮箱:ifaxin@yeah.net ##附件 源代码