From 5310bab4bef67d7d803852d36359d38bf6ef93a8 Mon Sep 17 00:00:00 2001 From: txk <1754875134@qq.com> Date: Fri, 11 Aug 2023 11:02:03 +0800 Subject: [PATCH 1/2] =?UTF-8?q?db=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=9F=BA=E4=BA=8Ejdbc=E7=9A=84=E5=AD=98=E5=82=A8=E8=BF=87?= =?UTF-8?q?=E7=A8=8B=E5=8F=8A=E5=87=BD=E6=95=B0=E8=B0=83=E7=94=A8=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../magicapi/modules/db/SQLModule.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java index f6cb2268..77e19b51 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java @@ -780,4 +780,64 @@ public class SQLModule implements DynamicAttribute, 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> list) { + List strings = new ArrayList<>(); + for (Map ignored : list) { + strings.add("?"); + } + String result = String.join(",", strings); + final String callProcedureSql = "call " + procName + "(" + result + ")"; + return this.call(callProcedureSql, list); + } + + @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> list) { + List strings = new ArrayList<>(); + for (Map ignored : list) { + strings.add("?"); + } + String result = String.join(",", strings); + final String callFunctionSql = "{call " + procName + "(" + result + ")}"; + return this.call(callFunctionSql, list); + } + + private Object call(String sql, List> list) { + List params = new ArrayList<>(); + for (Map 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; + return this.dataSourceNode.getJdbcTemplate().call( + con -> { + CallableStatement statement = con.prepareCall(callFunctionSql); + for (int i = 0; i < list.size(); i++) { + Map 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); + } + } + return statement; + }, params); + } + } -- Gitee From 46c8ab9e5b1c1ffe2c65e1c8e4c44d6a89ae8f30 Mon Sep 17 00:00:00 2001 From: txk <1754875134@qq.com> Date: Mon, 21 Aug 2023 19:33:05 +0800 Subject: [PATCH 2/2] =?UTF-8?q?db=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=9F=BA=E4=BA=8Ejdbc=E7=9A=84=E5=AD=98=E5=82=A8=E8=BF=87?= =?UTF-8?q?=E7=A8=8B=E5=8F=8A=E5=87=BD=E6=95=B0=E8=B0=83=E7=94=A8=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../magicapi/modules/db/SQLModule.java | 83 +++++------- .../magicapi/modules/db/model/StoreMode.java | 7 + .../modules/db/model/StoredParam.java | 123 ++++++++++++++++++ .../modules/db/mybatis/TextSqlNode.java | 102 ++++++++++++--- 4 files changed, 251 insertions(+), 64 deletions(-) create mode 100644 magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/StoreMode.java create mode 100644 magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/StoredParam.java diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java index 77e19b51..6bf875b3 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java @@ -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, Dynami private long ttl; private String logicDeleteColumn; private String logicDeleteValue; + public static List params; public SQLModule() { @@ -780,60 +790,37 @@ public class SQLModule implements DynamicAttribute, 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> list) { - List strings = new ArrayList<>(); - for (Map 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 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> list) { - List strings = new ArrayList<>(); - for (Map 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> list) { - List params = new ArrayList<>(); - for (Map 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 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; diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/StoreMode.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/StoreMode.java new file mode 100644 index 00000000..9404d536 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/StoreMode.java @@ -0,0 +1,7 @@ +package org.ssssssss.magicapi.modules.db.model; + +public enum StoreMode { + INOUT, + IN, + OUT +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/StoredParam.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/StoredParam.java new file mode 100644 index 00000000..7b86d901 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/StoredParam.java @@ -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; + } +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/mybatis/TextSqlNode.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/mybatis/TextSqlNode.java index 7e198e83..45165439 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/mybatis/TextSqlNode.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/mybatis/TextSqlNode.java @@ -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 varMap, List 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 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 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; } -- Gitee