|
@@ -1,6 +1,8 @@
|
|
package com.chelvc.framework.database.interceptor;
|
|
package com.chelvc.framework.database.interceptor;
|
|
|
|
|
|
import java.sql.Connection;
|
|
import java.sql.Connection;
|
|
|
|
+import java.time.temporal.Temporal;
|
|
|
|
+import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.Objects;
|
|
@@ -11,6 +13,7 @@ import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
|
|
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
|
|
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
|
|
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
|
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
|
import com.chelvc.framework.common.util.ObjectUtils;
|
|
import com.chelvc.framework.common.util.ObjectUtils;
|
|
|
|
+import com.chelvc.framework.common.util.StringUtils;
|
|
import com.chelvc.framework.database.config.DatabaseProperties;
|
|
import com.chelvc.framework.database.config.DatabaseProperties;
|
|
import com.chelvc.framework.database.context.DatabaseContextHolder;
|
|
import com.chelvc.framework.database.context.DatabaseContextHolder;
|
|
import com.chelvc.framework.database.context.TableFieldContext;
|
|
import com.chelvc.framework.database.context.TableFieldContext;
|
|
@@ -18,7 +21,6 @@ import com.chelvc.framework.database.entity.Creatable;
|
|
import com.chelvc.framework.database.entity.Deletable;
|
|
import com.chelvc.framework.database.entity.Deletable;
|
|
import com.chelvc.framework.database.entity.Environmental;
|
|
import com.chelvc.framework.database.entity.Environmental;
|
|
import com.chelvc.framework.database.entity.Updatable;
|
|
import com.chelvc.framework.database.entity.Updatable;
|
|
-import com.chelvc.framework.database.handler.CryptoTypeHandler;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Lists;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
import net.sf.jsqlparser.JSQLParserException;
|
|
import net.sf.jsqlparser.JSQLParserException;
|
|
@@ -30,6 +32,7 @@ import net.sf.jsqlparser.expression.Function;
|
|
import net.sf.jsqlparser.expression.JdbcParameter;
|
|
import net.sf.jsqlparser.expression.JdbcParameter;
|
|
import net.sf.jsqlparser.expression.NullValue;
|
|
import net.sf.jsqlparser.expression.NullValue;
|
|
import net.sf.jsqlparser.expression.Parenthesis;
|
|
import net.sf.jsqlparser.expression.Parenthesis;
|
|
|
|
+import net.sf.jsqlparser.expression.StringValue;
|
|
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
|
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
|
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
|
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
|
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
|
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
|
@@ -73,8 +76,6 @@ import org.apache.ibatis.plugin.Plugin;
|
|
import org.apache.ibatis.plugin.Signature;
|
|
import org.apache.ibatis.plugin.Signature;
|
|
import org.apache.ibatis.reflection.MetaObject;
|
|
import org.apache.ibatis.reflection.MetaObject;
|
|
import org.apache.ibatis.reflection.SystemMetaObject;
|
|
import org.apache.ibatis.reflection.SystemMetaObject;
|
|
-import org.apache.ibatis.session.Configuration;
|
|
|
|
-import org.apache.ibatis.type.StringTypeHandler;
|
|
|
|
import org.apache.ibatis.type.TypeHandler;
|
|
import org.apache.ibatis.type.TypeHandler;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.stereotype.Component;
|
|
@@ -89,8 +90,87 @@ import org.springframework.stereotype.Component;
|
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
|
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}))
|
|
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}))
|
|
public class DynamicInvokeInterceptor implements Interceptor {
|
|
public class DynamicInvokeInterceptor implements Interceptor {
|
|
|
|
+ /**
|
|
|
|
+ * JdbcParameter类型参数查找结果回调接口
|
|
|
|
+ */
|
|
|
|
+ private interface JdbcParameterConsumer {
|
|
|
|
+ /**
|
|
|
|
+ * 结果信息处理,并返回SQL结构是否变更
|
|
|
|
+ *
|
|
|
|
+ * @param table 关联表信息
|
|
|
|
+ * @param column 关联字段信息
|
|
|
|
+ * @param parameter 参数表达式
|
|
|
|
+ * @param condition 条件表达式
|
|
|
|
+ * @param changing 表达式变更回调函数
|
|
|
|
+ * @return true/false
|
|
|
|
+ */
|
|
|
|
+ boolean consume(Table table, Column column, JdbcParameter parameter, Expression condition,
|
|
|
|
+ Consumer<Expression> changing);
|
|
|
|
+ }
|
|
|
|
+
|
|
private final DatabaseProperties properties;
|
|
private final DatabaseProperties properties;
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 字符串参数特殊字符转义
|
|
|
|
+ *
|
|
|
|
+ * @param value 参数值
|
|
|
|
+ * @return 参数值
|
|
|
|
+ */
|
|
|
|
+ private String escape(String value) {
|
|
|
|
+ if (StringUtils.isEmpty(value)) {
|
|
|
|
+ return value;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 判断参数是否需要转义
|
|
|
|
+ boolean needs = false;
|
|
|
|
+ int size = value.length();
|
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
|
+ char c = value.charAt(i);
|
|
|
|
+ if (c == '\u0000' || c == '\n' || c == '\r' || c == '\u001a' || c == '"' || c == '\'' || c == '\\') {
|
|
|
|
+ needs = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (!needs) {
|
|
|
|
+ return value;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 特殊字符转义
|
|
|
|
+ StringBuilder buffer = new StringBuilder((int) ((double) size * 1.1D));
|
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
|
+ char c = value.charAt(i);
|
|
|
|
+ switch (c) {
|
|
|
|
+ case '\u0000':
|
|
|
|
+ buffer.append('\\');
|
|
|
|
+ buffer.append('0');
|
|
|
|
+ break;
|
|
|
|
+ case '\n':
|
|
|
|
+ buffer.append('\\');
|
|
|
|
+ buffer.append('n');
|
|
|
|
+ break;
|
|
|
|
+ case '\r':
|
|
|
|
+ buffer.append('\\');
|
|
|
|
+ buffer.append('r');
|
|
|
|
+ break;
|
|
|
|
+ case '\u001a':
|
|
|
|
+ buffer.append('\\');
|
|
|
|
+ buffer.append('Z');
|
|
|
|
+ break;
|
|
|
|
+ case '\'':
|
|
|
|
+ buffer.append('\'');
|
|
|
|
+ buffer.append('\'');
|
|
|
|
+ break;
|
|
|
|
+ case '\\':
|
|
|
|
+ buffer.append('\\');
|
|
|
|
+ buffer.append('\\');
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ buffer.append(c);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return buffer.toString();
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 判断字段别名与指定别名是否相同
|
|
* 判断字段别名与指定别名是否相同
|
|
*
|
|
*
|
|
@@ -106,6 +186,41 @@ public class DynamicInvokeInterceptor implements Interceptor {
|
|
return table == null || Objects.equals(table.getName(), alias.getName());
|
|
return table == null || Objects.equals(table.getName(), alias.getName());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 判断是否是元类型参数
|
|
|
|
+ *
|
|
|
|
+ * @param parameter 参数
|
|
|
|
+ * @return true/false
|
|
|
|
+ */
|
|
|
|
+ private boolean isMetaParameter(Object parameter) {
|
|
|
|
+ return parameter == null || parameter instanceof Enum || parameter instanceof Number
|
|
|
|
+ || parameter instanceof String || parameter instanceof Boolean || parameter instanceof Character
|
|
|
|
+ || parameter instanceof Date || parameter instanceof Temporal;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取参数值
|
|
|
|
+ *
|
|
|
|
+ * @param bound 绑定SQL
|
|
|
|
+ * @param parameter 参数值表达式
|
|
|
|
+ * @return 参数值
|
|
|
|
+ */
|
|
|
|
+ private Object getParameterValue(BoundSql bound, JdbcParameter parameter) {
|
|
|
|
+ Object object = bound.getParameterObject();
|
|
|
|
+ if (this.isMetaParameter(object)) {
|
|
|
|
+ return object;
|
|
|
|
+ }
|
|
|
|
+ List<ParameterMapping> mappings = bound.getParameterMappings();
|
|
|
|
+ if (ObjectUtils.isEmpty(mappings)) {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ String property = mappings.get(parameter.getIndex() - 1).getProperty();
|
|
|
|
+ if (bound.hasAdditionalParameter(property)) {
|
|
|
|
+ return bound.getAdditionalParameter(property);
|
|
|
|
+ }
|
|
|
|
+ return SystemMetaObject.forObject(object).getValue(property);
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 查找字段的下标位置,如果不存在则返回 -1
|
|
* 查找字段的下标位置,如果不存在则返回 -1
|
|
*
|
|
*
|
|
@@ -337,24 +452,6 @@ public class DynamicInvokeInterceptor implements Interceptor {
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * JdbcParameter类型参数查找结果回调接口
|
|
|
|
- */
|
|
|
|
- private interface JdbcParameterConsumer {
|
|
|
|
- /**
|
|
|
|
- * 结果信息处理,并返回SQL结构是否变更
|
|
|
|
- *
|
|
|
|
- * @param table 关联表信息
|
|
|
|
- * @param column 关联字段信息
|
|
|
|
- * @param parameter 参数表达式
|
|
|
|
- * @param condition 条件表达式
|
|
|
|
- * @param changing 表达式变更回调函数
|
|
|
|
- * @return true/false
|
|
|
|
- */
|
|
|
|
- boolean consume(Table table, Column column, JdbcParameter parameter, Expression condition,
|
|
|
|
- Consumer<Expression> changing);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* 预处理JdbcParameter类型参数,并返回SQL结构是否变更
|
|
* 预处理JdbcParameter类型参数,并返回SQL结构是否变更
|
|
*
|
|
*
|
|
@@ -811,22 +908,17 @@ public class DynamicInvokeInterceptor implements Interceptor {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- // 构建混合模式附加参数
|
|
|
|
- TypeHandler<?> handler;
|
|
|
|
- if (this.properties.getCrypto().isWritable()) {
|
|
|
|
- // 明文参数 Handler
|
|
|
|
- handler = DatabaseContextHolder.getTypeHandler(StringTypeHandler.class);
|
|
|
|
- } else {
|
|
|
|
- // 加密参数 Handler
|
|
|
|
- handler = DatabaseContextHolder.getTypeHandler(CryptoTypeHandler.class);
|
|
|
|
|
|
+ // 获取绑定参数值(明文)
|
|
|
|
+ Object value = this.getParameterValue(bound, parameter);
|
|
|
|
+ if (!(value instanceof String)) {
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
- List<ParameterMapping> mappings = bound.getParameterMappings();
|
|
|
|
- String property = mappings.get(parameter.getIndex() - 1).getProperty();
|
|
|
|
- Configuration configuration = DatabaseContextHolder.getSessionTemplate().getConfiguration();
|
|
|
|
- mappings.add(new ParameterMapping.Builder(configuration, property, handler).build());
|
|
|
|
- JdbcParameter extra = new JdbcParameter(mappings.size(), parameter.isUseFixedIndex());
|
|
|
|
|
|
|
|
- // 将附附加参数添加到当前SQL
|
|
|
|
|
|
+ // 追加混合查询明文/密文附加参数
|
|
|
|
+ if (!this.properties.getCrypto().isWritable()) {
|
|
|
|
+ value = DatabaseContextHolder.getDatabaseCipherHandler().encrypt((String) value, true);
|
|
|
|
+ }
|
|
|
|
+ StringValue extra = new StringValue(this.escape((String) value));
|
|
if (condition instanceof InExpression) {
|
|
if (condition instanceof InExpression) {
|
|
InExpression in = (InExpression) condition;
|
|
InExpression in = (InExpression) condition;
|
|
((ExpressionList) in.getRightItemsList()).getExpressions().add(extra);
|
|
((ExpressionList) in.getRightItemsList()).getExpressions().add(extra);
|