根据mybatils拦截器实现分页以及统计某个字段的和
1.先看一下数据,这是一张地区信息的数据表
2.用的springboot框架 配置文件如下
3.mybatils配置文件如下
4.下面是拦截器的实现
package com.demo.page.page;
import com.demo.page.page.utils.ReflectHelper;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
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.mapping.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import javax.xml.bind.PropertyException;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
/**
* 类名称:分页插件 类描述:
*
* @author SM 作者单位: 修改时间:2016年2月1日
* @version 1.0
*/
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class PagePlugin implements Interceptor {
private static String pageSqlId = ""; // dao.xml中需要拦截的ID(正则匹配)
public Object intercept(Invocation ivk) throws Throwable {
if (ivk.getTarget() instanceof RoutingStatementHandler) {
RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget();
BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate");
MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement");
if (mappedStatement.getId().matches(pageSqlId)) { // 拦截需要分页的SQL
BoundSql boundSql = delegate.getBoundSql();
Object parameterObject = boundSql.getParameterObject();// 分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空
if (parameterObject == null) {
throw new NullPointerException("parameterObject尚未实例化!");
} else {
Connection connection = (Connection) ivk.getArgs()[0];
String sql = boundSql.getSql();
String fhsql = sql;
String countSql = "select count(0) from (" + fhsql + ") tmp_count"; // 记录统计
if (!(parameterObject instanceof Page)) {
throw new Exception("Mapper paramType must is Page");
}
Page page = (Page) parameterObject;
// 查询总条数
PreparedStatement countStmt = connection.prepareStatement(countSql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql, boundSql.getParameterMappings(), parameterObject);
setParameters(countStmt, mappedStatement, countBS, parameterObject);
ResultSet rs = countStmt.executeQuery();
if (rs.next()) {
page.setTotalCount(rs.getInt(1));
}
rs.close();
countStmt.close();
// 统计字段和
if (page.getField() != null) {
String sumSql = "select sum(tmp_sum." + page.getField() + ") from (" + fhsql + " limit " + page.getStartIndex() + "," + page.getShowCount() + ") tmp_sum";
PreparedStatement sumStmt = connection.prepareStatement(sumSql);
BoundSql sumBS = new BoundSql(mappedStatement.getConfiguration(), sumSql, boundSql.getParameterMappings(), parameterObject);
setParameters(sumStmt, mappedStatement, sumBS, parameterObject);
ResultSet sum = sumStmt.executeQuery();
if (sum.next()) {
page.setTotalSum(sum.getLong(1));
}
sum.close();
sumStmt.close();
}
String pageSql = sql + " limit " + page.getStartIndex() + "," + page.getShowCount();
ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); // 将分页sql语句反射回BoundSql.
}
}
}
return ivk.proceed();
}
/**
* 对SQL参数(?)设值,参考org.apache.ibatis.executor.parameter.DefaultParameterHandler
*
* @param ps
* @param mappedStatement
* @param boundSql
* @param parameterObject
* @throws SQLException
*/
private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject) throws SQLException {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
Configuration configuration = mappedStatement.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
PropertyTokenizer prop = new PropertyTokenizer(propertyName);
if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX)
&& boundSql.hasAdditionalParameter(prop.getName())) {
value = boundSql.getAdditionalParameter(prop.getName());
if (value != null) {
value = configuration.newMetaObject(value)
.getValue(propertyName.substring(prop.getName().length()));
}
} else {
value = metaObject == null ? null : metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
if (typeHandler == null) {
throw new ExecutorException("There was no TypeHandler found for parameter " + propertyName
+ " of statement " + mappedStatement.getId());
}
typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());
}
}
}
}
public Object plugin(Object arg0) {
return Plugin.wrap(arg0, this);
}
@Override
public void setProperties(Properties properties) {
pageSqlId = properties.getProperty("pageSqlId");
if (pageSqlId == null) {
try {
throw new Exception("pageSqlId cannot be null");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
5.我的测试写了一个简单的接口查询
@RequestMapping
public Page index(int page, int pageSize,String field) throws Exception {
Page page1 = new Page();
page1.setCurrentPage(page);
page1.setShowCount(pageSize);
page1.setField(field);
List<Map<String, Object>> maps = areaMapper.listPage(page1);
page1.setResult(maps);
return page1;
}
查询结果如下
这样既实现了分页和统计莫个字段和的效果
用到了一个反射工具类如下
package com.demo.page.page.utils;
import java.lang.reflect.Field;
/**
* 说明:反射工具
* 创建人:SM
* @version
*/
public class ReflectHelper {
/**
* 获取obj对象fieldName的Field
* @param obj
* @param fieldName
* @return
*/
public static Field getFieldByFieldName(Object obj, String fieldName) {
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
return superClass.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
}
}
return null;
}
/**
* 获取obj对象fieldName的属性值
* @param obj
* @param fieldName
* @return
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static Object getValueByFieldName(Object obj, String fieldName)
throws SecurityException, NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
Field field = getFieldByFieldName(obj, fieldName);
Object value = null;
if(field!=null){
if (field.isAccessible()) {
value = field.get(obj);
} else {
field.setAccessible(true);
value = field.get(obj);
field.setAccessible(false);
}
}
return value;
}
/**
* 设置obj对象fieldName的属性值
* @param obj
* @param fieldName
* @param value
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static void setValueByFieldName(Object obj, String fieldName,
Object value) throws SecurityException, NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
if (field.isAccessible()) {
field.set(obj, value);
} else {
field.setAccessible(true);
field.set(obj, value);
field.setAccessible(false);
}
}
}