norm.support.mybatis.page.PagePlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of norm Show documentation
Show all versions of norm Show documentation
a small java orm library.
package norm.support.mybatis.page;
import norm.page.Filter;
import norm.page.Page;
import norm.page.PageSql;
import norm.page.impl.*;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.*;
import java.util.*;
/**
* MyBatis的分页插件,放在这里给大家使用
*/
public class PagePlugin implements Interceptor{
private static Map pageSqlMap = new HashMap();
private String database;
public static void registerPageSql(PageSql pageSql){
if(pageSql == null){
throw new IllegalArgumentException();
}
String db = pageSql.database();
if(db == null){
throw new PluginException("the database of pagesql is null!");
}
pageSqlMap.put(db.toLowerCase(),pageSql);
}
static {
registerPageSql(new Db2Page());
registerPageSql(new DerbyPage());
registerPageSql(new H2Page());
registerPageSql(new MySQLPage());
registerPageSql(new OraclePage());
registerPageSql(new PostgreSQLPage());
registerPageSql(new SQLServerPage());
}
@Override
public Object intercept(Invocation invocation) throws Throwable {
Page page = PageHelper.getPage();
if(page == null){
return invocation.proceed();
}
if(invocation.getTarget() instanceof StatementHandler){
StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
// 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环
// 可以分离出最原始的的目标类)
while (metaStatementHandler.hasGetter("h")) {
Object object = metaStatementHandler.getValue("h");
metaStatementHandler = SystemMetaObject.forObject(object);
}
// 分离最后一个代理对象的目标类
while (metaStatementHandler.hasGetter("target")) {
Object object = metaStatementHandler.getValue("target");
metaStatementHandler = SystemMetaObject.forObject(object);
}
MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
Filter filter = PageHelper.getFilter();
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
String sql = boundSql.getSql();
if(sql.toLowerCase().startsWith("select") && (filter == null || filter.accept((StatementHandler) metaStatementHandler.getValue("delegate")))){
String pageSql = this.buildPageSql(page,sql);
//重写分页sql
metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);
//计算page count
this.evalPageCount(sql, invocation, mappedStatement, boundSql, page);
}
return invocation.proceed();
}else if(invocation.getTarget() instanceof ResultSetHandler){
Object result = invocation.proceed();
if(page.isCollectResult()){
page.setResult(result);
}
return result;
}
//如果抛出这个异常 你可以去买彩票了
throw new IllegalStateException("invocation error!");
}
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler || target instanceof ResultSetHandler) {
Class> type = target.getClass();
Map, Set> signatureMap = getSignatureMap(type);
Class>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, this, signatureMap));
}
}
return target;
}
@Override
public void setProperties(Properties properties) {
String database = properties.getProperty("database");
if(database == null || database.isEmpty()){
throw new RuntimeException("null database property!");
}
this.database = database;
}
private String buildPageSql(Page page,String sql){
PageSql pageSql = pageSqlMap.get(this.database.toLowerCase());
if(pageSql == null){
throw new PluginException("not support database :" + this.database);
}
return pageSql.buildSql(page,sql);
}
private void evalPageCount(String sql, Invocation invocation, MappedStatement mappedStatement,
BoundSql boundSql, Page page){
if(page.isEvalCount()){
String countSql = "select count(1) from ( " + sql + " )";
Connection connection = (Connection) invocation.getArgs()[0];
PreparedStatement ps = null;
ResultSet rs = null;
try{
ps = connection.prepareStatement(countSql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,
boundSql.getParameterMappings(), boundSql.getParameterObject());
setParameters(ps, mappedStatement, countBS, boundSql.getParameterObject());
rs = ps.executeQuery();
int totalCount = 0;
if (rs.next()) {
totalCount = rs.getInt(1);
}
page.setTotal(totalCount);
int pageSize = page.getPageSize();
page.setPageCount(totalCount / pageSize + ((totalCount % pageSize == 0) ? 0 : 1));
}catch (SQLException e){
throw new PersistenceException("eval page count error.sql:" + countSql,e);
}finally {
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
}
}
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
}
}
}
}
}
private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject) throws SQLException {
ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler.setParameters(ps);
}
//这里跟mybatis原生的Plugin.wrap方法原理类似,不过这里是采取手动代理的方式,而不是采取注解
//这样,可兼容mybatis所有版本,具体参考mybatis中Plugin类的源码
private Map, Set> getSignatureMap(Class> type){
Map, Set> signatureMap = new HashMap, Set>();
//处理StatementHandler prepare方法
handleMethodSet(signatureMap,StatementHandler.class,"prepare");
//处理ResultSetHandler handleResultSets方法
handleMethodSet(signatureMap,ResultSetHandler.class,"handleResultSets");
return signatureMap;
}
private static void handleMethodSet(Map, Set> signatureMap,Class> type,String methodName){
Method[] methods = type.getDeclaredMethods();
Set set = new HashSet();
for(Method method : methods){
if(method.getName().equals(methodName)){
set.add(method);
}
}
if(set.isEmpty()){
throw new PluginException("no such method on [" + type + "] name:" + methodName);
}
signatureMap.put(type,set);
}
private static Class>[] getAllInterfaces(Class> type, Map, Set> signatureMap) {
Set> interfaces = new HashSet>();
while (type != null) {
for (Class> c : type.getInterfaces()) {
if (signatureMap.containsKey(c)) {
interfaces.add(c);
}
}
type = type.getSuperclass();
}
return interfaces.toArray(new Class>[interfaces.size()]);
}
private static class Plugin implements InvocationHandler {
private final Object target;
private final Interceptor interceptor;
private final Map, Set> signatureMap;
public Plugin(Object target, Interceptor interceptor, Map, Set> signatureMap) {
this.target = target;
this.interceptor = interceptor;
this.signatureMap = signatureMap;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy