java分頁(yè)攔截類實(shí)現(xiàn)sql自動(dòng)分頁(yè)
本文實(shí)例為大家分享了完整的java分頁(yè)攔截類,供大家參考,具體內(nèi)容如下
package com.opms.interceptor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
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.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.RowBounds;
import com.wifi.core.page.Page;
/**
* 通過(guò)攔截<code>StatementHandler</code>的<code>prepare</code>方法,重寫(xiě)sql語(yǔ)句實(shí)現(xiàn)物理分頁(yè)。
* 老規(guī)矩,簽名里要攔截的類型只能是接口。
*
* @author 湖畔微風(fēng)
*
*/
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class PageInterceptor implements Interceptor {
/**
* 日志
*/
private static final Log logger = LogFactory.getLog(PageInterceptor.class);
/**
* 聲明對(duì)象
*/
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
/**
* 聲明對(duì)象
*/
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
/**
* 數(shù)據(jù)庫(kù)類型(默認(rèn)為mysql)
*/
private static String defaultDialect = "mysql";
/**
* 需要攔截的ID(正則匹配)
*/
private static String defaultPageSqlId = ".*4Page$";
/**
* 數(shù)據(jù)庫(kù)類型(默認(rèn)為mysql)
*/
private static String dialect = "";
/**
* 需要攔截的ID(正則匹配)
*/
private static String pageSqlId = "";
/**
* @param invocation 參數(shù)
* @return Object
* @throws Throwable 拋出異常
*/
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY);
// 分離代理對(duì)象鏈(由于目標(biāo)類可能被多個(gè)攔截器攔截,從而形成多次代理,通過(guò)下面的兩次循環(huán)可以分離出最原始的的目標(biāo)類)
while (metaStatementHandler.hasGetter("h")) {
Object object = metaStatementHandler.getValue("h");
metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
}
// 分離最后一個(gè)代理對(duì)象的目標(biāo)類
while (metaStatementHandler.hasGetter("target")) {
Object object = metaStatementHandler.getValue("target");
metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
}
dialect=defaultDialect;pageSqlId=defaultPageSqlId;
/* Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration");
dialect = configuration.getVariables().getProperty("dialect");
if (null == dialect || "".equals(dialect)) {
logger.warn("Property dialect is not setted,use default 'mysql' ");
dialect = defaultDialect;
}
pageSqlId = configuration.getVariables().getProperty("pageSqlId");
if (null == pageSqlId || "".equals(pageSqlId)) {
logger.warn("Property pageSqlId is not setted,use default '.*Page$' ");
pageSqlId = defaultPageSqlId;
}*/
MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
// 只重寫(xiě)需要分頁(yè)的sql語(yǔ)句。通過(guò)MappedStatement的ID匹配,默認(rèn)重寫(xiě)以Page結(jié)尾的MappedStatement的sql
if (mappedStatement.getId().matches(pageSqlId)) {
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
Object parameterObject = boundSql.getParameterObject();
if (parameterObject == null) {
throw new NullPointerException("parameterObject is null!");
} else {
Object obj = metaStatementHandler
.getValue("delegate.boundSql.parameterObject.page");
// 傳入了page參數(shù)且需要開(kāi)啟分頁(yè)時(shí)
if(obj!=null&&obj instanceof Page &&((Page)obj).isPagination()){
Page page = (Page) metaStatementHandler
.getValue("delegate.boundSql.parameterObject.page");
String sql = boundSql.getSql();
// 重寫(xiě)sql
String pageSql = buildPageSql(sql, page);
metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);
// 采用物理分頁(yè)后,就不需要mybatis的內(nèi)存分頁(yè)了,所以重置下面的兩個(gè)參數(shù)
metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
Connection connection = (Connection) invocation.getArgs()[0];
// 重設(shè)分頁(yè)參數(shù)里的總頁(yè)數(shù)等
setPageParameter(sql, connection, mappedStatement, boundSql, page);
}
}
}
// 將執(zhí)行權(quán)交給下一個(gè)攔截器
return invocation.proceed();
}
/**
* 從數(shù)據(jù)庫(kù)里查詢總的記錄數(shù)并計(jì)算總頁(yè)數(shù),回寫(xiě)進(jìn)分頁(yè)參數(shù)<code>PageParameter</code>,這樣調(diào)用者就可用通過(guò) 分頁(yè)參數(shù)
* <code>PageParameter</code>獲得相關(guān)信息。
*
* @param sql 參數(shù)
* @param connection 連接
* @param mappedStatement 參數(shù)
* @param boundSql 綁定sql
* @param page 頁(yè)
*/
private void setPageParameter(String sql, Connection connection, MappedStatement mappedStatement,
BoundSql boundSql, Page page) {
// 記錄總記錄數(shù)
String countSql = "select count(0) from (" + sql + ") as total";
PreparedStatement countStmt = null;
ResultSet rs = null;
try {
countStmt = connection.prepareStatement(countSql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,
boundSql.getParameterMappings(), boundSql.getParameterObject());
setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject());
rs = countStmt.executeQuery();
int totalCount = 0;
if (rs.next()) {
totalCount = rs.getInt(1);
}
page.setTotalCount(totalCount);
page.init(page.getCurPage(), page.getPageSize(), totalCount);
} catch (SQLException e) {
logger.error("Ignore this exception", e);
} finally {
try {
rs.close();
} catch (SQLException e) {
logger.error("Ignore this exception", e);
}
try {
countStmt.close();
} catch (SQLException e) {
logger.error("Ignore this exception", e);
}
}
}
/**
* 對(duì)SQL參數(shù)(?)設(shè)值
*
* @param ps 參數(shù)
* @param mappedStatement 參數(shù)
* @param boundSql 綁定sql
* @param parameterObject 參數(shù)對(duì)象
* @throws SQLException 拋出sql異常
*/
private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject) throws SQLException {
ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler.setParameters(ps);
}
/**
* 根據(jù)數(shù)據(jù)庫(kù)類型,生成特定的分頁(yè)sql
*
* @param sql 餐宿
* @param page 頁(yè)
* @return String
*/
private String buildPageSql(String sql, Page page) {
if (page != null) {
StringBuilder pageSql = new StringBuilder();
if ("mysql".equals(dialect)) {
pageSql = buildPageSqlForMysql(sql, page);
} else if ("oracle".equals(dialect)) {
pageSql = buildPageSqlForOracle(sql, page);
} else {
return sql;
}
return pageSql.toString();
} else {
return sql;
}
}
/**
* mysql的分頁(yè)語(yǔ)句
*
* @param sql 參數(shù)
* @param page 頁(yè)
* @return String
*/
public StringBuilder buildPageSqlForMysql(String sql, Page page) {
StringBuilder pageSql = new StringBuilder(100);
String beginrow = String.valueOf((page.getCurPage() - 1) * page.getPageSize());
pageSql.append(sql);
pageSql.append(" limit " + beginrow + "," + page.getPageSize());
return pageSql;
}
/**
* 參考hibernate的實(shí)現(xiàn)完成oracle的分頁(yè)
*
* @param sql 參數(shù)
* @param page 參數(shù)
* @return String
*/
public StringBuilder buildPageSqlForOracle(String sql, Page page) {
StringBuilder pageSql = new StringBuilder(100);
String beginrow = String.valueOf((page.getCurPage() - 1) * page.getPageSize());
String endrow = String.valueOf(page.getCurPage() * page.getPageSize());
pageSql.append("select * from ( select temp.*, rownum row_id from ( ");
pageSql.append(sql);
pageSql.append(" ) temp where rownum <= ").append(endrow);
pageSql.append(") where row_id > ").append(beginrow);
return pageSql;
}
/**
* @param target 參數(shù)
* @return Object
*/
public Object plugin(Object target) {
// 當(dāng)目標(biāo)類是StatementHandler類型時(shí),才包裝目標(biāo)類,否者直接返回目標(biāo)本身,減少目標(biāo)被代理的次數(shù)
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
/**
* @param properties 參數(shù)
*/
public void setProperties(Properties properties) {
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java分頁(yè)工具類的使用方法
- Java分頁(yè)工具類及其使用(示例分享)
- 淺談java分頁(yè)三個(gè)類 PageBean ResponseUtil StringUtil
- 一個(gè)通用的Java分頁(yè)基類代碼詳解
- Java Web 簡(jiǎn)單的分頁(yè)顯示實(shí)例代碼
- Java簡(jiǎn)單實(shí)現(xiàn)SpringMVC+MyBatis分頁(yè)插件
- 舉例詳解用Java實(shí)現(xiàn)web分頁(yè)功能的方法
- 使用Jquery+Ajax+Json如何實(shí)現(xiàn)分頁(yè)顯示附JAVA+JQuery實(shí)現(xiàn)異步分頁(yè)
- java中利用List的subList方法實(shí)現(xiàn)對(duì)List分頁(yè)(簡(jiǎn)單易學(xué))
- jsp+servlet+javabean實(shí)現(xiàn)數(shù)據(jù)分頁(yè)方法完整實(shí)例
- Java實(shí)現(xiàn)的分頁(yè)工具類與用法示例
相關(guān)文章
SpringBoot項(xiàng)目的測(cè)試類實(shí)例解析
這篇文章主要介紹了SpringBoot項(xiàng)目的測(cè)試類實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
Java老手該當(dāng)心的13個(gè)錯(cuò)誤
這篇文章主要介紹了Java老手該當(dāng)心的13個(gè)錯(cuò)誤,需要的朋友可以參考下2015-04-04
深入理解MyBatis中的一級(jí)緩存與二級(jí)緩存
這篇文章主要給大家深入的介紹了關(guān)于MyBatis中一級(jí)緩存與二級(jí)緩存的相關(guān)資料,文中詳細(xì)介紹MyBatis中一級(jí)緩存與二級(jí)緩存的工作原理及使用,對(duì)大家具有一定的參考性學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-06-06
Java實(shí)現(xiàn)高校教務(wù)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)高校教務(wù)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
java使用htmlparser提取網(wǎng)頁(yè)純文本例子
這篇文章主要介紹了java使用htmlparser提取網(wǎng)頁(yè)純文本例子,需要的朋友可以參考下2014-04-04
SpringBoot各種參數(shù)校驗(yàn)的實(shí)例教程
經(jīng)常需要提供接口與用戶交互(獲取數(shù)據(jù)、上傳數(shù)據(jù)等),由于這個(gè)過(guò)程需要用戶進(jìn)行相關(guān)的操作,為了避免出現(xiàn)一些錯(cuò)誤的數(shù)據(jù)等,一般需要對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),下面這篇文章主要給大家介紹了關(guān)于SpringBoot各種參數(shù)校驗(yàn)的相關(guān)資料,需要的朋友可以參考下2022-03-03
詳解Spring MVC如何測(cè)試Controller(使用springmvc mock測(cè)試)
這篇文章主要介紹了詳解Spring MVC如何測(cè)試Controller(使用springmvc mock測(cè)試),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12

