java分页拦截类实现sql自动分页
本文实例为大家分享了完整的java分页拦截类,供大家参考,具体内容如下
packagecom.opms.interceptor;
importjava.sql.Connection;
importjava.sql.PreparedStatement;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.util.Properties;
importorg.apache.ibatis.executor.parameter.ParameterHandler;
importorg.apache.ibatis.executor.statement.StatementHandler;
importorg.apache.ibatis.logging.Log;
importorg.apache.ibatis.logging.LogFactory;
importorg.apache.ibatis.mapping.BoundSql;
importorg.apache.ibatis.mapping.MappedStatement;
importorg.apache.ibatis.plugin.Interceptor;
importorg.apache.ibatis.plugin.Intercepts;
importorg.apache.ibatis.plugin.Invocation;
importorg.apache.ibatis.plugin.Plugin;
importorg.apache.ibatis.plugin.Signature;
importorg.apache.ibatis.reflection.MetaObject;
importorg.apache.ibatis.reflection.factory.DefaultObjectFactory;
importorg.apache.ibatis.reflection.factory.ObjectFactory;
importorg.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
importorg.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
importorg.apache.ibatis.scripting.defaults.DefaultParameterHandler;
importorg.apache.ibatis.session.RowBounds;
importcom.wifi.core.page.Page;
/**
*通过拦截<code>StatementHandler</code>的<code>prepare</code>方法,重写sql语句实现物理分页。
*老规矩,签名里要拦截的类型只能是接口。
*
*@author湖畔微风
*
*/
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
publicclassPageInterceptorimplementsInterceptor{
/**
*日志
*/
privatestaticfinalLoglogger=LogFactory.getLog(PageInterceptor.class);
/**
*声明对象
*/
privatestaticfinalObjectFactoryDEFAULT_OBJECT_FACTORY=newDefaultObjectFactory();
/**
*声明对象
*/
privatestaticfinalObjectWrapperFactoryDEFAULT_OBJECT_WRAPPER_FACTORY=newDefaultObjectWrapperFactory();
/**
*数据库类型(默认为mysql)
*/
privatestaticStringdefaultDialect="mysql";
/**
*需要拦截的ID(正则匹配)
*/
privatestaticStringdefaultPageSqlId=".*4Page$";
/**
*数据库类型(默认为mysql)
*/
privatestaticStringdialect="";
/**
*需要拦截的ID(正则匹配)
*/
privatestaticStringpageSqlId="";
/**
*@paraminvocation参数
*@returnObject
*@throwsThrowable抛出异常
*/
publicObjectintercept(Invocationinvocation)throwsThrowable{
StatementHandlerstatementHandler=(StatementHandler)invocation.getTarget();
MetaObjectmetaStatementHandler=MetaObject.forObject(statementHandler,DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY);
//分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环可以分离出最原始的的目标类)
while(metaStatementHandler.hasGetter("h")){
Objectobject=metaStatementHandler.getValue("h");
metaStatementHandler=MetaObject.forObject(object,DEFAULT_OBJECT_FACTORY,DEFAULT_OBJECT_WRAPPER_FACTORY);
}
//分离最后一个代理对象的目标类
while(metaStatementHandler.hasGetter("target")){
Objectobject=metaStatementHandler.getValue("target");
metaStatementHandler=MetaObject.forObject(object,DEFAULT_OBJECT_FACTORY,DEFAULT_OBJECT_WRAPPER_FACTORY);
}
dialect=defaultDialect;pageSqlId=defaultPageSqlId;
/*Configurationconfiguration=(Configuration)metaStatementHandler.getValue("delegate.configuration");
dialect=configuration.getVariables().getProperty("dialect");
if(null==dialect||"".equals(dialect)){
logger.warn("Propertydialectisnotsetted,usedefault'mysql'");
dialect=defaultDialect;
}
pageSqlId=configuration.getVariables().getProperty("pageSqlId");
if(null==pageSqlId||"".equals(pageSqlId)){
logger.warn("PropertypageSqlIdisnotsetted,usedefault'.*Page$'");
pageSqlId=defaultPageSqlId;
}*/
MappedStatementmappedStatement=(MappedStatement)metaStatementHandler.getValue("delegate.mappedStatement");
//只重写需要分页的sql语句。通过MappedStatement的ID匹配,默认重写以Page结尾的MappedStatement的sql
if(mappedStatement.getId().matches(pageSqlId)){
BoundSqlboundSql=(BoundSql)metaStatementHandler.getValue("delegate.boundSql");
ObjectparameterObject=boundSql.getParameterObject();
if(parameterObject==null){
thrownewNullPointerException("parameterObjectisnull!");
}else{
Objectobj=metaStatementHandler
.getValue("delegate.boundSql.parameterObject.page");
//传入了page参数且需要开启分页时
if(obj!=null&&objinstanceofPage&&((Page)obj).isPagination()){
Pagepage=(Page)metaStatementHandler
.getValue("delegate.boundSql.parameterObject.page");
Stringsql=boundSql.getSql();
//重写sql
StringpageSql=buildPageSql(sql,page);
metaStatementHandler.setValue("delegate.boundSql.sql",pageSql);
//采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数
metaStatementHandler.setValue("delegate.rowBounds.offset",RowBounds.NO_ROW_OFFSET);
metaStatementHandler.setValue("delegate.rowBounds.limit",RowBounds.NO_ROW_LIMIT);
Connectionconnection=(Connection)invocation.getArgs()[0];
//重设分页参数里的总页数等
setPageParameter(sql,connection,mappedStatement,boundSql,page);
}
}
}
//将执行权交给下一个拦截器
returninvocation.proceed();
}
/**
*从数据库里查询总的记录数并计算总页数,回写进分页参数<code>PageParameter</code>,这样调用者就可用通过分页参数
*<code>PageParameter</code>获得相关信息。
*
*@paramsql参数
*@paramconnection连接
*@parammappedStatement参数
*@paramboundSql绑定sql
*@parampage页
*/
privatevoidsetPageParameter(Stringsql,Connectionconnection,MappedStatementmappedStatement,
BoundSqlboundSql,Pagepage){
//记录总记录数
StringcountSql="selectcount(0)from("+sql+")astotal";
PreparedStatementcountStmt=null;
ResultSetrs=null;
try{
countStmt=connection.prepareStatement(countSql);
BoundSqlcountBS=newBoundSql(mappedStatement.getConfiguration(),countSql,
boundSql.getParameterMappings(),boundSql.getParameterObject());
setParameters(countStmt,mappedStatement,countBS,boundSql.getParameterObject());
rs=countStmt.executeQuery();
inttotalCount=0;
if(rs.next()){
totalCount=rs.getInt(1);
}
page.setTotalCount(totalCount);
page.init(page.getCurPage(),page.getPageSize(),totalCount);
}catch(SQLExceptione){
logger.error("Ignorethisexception",e);
}finally{
try{
rs.close();
}catch(SQLExceptione){
logger.error("Ignorethisexception",e);
}
try{
countStmt.close();
}catch(SQLExceptione){
logger.error("Ignorethisexception",e);
}
}
}
/**
*对SQL参数(?)设值
*
*@paramps参数
*@parammappedStatement参数
*@paramboundSql绑定sql
*@paramparameterObject参数对象
*@throwsSQLException抛出sql异常
*/
privatevoidsetParameters(PreparedStatementps,MappedStatementmappedStatement,BoundSqlboundSql,
ObjectparameterObject)throwsSQLException{
ParameterHandlerparameterHandler=newDefaultParameterHandler(mappedStatement,parameterObject,boundSql);
parameterHandler.setParameters(ps);
}
/**
*根据数据库类型,生成特定的分页sql
*
*@paramsql餐宿
*@parampage页
*@returnString
*/
privateStringbuildPageSql(Stringsql,Pagepage){
if(page!=null){
StringBuilderpageSql=newStringBuilder();
if("mysql".equals(dialect)){
pageSql=buildPageSqlForMysql(sql,page);
}elseif("oracle".equals(dialect)){
pageSql=buildPageSqlForOracle(sql,page);
}else{
returnsql;
}
returnpageSql.toString();
}else{
returnsql;
}
}
/**
*mysql的分页语句
*
*@paramsql参数
*@parampage页
*@returnString
*/
publicStringBuilderbuildPageSqlForMysql(Stringsql,Pagepage){
StringBuilderpageSql=newStringBuilder(100);
Stringbeginrow=String.valueOf((page.getCurPage()-1)*page.getPageSize());
pageSql.append(sql);
pageSql.append("limit"+beginrow+","+page.getPageSize());
returnpageSql;
}
/**
*参考hibernate的实现完成oracle的分页
*
*@paramsql参数
*@parampage参数
*@returnString
*/
publicStringBuilderbuildPageSqlForOracle(Stringsql,Pagepage){
StringBuilderpageSql=newStringBuilder(100);
Stringbeginrow=String.valueOf((page.getCurPage()-1)*page.getPageSize());
Stringendrow=String.valueOf(page.getCurPage()*page.getPageSize());
pageSql.append("select*from(selecttemp.*,rownumrow_idfrom(");
pageSql.append(sql);
pageSql.append(")tempwhererownum<=").append(endrow);
pageSql.append(")whererow_id>").append(beginrow);
returnpageSql;
}
/**
*@paramtarget参数
*@returnObject
*/
publicObjectplugin(Objecttarget){
//当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数
if(targetinstanceofStatementHandler){
returnPlugin.wrap(target,this);
}else{
returntarget;
}
}
/**
*@paramproperties参数
*/
publicvoidsetProperties(Propertiesproperties){
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。