|
@@ -0,0 +1,366 @@
|
|
|
|
+package com.minpay.db;
|
|
|
|
+
|
|
|
|
+import java.lang.reflect.Field;
|
|
|
|
+import java.lang.reflect.InvocationTargetException;
|
|
|
|
+import java.lang.reflect.Method;
|
|
|
|
+import java.lang.reflect.Modifier;
|
|
|
|
+import java.sql.Connection;
|
|
|
|
+import java.sql.PreparedStatement;
|
|
|
|
+import java.sql.ResultSet;
|
|
|
|
+import java.util.Properties;
|
|
|
|
+import java.util.Stack;
|
|
|
|
+
|
|
|
|
+import org.apache.commons.lang.reflect.FieldUtils;
|
|
|
|
+import org.apache.ibatis.executor.statement.PreparedStatementHandler;
|
|
|
|
+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.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 org.apache.ibatis.session.Configuration;
|
|
|
|
+import org.apache.ibatis.session.SqlSession;
|
|
|
|
+
|
|
|
|
+import com.startup.minpay.frame.exception.MINRuntimeException;
|
|
|
|
+import com.startup.minpay.frame.jdbc.MINRowBounds;
|
|
|
|
+import com.startup.minpay.frame.jdbc.MINTransaction;
|
|
|
|
+import com.startup.minpay.frame.jdbc.dialet.Dialect;
|
|
|
|
+import com.startup.minpay.util.Env;
|
|
|
|
+
|
|
|
|
+@Intercepts({
|
|
|
|
+ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
|
|
|
|
+public class StatementInterceptor implements Interceptor {
|
|
|
|
+ private static final String OracleDialect = "com.startup.minpay.frame.jdbc.dialet.OracleDialect";
|
|
|
|
+ private static final String MySQLDIALECT = "com.startup.minpay.frame.jdbc.dialet.MySQLDialect";
|
|
|
|
+
|
|
|
|
+ private enum DialectType {
|
|
|
|
+ Oracle("Oracle"), MySQL("MySQL");
|
|
|
|
+ String value;
|
|
|
|
+
|
|
|
|
+ DialectType(String value) {
|
|
|
|
+ this.value = value;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public Object intercept(Invocation invocation) throws Throwable {
|
|
|
|
+ int page = 0;
|
|
|
|
+ SqlSession session = null;
|
|
|
|
+ Stack<MINTransaction> transaction = (Stack<MINTransaction>) Env.getThreadEnv("MINDatabaseSession");
|
|
|
|
+ session = ((MINTransaction) transaction.peek()).getSession();
|
|
|
|
+ Connection connection = session.getConnection();
|
|
|
|
+ Configuration config = session.getConfiguration();
|
|
|
|
+
|
|
|
|
+ RoutingStatementHandler statement = (RoutingStatementHandler) invocation.getTarget();
|
|
|
|
+ Object o = MINReflectUtil.getFieldValue(statement, "delegate");
|
|
|
|
+
|
|
|
|
+ BoundSql boundSql = statement.getBoundSql();
|
|
|
|
+ String sql = boundSql.getSql();
|
|
|
|
+
|
|
|
|
+ if (o instanceof PreparedStatementHandler) {
|
|
|
|
+ PreparedStatementHandler handler = (PreparedStatementHandler) MINReflectUtil.getFieldValue(statement, "delegate");
|
|
|
|
+ Object rows = MINReflectUtil.getFieldValue(handler, "rowBounds");
|
|
|
|
+
|
|
|
|
+ if (rows instanceof MINRowBounds) {
|
|
|
|
+ MINRowBounds rowBounds = (MINRowBounds) rows;
|
|
|
|
+
|
|
|
|
+ if (rowBounds.getLimit() > 0 && rowBounds.getLimit() < Integer.MAX_VALUE) {
|
|
|
|
+
|
|
|
|
+ String DIALECT = null;
|
|
|
|
+ try {
|
|
|
|
+ String countSql = "";
|
|
|
|
+
|
|
|
|
+ if (rowBounds.isSeparateSql()) {
|
|
|
|
+ if (rowBounds.getCountSql() != null && !"".equals(rowBounds.getCountSql())) {
|
|
|
|
+ countSql = rowBounds.getCountSql();
|
|
|
|
+ } else {
|
|
|
|
+ countSql = getCountSql(sql);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ countSql = "select count(1) from (" + sql + ") b";
|
|
|
|
+// countSql = getCountSql(sql);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Object parameterObject = handler.getParameterHandler().getParameterObject();
|
|
|
|
+
|
|
|
|
+ BoundSql b = new BoundSql(config, countSql.toString(), boundSql.getParameterMappings(),
|
|
|
|
+ parameterObject);
|
|
|
|
+ MINReflectUtil.setFieldValue(b, "metaParameters",
|
|
|
|
+ MINReflectUtil.getFieldValue(boundSql, "metaParameters"));
|
|
|
|
+ MINReflectUtil.setFieldValue(b, "additionalParameters",
|
|
|
|
+ MINReflectUtil.getFieldValue(boundSql, "additionalParameters"));
|
|
|
|
+
|
|
|
|
+ MappedStatement mappedStatement = (MappedStatement) FieldUtils.readField(handler,
|
|
|
|
+ "mappedStatement", true);
|
|
|
|
+
|
|
|
|
+ String databaseName = connection.getMetaData().getDatabaseProductName();
|
|
|
|
+
|
|
|
|
+ if (DialectType.Oracle.value.equalsIgnoreCase(databaseName)) {
|
|
|
|
+ DIALECT = "com.startup.minpay.frame.jdbc.dialet.OracleDialect";
|
|
|
|
+ } else {
|
|
|
|
+ DIALECT = "com.startup.minpay.frame.jdbc.dialet.MySQLDialect";
|
|
|
|
+ }
|
|
|
|
+ PreparedStatement countStmt = connection.prepareStatement(countSql);
|
|
|
|
+
|
|
|
|
+ if (rowBounds.getCountSql() == null || "".equals(rowBounds.getCountSql())) {
|
|
|
|
+ DefaultParameterHandler dph = new DefaultParameterHandler(mappedStatement, parameterObject,
|
|
|
|
+ b);
|
|
|
|
+ dph.setParameters(countStmt);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ResultSet rs = countStmt.executeQuery();
|
|
|
|
+ rs.next();
|
|
|
|
+ page = rs.getInt(1);
|
|
|
|
+
|
|
|
|
+ rs.close();
|
|
|
|
+ countStmt.close();
|
|
|
|
+
|
|
|
|
+ rowBounds.setMaxRows(page);
|
|
|
|
+ } finally {
|
|
|
|
+ if (session != null) {
|
|
|
|
+ session.close();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Dialect dialect = (Dialect) Class.forName(DIALECT).newInstance();
|
|
|
|
+
|
|
|
|
+ sql = dialect.getLimitString(sql, rowBounds.getOffset(), rowBounds.getLimit());
|
|
|
|
+
|
|
|
|
+ MINReflectUtil.setFieldValue(boundSql, "sql", sql);
|
|
|
|
+ } else {
|
|
|
|
+ String countSql = getCountSql(sql);
|
|
|
|
+ if(countSql != null) {
|
|
|
|
+ Object parameterObject = handler.getParameterHandler().getParameterObject();
|
|
|
|
+
|
|
|
|
+ BoundSql b = new BoundSql(config, countSql, boundSql.getParameterMappings(),
|
|
|
|
+ parameterObject);
|
|
|
|
+ MINReflectUtil.setFieldValue(b, "metaParameters",
|
|
|
|
+ MINReflectUtil.getFieldValue(boundSql, "metaParameters"));
|
|
|
|
+ MINReflectUtil.setFieldValue(b, "additionalParameters",
|
|
|
|
+ MINReflectUtil.getFieldValue(boundSql, "additionalParameters"));
|
|
|
|
+
|
|
|
|
+ MappedStatement mappedStatement = (MappedStatement) FieldUtils.readField(handler,
|
|
|
|
+ "mappedStatement", true);
|
|
|
|
+
|
|
|
|
+ PreparedStatement countStmt = connection.prepareStatement(countSql);
|
|
|
|
+
|
|
|
|
+ DefaultParameterHandler dph = new DefaultParameterHandler(mappedStatement, parameterObject,
|
|
|
|
+ b);
|
|
|
|
+ dph.setParameters(countStmt);
|
|
|
|
+
|
|
|
|
+ ResultSet rs = countStmt.executeQuery();
|
|
|
|
+ while (rs.next()){
|
|
|
|
+ page = rs.getInt(1);
|
|
|
|
+ }
|
|
|
|
+ countStmt.close();
|
|
|
|
+ session.close();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ String countSql = getCountSql(sql);
|
|
|
|
+ if(countSql != null) {
|
|
|
|
+ Object parameterObject = handler.getParameterHandler().getParameterObject();
|
|
|
|
+
|
|
|
|
+ BoundSql b = new BoundSql(config, countSql, boundSql.getParameterMappings(),
|
|
|
|
+ parameterObject);
|
|
|
|
+ MINReflectUtil.setFieldValue(b, "metaParameters",
|
|
|
|
+ MINReflectUtil.getFieldValue(boundSql, "metaParameters"));
|
|
|
|
+ MINReflectUtil.setFieldValue(b, "additionalParameters",
|
|
|
|
+ MINReflectUtil.getFieldValue(boundSql, "additionalParameters"));
|
|
|
|
+
|
|
|
|
+ MappedStatement mappedStatement = (MappedStatement) FieldUtils.readField(handler,
|
|
|
|
+ "mappedStatement", true);
|
|
|
|
+
|
|
|
|
+ PreparedStatement countStmt = connection.prepareStatement(countSql);
|
|
|
|
+
|
|
|
|
+ DefaultParameterHandler dph = new DefaultParameterHandler(mappedStatement, parameterObject, b);
|
|
|
|
+ dph.setParameters(countStmt);
|
|
|
|
+
|
|
|
|
+ ResultSet rs = countStmt.executeQuery();
|
|
|
|
+ while (rs.next()){
|
|
|
|
+ page = rs.getInt(1);
|
|
|
|
+ }
|
|
|
|
+ countStmt.close();
|
|
|
|
+ session.close();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ System.out.println("page====>:" + page);
|
|
|
|
+ return invocation.proceed();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String getCountSql(String sql) {
|
|
|
|
+ sql = sql.toLowerCase();
|
|
|
|
+ if(!sql.trim().startsWith("select") || sql.contains("count(") || !sql.contains("from")){
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ String countSql = sql.substring(sql.toLowerCase().indexOf("select") + 6);
|
|
|
|
+ countSql = countSql.toLowerCase();
|
|
|
|
+ int sumStatIndex = 6;
|
|
|
|
+ int startIndex = 0;
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < 15;) {
|
|
|
|
+
|
|
|
|
+ startIndex = countSql.indexOf("from");
|
|
|
|
+ if (startIndex == -1) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ sumStatIndex = sumStatIndex + startIndex + 4;
|
|
|
|
+
|
|
|
|
+ String nowSql = countSql.substring(0, startIndex);
|
|
|
|
+
|
|
|
|
+ if (nowSql.indexOf("select") != -1) {
|
|
|
|
+ countSql = sql.substring(sumStatIndex);
|
|
|
|
+
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ String retcountSql = sql.substring(sumStatIndex);
|
|
|
|
+ retcountSql = "select count(1) from ".concat(retcountSql);
|
|
|
|
+
|
|
|
|
+ if (sql.toUpperCase().lastIndexOf("GROUP BY") != -1) {
|
|
|
|
+ countSql = "select count(1) from (" + countSql + ") tt";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ System.out.println("" + retcountSql);
|
|
|
|
+
|
|
|
|
+ return retcountSql;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public Object plugin(Object target) {
|
|
|
|
+ return Plugin.wrap(target, this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void setProperties(Properties properties) {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static class MINReflectUtil {
|
|
|
|
+ protected static Object operate(Object obj, String fieldName, Object fieldVal, String type) {
|
|
|
|
+ Object ret = null;
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ Class<? extends Object> classType = (Class) obj.getClass();
|
|
|
|
+
|
|
|
|
+ Field[] fields = classType.getDeclaredFields();
|
|
|
|
+ for (int i = 0; i < fields.length; i++) {
|
|
|
|
+ Field field = fields[i];
|
|
|
|
+ if (field.getName().equals(fieldName)) {
|
|
|
|
+
|
|
|
|
+ String firstLetter = fieldName.substring(0, 1).toUpperCase();
|
|
|
|
+ if ("set".equals(type)) {
|
|
|
|
+ String setMethodName = "set" + firstLetter + fieldName.substring(1);
|
|
|
|
+ Method setMethod = classType.getMethod(setMethodName, new Class[] { field.getType() });
|
|
|
|
+ ret = setMethod.invoke(obj, new Object[] { fieldVal });
|
|
|
|
+ }
|
|
|
|
+ if ("get".equals(type)) {
|
|
|
|
+ String getMethodName = "get" + firstLetter + fieldName.substring(1);
|
|
|
|
+ Method getMethod = classType.getMethod(getMethodName, new Class[0]);
|
|
|
|
+ ret = getMethod.invoke(obj, new Object[0]);
|
|
|
|
+ }
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ throw new MINRuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Object getVal(Object obj, String fieldName) {
|
|
|
|
+ return operate(obj, fieldName, null, "get");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void setVal(Object obj, String fieldName, Object fieldVal) {
|
|
|
|
+ operate(obj, fieldName, fieldVal, "set");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static Method getDeclaredMethod(Object object, String methodName, Class[] parameterTypes) {
|
|
|
|
+ for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
|
|
|
|
+ .getSuperclass()) {
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ return superClass.getDeclaredMethod(methodName, parameterTypes);
|
|
|
|
+ } catch (NoSuchMethodException noSuchMethodException) {
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void makeAccessible(Field field) {
|
|
|
|
+ if (!Modifier.isPublic(field.getModifiers())) {
|
|
|
|
+ field.setAccessible(true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static Field getDeclaredField(Object object, String filedName) {
|
|
|
|
+ for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
|
|
|
|
+ .getSuperclass()) {
|
|
|
|
+ try {
|
|
|
|
+ return superClass.getDeclaredField(filedName);
|
|
|
|
+ } catch (NoSuchFieldException noSuchFieldException) {
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Object invokeMethod(Object object, String methodName, Class[] parameterTypes, Object[] parameters)
|
|
|
|
+ throws InvocationTargetException {
|
|
|
|
+ Method method = getDeclaredMethod(object, methodName, parameterTypes);
|
|
|
|
+
|
|
|
|
+ if (method == null) {
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "Could not find method [" + methodName + "] on target [" + object + "]");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ method.setAccessible(true);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ return method.invoke(object, parameters);
|
|
|
|
+ } catch (IllegalAccessException illegalAccessException) {
|
|
|
|
+
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void setFieldValue(Object object, String fieldName, Object value) {
|
|
|
|
+ Field field = getDeclaredField(object, fieldName);
|
|
|
|
+
|
|
|
|
+ if (field == null) {
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "Could not find field [" + fieldName + "] on target [" + object + "]");
|
|
|
|
+ }
|
|
|
|
+ makeAccessible(field);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ field.set(object, value);
|
|
|
|
+ } catch (IllegalAccessException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Object getFieldValue(Object object, String fieldName) {
|
|
|
|
+ Field field = getDeclaredField(object, fieldName);
|
|
|
|
+ if (field == null) {
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "Could not find field [" + fieldName + "] on target [" + object + "]");
|
|
|
|
+ }
|
|
|
|
+ makeAccessible(field);
|
|
|
|
+
|
|
|
|
+ Object result = null;
|
|
|
|
+ try {
|
|
|
|
+ result = field.get(object);
|
|
|
|
+ } catch (IllegalAccessException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|