db模块增加基于jdbc的存储过程及函数调用方法

This commit is contained in:
txk
2023-08-21 19:33:05 +08:00
parent 5310bab4be
commit 46c8ab9e5b
4 changed files with 251 additions and 64 deletions

View File

@@ -1,5 +1,7 @@
package org.ssssssss.magicapi.modules.db;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.support.GeneratedKeyHolder;
@@ -16,6 +18,9 @@ import org.ssssssss.magicapi.modules.db.dialect.Dialect;
import org.ssssssss.magicapi.modules.db.inteceptor.NamedTableInterceptor;
import org.ssssssss.magicapi.modules.db.inteceptor.SQLInterceptor;
import org.ssssssss.magicapi.modules.db.model.Page;
import org.ssssssss.magicapi.modules.db.model.SqlMode;
import org.ssssssss.magicapi.modules.db.model.StoreMode;
import org.ssssssss.magicapi.modules.db.model.StoredParam;
import org.ssssssss.magicapi.modules.db.provider.PageProvider;
import org.ssssssss.magicapi.modules.db.table.NamedTable;
import org.ssssssss.magicapi.core.interceptor.ResultProvider;
@@ -23,6 +28,8 @@ import org.ssssssss.magicapi.utils.ScriptManager;
import org.ssssssss.script.MagicScriptContext;
import org.ssssssss.script.annotation.Comment;
import org.ssssssss.script.functions.DynamicAttribute;
import org.ssssssss.script.parsing.GenericTokenParser;
import org.ssssssss.script.parsing.ast.literal.BooleanLiteral;
import org.ssssssss.script.parsing.ast.statement.ClassConverter;
import org.ssssssss.script.reflection.JavaReflection;
import org.ssssssss.script.runtime.RuntimeContext;
@@ -31,6 +38,8 @@ import java.beans.Transient;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -81,6 +90,7 @@ public class SQLModule implements DynamicAttribute<SQLModule, SQLModule>, Dynami
private long ttl;
private String logicDeleteColumn;
private String logicDeleteValue;
public static List<SqlParameter> params;
public SQLModule() {
@@ -780,60 +790,37 @@ public class SQLModule implements DynamicAttribute<SQLModule, SQLModule>, Dynami
}
}
@Comment("调用存储过程方法")
public Object callPro(
@Comment(name = "procName", value = "存储过程名称") String procName,
@Comment(name = "list", value = "[{\"p\":\"参数名\",\"io\":\"i/o/io\",\"t\":\"java.sql.Types\",\"v\":\"参数值\"}]") List<HashMap<String, Object>> list) {
List<String> strings = new ArrayList<>();
for (Map<String, Object> ignored : list) {
strings.add("?");
}
String result = String.join(",", strings);
final String callProcedureSql = "call " + procName + "(" + result + ")";
return this.call(callProcedureSql, list);
@Comment("调用过程")
public Object call(RuntimeContext runtimeContext,
@Comment(name = "sqlOrXml", value = "`SQL`语句或`xml`") String sqlOrXml) {
return call(runtimeContext, sqlOrXml, null);
}
private Object call(RuntimeContext runtimeContext,
@Comment(name = "sqlOrXml", value = "`SQL`语句或`xml`") String sqlOrXml,
@Comment(name = "params", value = "变量信息") Map<String, Object> params){
return call(new BoundSql(runtimeContext, sqlOrXml, params, this),runtimeContext);
}
@Comment("调用函数方法")
public Object callFun(
@Comment(name = "funcName", value = "函数名称") String procName,
@Comment(name = "list", value = "[{\"p\":\"参数名\",\"io\":\"i/o/io\",\"t\":\"java.sql.type\",\"v\":\"参数值\"}]") List<HashMap<String, Object>> list) {
List<String> strings = new ArrayList<>();
for (Map<String, Object> ignored : list) {
strings.add("?");
}
String result = String.join(",", strings);
final String callFunctionSql = "{call " + procName + "(" + result + ")}";
return this.call(callFunctionSql, list);
@Transient
public Object call(BoundSql boundSql,RuntimeContext runtimeContext) {
assertDatasourceNotNull();
return boundSql.execute(this.sqlInterceptors, () -> call(boundSql));
}
private Object call(String sql, List<HashMap<String, Object>> list) {
List<SqlParameter> params = new ArrayList<>();
for (Map<String, Object> map : list) {
String paramName = (String) map.get("p");
int type = (int) map.get("t");
if ("i".equals(map.get("io"))) {
params.add(new SqlParameter(paramName, type));
} else if ("o".equals(map.get("io"))) {
params.add(new SqlOutParameter(paramName, type));
} else {
params.add(new SqlInOutParameter(paramName, type));
}
}
final String callFunctionSql = sql;
private Object call(BoundSql boundSql) {
return this.dataSourceNode.getJdbcTemplate().call(
con -> {
CallableStatement statement = con.prepareCall(callFunctionSql);
for (int i = 0; i < list.size(); i++) {
Map<String, Object> map = list.get(i);
Object param = map.get("v");
int type = (int) map.get("t");
if ("i".equals(map.get("io"))) {
statement.setObject(i + 1, param);
} else if ("o".equals(map.get("io"))) {
statement.registerOutParameter(i + 1, type);
} else {
statement.setObject(i + 1, param);
statement.registerOutParameter(i + 1, type);
CallableStatement statement = con.prepareCall(boundSql.getSql());
Object[] parameters = boundSql.getParameters();
for (int i = 0; i < parameters.length; i++) {
StoredParam storedParam = (StoredParam) parameters[i];
if (storedParam.getInOut() == StoreMode.IN) {
statement.setObject(i + 1, storedParam.getValue());
} else if (storedParam.getInOut() == StoreMode.OUT) {
statement.registerOutParameter(i + 1, storedParam.getType());
} else if (storedParam.getInOut() == StoreMode.INOUT) {
statement.setObject(i + 1, storedParam.getValue());
statement.registerOutParameter(i + 1, storedParam.getType());
}
}
return statement;

View File

@@ -0,0 +1,7 @@
package org.ssssssss.magicapi.modules.db.model;
public enum StoreMode {
INOUT,
IN,
OUT
}

View File

@@ -0,0 +1,123 @@
package org.ssssssss.magicapi.modules.db.model;
import java.sql.Types;
import java.util.Objects;
/**
* 过程入参
*/
public class StoredParam {
//参数SQL类型
private Integer type;
//入出参
private StoreMode inOut;
//参数值
private Object value;
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public StoreMode getInOut() {
return inOut;
}
public void setInOut(StoreMode inOut) {
this.inOut = inOut;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public static int paramType(String type){
if (Objects.equals(type, "BIT")) {
return Types.BIT;
} else if (Objects.equals(type, "TINYINT")) {
return Types.TINYINT;
} else if (Objects.equals(type, "SMALLINT")) {
return Types.SMALLINT;
} else if (Objects.equals(type, "INTEGER")) {
return Types.INTEGER;
} else if (Objects.equals(type, "BIGINT")) {
return Types.BIGINT;
} else if (Objects.equals(type, "FLOAT")) {
return Types.FLOAT;
} else if (Objects.equals(type, "REAL")) {
return Types.REAL;
} else if (Objects.equals(type, "NUMERIC")) {
return Types.NUMERIC;
} else if (Objects.equals(type, "DECIMAL")) {
return Types.DECIMAL;
} else if (Objects.equals(type, "CHAR")) {
return Types.CHAR;
} else if (Objects.equals(type, "VARCHAR")) {
return Types.VARCHAR;
} else if (Objects.equals(type, "LONGVARCHAR")) {
return Types.LONGVARCHAR;
} else if (Objects.equals(type, "DATE")) {
return Types.DATE;
} else if (Objects.equals(type, "TIME")) {
return Types.TIME;
} else if (Objects.equals(type, "TIMESTAMP")) {
return Types.TIMESTAMP;
} else if (Objects.equals(type, "BINARY")) {
return Types.BINARY;
} else if (Objects.equals(type, "VARBINARY")) {
return Types.VARBINARY;
} else if (Objects.equals(type, "LONGVARBINARY")) {
return Types.LONGVARBINARY;
} else if (Objects.equals(type, "NULL")) {
return Types.NULL;
} else if (Objects.equals(type, "OTHER")) {
return Types.OTHER;
} else if (Objects.equals(type, "JAVA_OBJECT")) {
return Types.JAVA_OBJECT;
} else if (Objects.equals(type, "DISTINCT")) {
return Types.DISTINCT;
} else if (Objects.equals(type, "STRUCT")) {
return Types.STRUCT;
} else if (Objects.equals(type, "ARRAY")) {
return Types.ARRAY;
} else if (Objects.equals(type, "BLOB")) {
return Types.BLOB;
} else if (Objects.equals(type, "CLOB")) {
return Types.CLOB;
} else if (Objects.equals(type, "REF")) {
return Types.REF;
} else if (Objects.equals(type, "DATALINK")) {
return Types.DATALINK;
} else if (Objects.equals(type, "BOOLEAN")) {
return Types.BOOLEAN;
} else if (Objects.equals(type, "ROWID")) {
return Types.ROWID;
} else if (Objects.equals(type, "NCHAR")) {
return Types.NCHAR;
} else if (Objects.equals(type, "NVARCHAR")) {
return Types.NVARCHAR;
} else if (Objects.equals(type, "LONGNVARCHAR")) {
return Types.LONGNVARCHAR;
} else if (Objects.equals(type, "NCLOB")) {
return Types.NCLOB;
} else if (Objects.equals(type, "SQLXML")) {
return Types.SQLXML;
} else if (Objects.equals(type, "REF_CURSOR")) {
return Types.REF_CURSOR;
} else if (Objects.equals(type, "TIME_WITH_TIMEZONE")) {
return Types.TIME_WITH_TIMEZONE;
} else if (Objects.equals(type, "TIMESTAMP_WITH_TIMEZONE")) {
return Types.TIMESTAMP_WITH_TIMEZONE;
}
return Types.NULL;
}
}

View File

@@ -1,12 +1,18 @@
package org.ssssssss.magicapi.modules.db.mybatis;
import org.springframework.jdbc.core.SqlInOutParameter;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.ssssssss.magicapi.modules.db.SQLModule;
import org.ssssssss.magicapi.modules.db.model.StoreMode;
import org.ssssssss.magicapi.modules.db.model.StoredParam;
import org.ssssssss.magicapi.utils.ScriptManager;
import org.ssssssss.script.functions.StreamExtension;
import org.ssssssss.script.parsing.GenericTokenParser;
import org.ssssssss.script.parsing.ast.literal.BooleanLiteral;
import java.util.List;
import java.util.Map;
import java.sql.Types;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -27,6 +33,18 @@ public class TextSqlNode extends SqlNode {
private static final GenericTokenParser IF_PARAM_TOKEN_PARSER = new GenericTokenParser("?{", ",", true);
private static final GenericTokenParser OUT_PARAM_TOKEN_PARSER = new GenericTokenParser("@{", ",", true);
private static final GenericTokenParser OUT_TOKEN_PARSER = new GenericTokenParser("@{", "}", true);
private static final GenericTokenParser TYPE_TOKEN_PARSER = new GenericTokenParser(",", "}", true);
private static final GenericTokenParser INOUT_TOKEN_PARSER = new GenericTokenParser("@{", "(", true);
private static final GenericTokenParser IN_PARAM_TOKEN_PARSER = new GenericTokenParser("#{", ",", true);
private static final GenericTokenParser PARAM_TOKEN_PARSER = new GenericTokenParser("(", ")", true);
/**
* SQL
*/
@@ -37,6 +55,7 @@ public class TextSqlNode extends SqlNode {
}
public static String parseSql(String sql, Map<String, Object> varMap, List<Object> parameters) {
SQLModule.params = new ArrayList<>();
// 处理?{}参数
sql = IF_TOKEN_PARSER.parse(sql.trim(), text -> {
AtomicBoolean ifTrue = new AtomicBoolean(false);
@@ -50,21 +69,72 @@ public class TextSqlNode extends SqlNode {
sql = CONCAT_TOKEN_PARSER.parse(sql, text -> String.valueOf(ScriptManager.executeExpression(text, varMap)));
// 处理#{}参数
sql = REPLACE_TOKEN_PARSER.parse(sql, text -> {
Object value = ScriptManager.executeExpression(text, varMap);
if (value == null) {
parameters.add(null);
return "?";
}
try {
//对集合自动展开
List<Object> objects = StreamExtension.arrayLikeToList(value);
parameters.addAll(objects);
return IntStream.range(0, objects.size()).mapToObj(t -> "?").collect(Collectors.joining(","));
} catch (Exception e) {
parameters.add(value);
return "?";
}
StoredParam storedParam = new StoredParam();
if (text.indexOf(",") > 0) {
IN_PARAM_TOKEN_PARSER.parse("#{" + text, param -> {
PARAM_TOKEN_PARSER.parse(param,variable -> {
Object value = ScriptManager.executeExpression(variable, varMap);
storedParam.setValue(value);
storedParam.setInOut(StoreMode.IN);
TYPE_TOKEN_PARSER.parse(text + "}", type -> {
storedParam.setType(StoredParam.paramType(type));
SQLModule.params.add(new SqlParameter(param, StoredParam.paramType(type)));
return null;
});
parameters.add(storedParam);
return null;
});
return null;
});
return "?";
} else {
Object value = ScriptManager.executeExpression(text, varMap);
if (value == null) {
parameters.add(null);
return "?";
}
try {
//对集合自动展开
List<Object> objects = StreamExtension.arrayLikeToList(value);
parameters.addAll(objects);
return IntStream.range(0, objects.size()).mapToObj(t -> "?").collect(Collectors.joining(","));
} catch (Exception e) {
parameters.add(value);
return "?";
}
}
});
sql = OUT_TOKEN_PARSER.parse(sql,text -> {
StoredParam storedParam = new StoredParam();
String val = OUT_PARAM_TOKEN_PARSER.parse("@{" + text, param -> {
TYPE_TOKEN_PARSER.parse(text + "}", type -> {
if (param.indexOf("(") > 0) {
PARAM_TOKEN_PARSER.parse(param,variable -> {
Object value = ScriptManager.executeExpression(variable, varMap);
storedParam.setValue(value);
storedParam.setInOut(StoreMode.INOUT);
storedParam.setType(StoredParam.paramType(type));
return null;
});
INOUT_TOKEN_PARSER.parse("@{" + param, inoutParam -> {
SQLModule.params.add(new SqlInOutParameter(inoutParam, StoredParam.paramType(type)));
return null;
});
} else {
Object value = ScriptManager.executeExpression(param, varMap);
storedParam.setValue(value);
storedParam.setInOut(StoreMode.OUT);
storedParam.setType(StoredParam.paramType(type));
SQLModule.params.add(new SqlOutParameter(param, StoredParam.paramType(type)));
}
return null;
});
parameters.add(storedParam);
return null;
});
return "?";
});
return sql;
}