From 696a3f4b9a9baefd0232cdabdd38ba9ccb833384 Mon Sep 17 00:00:00 2001 From: zagreb Date: Tue, 14 Oct 2025 07:31:27 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AD=98=E5=82=A8=E8=BF=87?= =?UTF-8?q?=E7=A8=8Bsql=E8=A7=A3=E6=9E=90=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=BD=93=E5=90=8C=E6=97=B6=E5=AD=98=E5=9C=A8#{}=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=92=8C@{}=E5=8F=82=E6=95=B0=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=8C=89=E8=A7=A3=E6=9E=90=E7=AC=AC=E4=B8=80=E4=B8=AA=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=86=8D=E5=88=A4=E6=96=AD=E5=90=8E=E7=BB=AD=E5=AD=90?= =?UTF-8?q?=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zagreb --- .../modules/db/mybatis/TextSqlNode.java | 166 ++++++++++++------ 1 file changed, 117 insertions(+), 49 deletions(-) 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 b5b669d9..5e6bea3e 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 @@ -14,8 +14,11 @@ import java.sql.Types; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -28,16 +31,20 @@ import java.util.stream.IntStream; public class TextSqlNode extends SqlNode { private static final GenericTokenParser CONCAT_TOKEN_PARSER = new GenericTokenParser("${", "}", false); + private static final Pattern CONCAT_TOKEN_PATTERN = Pattern.compile("\\$\\{.*?\\}"); private static final GenericTokenParser REPLACE_TOKEN_PARSER = new GenericTokenParser("#{", "}", true); + private static final Pattern REPLACE_TOKEN_PATTERN = Pattern.compile("\\#\\{.*?\\}"); private static final GenericTokenParser IF_TOKEN_PARSER = new GenericTokenParser("?{", "}", true); + private static final Pattern IF_TOKEN_PATTERN = Pattern.compile("\\?\\{.*?\\}"); 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 Pattern OUT_TOKEN_PATTERN = Pattern.compile("@\\{.*?\\}"); private static final GenericTokenParser TYPE_TOKEN_PARSER = new GenericTokenParser(",", "}", true); @@ -54,60 +61,121 @@ 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); - String val = IF_PARAM_TOKEN_PARSER.parse("?{" + text, param -> { - ifTrue.set(BooleanLiteral.isTrue(ScriptManager.executeExpression(param, varMap))); - return null; + + // 首先处理?{}参数 + if (IF_TOKEN_PATTERN.matcher(sql).find()) { + sql = IF_TOKEN_PARSER.parse(sql.trim(), text -> { + AtomicBoolean ifTrue = new AtomicBoolean(false); + String val = IF_PARAM_TOKEN_PARSER.parse("?{" + text, param -> { + ifTrue.set(BooleanLiteral.isTrue(ScriptManager.executeExpression(param, varMap))); + return null; + }); + return ifTrue.get() ? val : ""; }); - return ifTrue.get() ? val : ""; - }); - // 处理${}参数 - 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 "?"; + } + // 再处理${}参数 + if (CONCAT_TOKEN_PATTERN.matcher(sql).find()) { + sql = CONCAT_TOKEN_PARSER.parse(sql, text -> String.valueOf(ScriptManager.executeExpression(text, varMap))); + } + + // 判断#{}, @{}参数 + boolean hasReplaceToken = REPLACE_TOKEN_PATTERN.matcher(sql).find(); + boolean hasOutToken = OUT_TOKEN_PATTERN.matcher(sql).find(); + StringBuilder res = new StringBuilder(); + + // 没有 #{}, @{}参数 + if (!hasReplaceToken && !hasOutToken) { + return sql; + } + + while (hasReplaceToken || hasOutToken) { + + Pattern firstPattern = null; + Matcher firstMatcher = null; + int minIndex = Integer.MAX_VALUE; + String left; + + // 只有 #{} 参数,没有 @{} 参数 + if (!hasOutToken) { + firstPattern = REPLACE_TOKEN_PATTERN; + left = sql; + sql = ""; } - 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 "?"; + // 只有 @{} 参数,没有 #{} 参数 + else if (!hasReplaceToken) { + firstPattern = OUT_TOKEN_PATTERN; + left = sql; + sql = ""; } - }); - sql = OUT_TOKEN_PARSER.parse(sql, text -> { - // 获取类型 - AtomicInteger sqlType = new AtomicInteger(Types.NULL); - TYPE_TOKEN_PARSER.parse(text + "}", type -> { - sqlType.set(SqlTypes.getSqlType(type, true)); - return null; - }); - // 获取名称 - OUT_PARAM_TOKEN_PARSER.parse("@{" + text, param -> { - int index = param.indexOf("("); - if (index > 0) { - // 获取入参值 - String value = param.substring(index + 1, param.lastIndexOf(")")); - INOUT_TOKEN_PARSER.parse("@{" + param, inoutParam -> { - SqlInOutParameter p = new SqlInOutParameter(inoutParam, sqlType.get()); - parameters.add(new SqlParameterValue(p, ScriptManager.executeExpression(value, varMap))); + else { + // 找到第一个出现的参数 + for (Pattern pattern : new Pattern[]{ REPLACE_TOKEN_PATTERN, OUT_TOKEN_PATTERN }) { + Matcher matcher = pattern.matcher(sql); + int index = matcher.find() ? matcher.start() : Integer.MAX_VALUE; + if (index < minIndex) { + minIndex = index; + firstPattern = pattern; + firstMatcher = matcher; + } + } + // 截取第一个参数之前的SQL + left = sql.substring(0, firstMatcher.end()); + sql = sql.substring(firstMatcher.end()); + } + + if (Objects.equals(firstPattern, REPLACE_TOKEN_PATTERN)) { + // 处理#{}参数 + left = REPLACE_TOKEN_PARSER.parse(left, 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 "?"; + } + }); + } + else if (Objects.equals(firstPattern, OUT_TOKEN_PATTERN)) { + left = OUT_TOKEN_PARSER.parse(left, text -> { + // 获取类型 + AtomicInteger sqlType = new AtomicInteger(Types.NULL); + TYPE_TOKEN_PARSER.parse(text + "}", type -> { + sqlType.set(SqlTypes.getSqlType(type, true)); return null; }); - } else { - parameters.add(new SqlOutParameter(param, sqlType.get())); - } - return null; - }); - return "?"; - }); - return sql; + // 获取名称 + OUT_PARAM_TOKEN_PARSER.parse("@{" + text, param -> { + int index = param.indexOf("("); + if (index > 0) { + // 获取入参值 + String value = param.substring(index + 1, param.lastIndexOf(")")); + INOUT_TOKEN_PARSER.parse("@{" + param, inoutParam -> { + SqlInOutParameter p = new SqlInOutParameter(inoutParam, sqlType.get()); + parameters.add(new SqlParameterValue(p, ScriptManager.executeExpression(value, varMap))); + return null; + }); + } else { + parameters.add(new SqlOutParameter(param, sqlType.get())); + } + return null; + }); + return "?"; + }); + } + res.append(left); + + hasReplaceToken = REPLACE_TOKEN_PATTERN.matcher(sql).find(); + hasOutToken = OUT_TOKEN_PATTERN.matcher(sql).find(); + } + + return res.toString(); } @Override -- Gitee