From 5bda73696b81932c8d6a3b00b7d3bea684261e00 Mon Sep 17 00:00:00 2001 From: mxd <838425805@qq.com> Date: Thu, 30 Dec 2021 20:45:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E`mybatis`=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E7=9A=84`<`=E5=92=8C`>`=E8=87=AA=E5=8A=A8=E8=BD=AC=E4=B9=89?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96`mybatis`=E8=AF=AD=E6=B3=95=E5=92=8C?= =?UTF-8?q?`=3F{}`=E4=B8=8D=E5=85=BC=E5=AE=B9=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ssssssss/magicapi/modules/BoundSql.java | 50 ++----------- .../modules/mybatis/ForeachSqlNode.java | 13 ++-- .../magicapi/modules/mybatis/IfSqlNode.java | 4 +- .../modules/mybatis/MybatisParser.java | 25 +++++-- .../magicapi/modules/mybatis/SqlNode.java | 36 ++-------- .../magicapi/modules/mybatis/TextSqlNode.java | 71 +++++++++++++------ .../magicapi/modules/mybatis/TrimSqlNode.java | 2 +- .../modules/mybatis/WhereSqlNode.java | 2 +- 8 files changed, 91 insertions(+), 112 deletions(-) diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/BoundSql.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/BoundSql.java index 089abc37..5f1138b2 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/BoundSql.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/BoundSql.java @@ -5,18 +5,12 @@ import org.ssssssss.magicapi.interceptor.SQLInterceptor; import org.ssssssss.magicapi.model.RequestEntity; import org.ssssssss.magicapi.modules.mybatis.MybatisParser; import org.ssssssss.magicapi.modules.mybatis.SqlNode; -import org.ssssssss.script.MagicScriptContext; -import org.ssssssss.script.functions.StreamExtension; -import org.ssssssss.script.parsing.GenericTokenParser; -import org.ssssssss.script.parsing.ast.literal.BooleanLiteral; +import org.ssssssss.magicapi.modules.mybatis.TextSqlNode; import org.ssssssss.script.runtime.RuntimeContext; import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.IntStream; /** * SQL参数处理 @@ -25,14 +19,6 @@ import java.util.stream.IntStream; */ public class BoundSql { - private static final GenericTokenParser CONCAT_TOKEN_PARSER = new GenericTokenParser("${", "}", false); - - private static final GenericTokenParser REPLACE_TOKEN_PARSER = new GenericTokenParser("#{", "}", true); - - private static final GenericTokenParser IF_TOKEN_PARSER = new GenericTokenParser("?{", "}", true); - - private static final GenericTokenParser IF_PARAM_TOKEN_PARSER = new GenericTokenParser("?{", ",", true); - private static final Pattern REPLACE_MULTI_WHITE_LINE = Pattern.compile("(\r?\n(\\s*\r?\n)+)"); private static final List MYBATIS_TAGS = Arrays.asList("", "", "", "", ""); @@ -91,40 +77,12 @@ public class BoundSql { this.sqlOrXml = sqlNode.getSql(varMap); this.parameters = sqlNode.getParameters(); } else { - normal(runtimeContext, varMap); + normal(varMap); } } - private void normal(RuntimeContext runtimeContext, Map varMap) { - MagicScriptContext context = runtimeContext.getScriptContext(); - // 处理?{}参数 - this.sqlOrXml = IF_TOKEN_PARSER.parse(this.sqlOrXml.trim(), text -> { - AtomicBoolean ifTrue = new AtomicBoolean(false); - String val = IF_PARAM_TOKEN_PARSER.parse("?{" + text, param -> { - ifTrue.set(BooleanLiteral.isTrue(context.eval(param, varMap))); - return null; - }); - return ifTrue.get() ? val : ""; - }); - // 处理${}参数 - this.sqlOrXml = CONCAT_TOKEN_PARSER.parse(this.sqlOrXml, text -> String.valueOf(context.eval(text, varMap))); - // 处理#{}参数 - this.sqlOrXml = REPLACE_TOKEN_PARSER.parse(this.sqlOrXml, text -> { - Object value = context.eval(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 "?"; - } - }); + private void normal(Map varMap) { + this.sqlOrXml = TextSqlNode.parseSql(this.sqlOrXml, varMap, parameters); this.sqlOrXml = this.sqlOrXml == null ? null : REPLACE_MULTI_WHITE_LINE.matcher(this.sqlOrXml.trim()).replaceAll("\r\n"); } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/ForeachSqlNode.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/ForeachSqlNode.java index 65a32d9c..1771ca8c 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/ForeachSqlNode.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/ForeachSqlNode.java @@ -64,8 +64,6 @@ public class ForeachSqlNode extends SqlNode { if (value == null) { return ""; } - // 开始拼接SQL, - String sql = StringUtils.defaultString(this.open); // 如果集合是Collection对象或其子类,则转成数组 if (value instanceof Collection) { value = ((Collection) value).toArray(); @@ -74,19 +72,22 @@ public class ForeachSqlNode extends SqlNode { if (!value.getClass().isArray()) { return ""; } + // 开始拼接SQL, + StringBuilder sqlBuilder = new StringBuilder(StringUtils.defaultString(this.open)); // 获取数组长度 int len = Array.getLength(value); for (int i = 0; i < len; i++) { // 存入item对象 paramMap.put(this.item, Array.get(value, i)); // 拼接子节点 - sql += executeChildren(paramMap, parameters); + sqlBuilder.append(executeChildren(paramMap, parameters)); // 拼接分隔符 if (i + 1 < len) { - sql += StringUtils.defaultString(this.separator); + sqlBuilder.append(StringUtils.defaultString(this.separator)); } } // 拼接结束SQL - return sql + StringUtils.defaultString(this.close); + sqlBuilder.append(StringUtils.defaultString(this.close)); + return sqlBuilder.toString(); } -} \ No newline at end of file +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/IfSqlNode.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/IfSqlNode.java index 844a10c5..ebfef69e 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/IfSqlNode.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/IfSqlNode.java @@ -16,7 +16,7 @@ public class IfSqlNode extends SqlNode { /** * 判断表达式 */ - private String test; + private final String test; public IfSqlNode(String test) { this.test = test; @@ -32,4 +32,4 @@ public class IfSqlNode extends SqlNode { } return ""; } -} \ No newline at end of file +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/MybatisParser.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/MybatisParser.java index 9ec134a0..53a63a96 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/MybatisParser.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/MybatisParser.java @@ -8,12 +8,21 @@ import org.w3c.dom.NodeList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.ByteArrayInputStream; +import java.util.regex.Pattern; public class MybatisParser { + private static final Pattern ESCAPE_LT_PATTERN = Pattern.compile("<([\\d'\"\\s=>#$?(])"); + + private static final Pattern ESCAPE_GT_PATTERN = Pattern.compile("([})\\s<\\d])>"); + + private static final String ESCAPE_LT_REPLACEMENT = "<$1"; + + private static final String ESCAPE_GT_REPLACEMENT = "$1>"; + public static SqlNode parse(String xml) { try { - xml = "" + xml + ""; + xml = "" + escapeXml(xml) + ""; DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = documentBuilder.parse(new ByteArrayInputStream(xml.getBytes())); SqlNode sqlNode = new TextSqlNode(""); @@ -24,6 +33,10 @@ public class MybatisParser { } } + private static String escapeXml(String xml) { + return ESCAPE_GT_PATTERN.matcher(ESCAPE_LT_PATTERN.matcher(xml).replaceAll(ESCAPE_LT_REPLACEMENT)).replaceAll(ESCAPE_GT_REPLACEMENT); + } + private static void parseNodeList(SqlNode sqlNode, NodeList nodeList) { for (int i = 0, len = nodeList.getLength(); i < len; i++) { Node node = nodeList.item(i); @@ -82,20 +95,22 @@ public class MybatisParser { * 解析set节点 */ private static SetSqlNode parseSetSqlNode() { - SetSqlNode setSqlNode = new SetSqlNode(); - return setSqlNode; + return new SetSqlNode(); } /** * 解析where节点 */ private static WhereSqlNode parseWhereSqlNode() { - WhereSqlNode whereSqlNode = new WhereSqlNode(); - return whereSqlNode; + return new WhereSqlNode(); } private static String getNodeAttributeValue(Node node, String attributeKey) { Node item = node.getAttributes().getNamedItem(attributeKey); return item != null ? item.getNodeValue() : null; } + + public static void main(String[] args) { + System.out.println(escapeXml(" and 1 < 2 and 1<6 and 2>#{666}")); + } } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/SqlNode.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/SqlNode.java index 24fea8a0..07caa17b 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/SqlNode.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/SqlNode.java @@ -5,8 +5,6 @@ import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * sql节点 @@ -15,14 +13,7 @@ import java.util.regex.Pattern; * @version : 2020-05-18 */ public abstract class SqlNode { - /** - * 提取#{}的正则 - */ - final Pattern expressionRegx = Pattern.compile("#\\{(.*?)\\}"); - /** - * 提取${}的正则 - */ - final Pattern replaceRegx = Pattern.compile("\\$\\{(.*?)\\}"); + /** * 子节点 */ @@ -56,30 +47,15 @@ public abstract class SqlNode { * 获取子节点SQL */ public String executeChildren(Map paramMap, List parameters) { - String sql = ""; + StringBuilder sqlBuilder = new StringBuilder(); for (SqlNode node : nodes) { - sql += StringUtils.defaultString(node.getSql(paramMap, parameters)) + " "; + sqlBuilder.append(StringUtils.defaultString(node.getSql(paramMap, parameters))); + sqlBuilder.append(" "); } - return sql; + return sqlBuilder.toString(); } public List getParameters() { return parameters; } - - /** - * 根据正则表达式提取参数 - * - * @param pattern 正则表达式 - * @param sql SQL - */ - public List extractParameter(Pattern pattern, String sql) { - Matcher matcher = pattern.matcher(sql); - List results = new ArrayList<>(); - while (matcher.find()) { - results.add(matcher.group(1)); - } - return results; - } - -} \ No newline at end of file +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/TextSqlNode.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/TextSqlNode.java index d825f868..36d49864 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/TextSqlNode.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/TextSqlNode.java @@ -1,11 +1,15 @@ package org.ssssssss.magicapi.modules.mybatis; -import org.apache.commons.lang3.StringUtils; import org.ssssssss.magicapi.script.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.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * 普通SQL节点 @@ -14,33 +18,58 @@ import java.util.Objects; * @version : 2020-05-18 */ public class TextSqlNode extends SqlNode { + + private static final GenericTokenParser CONCAT_TOKEN_PARSER = new GenericTokenParser("${", "}", false); + + private static final GenericTokenParser REPLACE_TOKEN_PARSER = new GenericTokenParser("#{", "}", true); + + private static final GenericTokenParser IF_TOKEN_PARSER = new GenericTokenParser("?{", "}", true); + + private static final GenericTokenParser IF_PARAM_TOKEN_PARSER = new GenericTokenParser("?{", ",", true); + /** * SQL */ - private String text; + private final String text; public TextSqlNode(String text) { this.text = text; } + public static String parseSql(String sql, Map varMap, List parameters) { + // 处理?{}参数 + 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 : ""; + }); + // 处理${}参数 + 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 "?"; + } + }); + return sql; + } + @Override public String getSql(Map paramMap, List parameters) { - String sql = text; - if (StringUtils.isNotBlank(text)) { - // 提取#{}表达式 - List expressions = extractParameter(expressionRegx, text); - for (String expression : expressions) { - // 执行表达式 - Object val = ScriptManager.executeExpression(expression, paramMap); - parameters.add(val); - sql = sql.replaceFirst(expressionRegx.pattern(), "?"); - } - expressions = extractParameter(replaceRegx, text); - for (String expression : expressions) { - Object val = ScriptManager.executeExpression(expression, paramMap); - sql = sql.replaceFirst(replaceRegx.pattern(), Objects.toString(val, "")); - } - } - return sql + executeChildren(paramMap, parameters).trim(); + return parseSql(text, paramMap, parameters) + executeChildren(paramMap, parameters).trim(); } -} \ No newline at end of file +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/TrimSqlNode.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/TrimSqlNode.java index a0ebb8be..27f9f39b 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/TrimSqlNode.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/TrimSqlNode.java @@ -86,4 +86,4 @@ public class TrimSqlNode extends SqlNode { } return sqlBuffer.toString(); } -} \ No newline at end of file +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/WhereSqlNode.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/WhereSqlNode.java index 1ec1d43e..75aa8e84 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/WhereSqlNode.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/mybatis/WhereSqlNode.java @@ -24,4 +24,4 @@ public class WhereSqlNode extends TrimSqlNode { return sql; } -} \ No newline at end of file +}