package dong.interceptor.mapper;
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.Map;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.ParameterHandler;
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 org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import dong.interceptor.BaseInterceptor;
import dong.util.Page;
/**
*
* 分页拦截器,用于拦截需要进行分页查询的操作,然后对其进行分页处理。
* 利用拦截器实现Mybatis分页的原理:
* 要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象,Mybatis在执行Sql语句前就会产生一个包含Sql语句的Statement对象,而且对应的Sql语句
* 是在Statement之前产生的,所以我们就可以在它生成Statement之前对用来生成Statement的Sql语句下手。在Mybatis中Statement语句是通过RoutingStatementHandler对象的
* prepare方法生成的。所以利用拦截器实现Mybatis分页的一个思路就是拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用
* StatementHandler对象的prepare方法,即调用invocation.proceed()。
* 对于分页而言,在拦截器里面我们还需要做的一个操作就是统计满足当前条件的记录一共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利用Mybatis封装好的参数和设
* 置参数的功能把Sql语句中的参数进行替换,之后再执行查询记录数的Sql语句进行总记录数的统计。
*
*/
@Intercepts( {
@Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class}) })
public class PageInterceptor extends BaseInterceptor implements Interceptor {
private String databaseType;//数据库类型,不同的数据库有不同的分页方法
/**
* 拦截后要执行的方法
*/
public Object intercept(Invocation invocation) throws Throwable {
//对于StatementHandler其实只有两个实现类,一个是RoutingStatementHandler,另一个是抽象类BaseStatementHandler,
//BaseStatementHandler有三个子类,分别是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler,
//SimpleStatementHandler是用于处理Statement的,PreparedStatementHandler是处理PreparedStatement的,而CallableStatementHandler是
//处理CallableStatement的。Mybatis在进行Sql语句处理的时候都是建立的RoutingStatementHandler,而在RoutingStatementHandler里面拥有一个
//StatementHandler类型的delegate属性,RoutingStatementHandler会依据Statement的不同建立对应的BaseStatementHandler,即SimpleStatementHandler、
//PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler里面所有StatementHandler接口方法的实现都是调用的delegate对应的方法。
//我们在PageInterceptor类上已经用@Signature标记了该Interceptor只拦截StatementHandler接口的prepare方法,又因为Mybatis只有在建立RoutingStatementHandler的时候
//是通过Interceptor的plugin方法进行包裹的,所以我们这里拦截到的目标对象肯定是RoutingStatementHandler对象。
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
//通过反射获取到当前RoutingStatementHandler对象的delegate属性
StatementHandler delegate = (StatementHandler)ReflectUtil.getFieldValue(handler, "delegate");
//获取到当前StatementHandler的 boundSql,这里不管是调用handler.getBoundSql()还是直接调用delegate.getBoundSql()结果是一样的,因为之前已经说过了
//RoutingStatementHandler实现的所有StatementHandler接口方法里面都是调用的delegate对应的方法。
BoundSql boundSql = delegate.getBoundSql();
//拿到当前绑定Sql的参数对象,就是我们在调用对应的Mapper映射语句时所传入的参数对象
Object obj = boundSql.getParameterObject();
//这里我们简单的通过传入的是Page对象就认定它是需要进行分页操作的。
if (obj instanceof Map) {
if(((Map)(obj)).get("page") != null && ((Map)(obj)).get("page") instanceof Page){
Map<String,Object> map = ((Map)(obj));
Page page = (Page)map.get("page");
//通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
MappedStatement mappedStatement = (MappedStatement)ReflectUtil.getFieldValue(delegate, "mappedStatement");
//拦截到的prepare方法参数是一个Connection对象
Connection connection = (Connection)invocation.getArgs()[0];
//获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句
String sql = boundSql.getSql();
//给当前的page参数对象设置总记录数
this.setTotalRecord(page,map,
mappedStatement, connection);
if(page.getPageSize()>page.getTotalRecord()){//当每页显示的条数大于记录总条数时,设置为第一页
page.setPageNo(1);
}
//获取分页Sql语句
String pageSql = this.getPageSql(page, sql);
//利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句
ReflectUtil.setFieldValue(boundSql, "sql", pageSql);
}
}
return invocation.proceed();
}
/**
* 拦截器对应的封装原始对象的方法
*/
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
/**
* 设置注册拦截器时设定的属性
*/
public void setProperties(Properties properties) {
this.databaseType = properties.getProperty("databaseType");
}
/**
* 根据page对象获取对应的分页查询Sql语句,这里只做了两种数据库类型,Mysql和Oracle
* 其它的数据库都 没有进行分页
*
* @param page 分页对象
* @param sql 原sql语句
* @return
*/
private String getPageSql(Page page, String sql) {
StringBuffer sqlBuffer = new StringBuffer(sql);
if ("mysql".equalsIgnoreCase(databaseType)) {
return getMysqlPageSql(page, sqlBuffer);
} else if ("oracle".equalsIgnoreCase(databaseType)) {
return getOraclePageSql(page, sqlBuffer);
}
return sqlBuffer.toString();
}
/**
* 获取Mysql数据库的分页查询语句
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Mysql数据库分页语句
*/
private String getMysqlPageSql(Page page, StringBuffer sqlBuffer) {
//计算第一条记录的位置,Mysql中记录的位置是从0开始的。
int offset = (page.getPageNo() - 1) * page.getPageSize();
sqlBuffer.append(" limit ").append(
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
extjs+springmvc+dubbo+mybatis+oracle (1792个子文件)
all-wcprops 13KB
all-wcprops 7KB
all-wcprops 6KB
all-wcprops 5KB
all-wcprops 5KB
all-wcprops 4KB
all-wcprops 4KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 3KB
all-wcprops 2KB
all-wcprops 2KB
all-wcprops 2KB
all-wcprops 2KB
all-wcprops 2KB
all-wcprops 2KB
all-wcprops 2KB
all-wcprops 2KB
all-wcprops 1KB
all-wcprops 1KB
all-wcprops 1KB
all-wcprops 1KB
all-wcprops 1KB
all-wcprops 1KB
all-wcprops 1KB
all-wcprops 1KB
all-wcprops 1KB
all-wcprops 888B
all-wcprops 872B
all-wcprops 828B
all-wcprops 691B
all-wcprops 678B
all-wcprops 675B
all-wcprops 670B
all-wcprops 664B
all-wcprops 653B
all-wcprops 649B
all-wcprops 638B
all-wcprops 635B
all-wcprops 616B
all-wcprops 496B
all-wcprops 488B
all-wcprops 464B
all-wcprops 450B
all-wcprops 442B
all-wcprops 386B
all-wcprops 203B
all-wcprops 201B
all-wcprops 192B
all-wcprops 183B
all-wcprops 183B
PageInterceptor.class 7KB
CompanyController.class 5KB
DepartmentController.class 4KB
ControllerInterceptor.class 3KB
MainController.class 3KB
BaseController.class 3KB
CommonDao.class 3KB
LoginController.class 3KB
BaseControllerInterceptor.class 3KB
CompanyDao.class 2KB
BaseBean.class 2KB
DepartmentDao.class 2KB
CompanyServiceImpl.class 2KB
Page.class 2KB
PageInterceptor$ReflectUtil.class 2KB
MainDao.class 2KB
UserController.class 2KB
Page.class 2KB
DepartmentServiceImpl.class 2KB
CommonController.class 2KB
UserDao.class 2KB
ParameterRequestWrapper.class 2KB
DictionaryDao.class 2KB
SQLParameterInterceptor.class 2KB
EmployeeController.class 1KB
UserServiceImpl.class 1KB
JobController.class 1KB
MainServiceImpl.class 1KB
EmployeeDao.class 1KB
JobDao.class 1KB
UserInThreadLocal.class 1KB
LoginServiceImpl.class 1KB
DictionaryServiceImpl.class 1KB
CompanyService.class 1KB
CompanyService.class 1KB
LoginDao.class 1001B
IBean.class 998B
CompanyMapper.class 961B
DepartmentService.class 907B
DepartmentService.class 907B
CommonServiceImpl.class 904B
共 1792 条
- 1
- 2
- 3
- 4
- 5
- 6
- 18
资源评论
woshiliulidiyi
- 粉丝: 7
- 资源: 52
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功