mirror of
https://gitee.com/ssssssss-team/magic-api.git
synced 2026-06-06 05:49:32 +08:00
db模块增加基于jdbc的存储过程及函数调用方法
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.ssssssss.magicapi.modules.db.model;
|
||||
|
||||
public enum StoreMode {
|
||||
INOUT,
|
||||
IN,
|
||||
OUT
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user