浏览代码

refactor: 重构动态表名解析器,去除正则替换程序,改为按表名位置进行替换

825944942@qq.com 5 年之前
父节点
当前提交
9be0b4cd92

+ 6 - 1
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/TableNameParser.java

@@ -256,7 +256,7 @@ public final class TableNameParser {
     /**
      * SQL 词
      */
-    public static class SqlToken {
+    public static class SqlToken implements Comparable<SqlToken> {
         private final int start;
         private final int end;
         private final String value;
@@ -279,6 +279,11 @@ public final class TableNameParser {
             return value;
         }
 
+        @Override
+        public int compareTo(SqlToken o) {
+            return Integer.compare(start, o.start);
+        }
+
         @Override
         public String toString() {
             return value;

+ 23 - 10
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parsers/DynamicTableNameParser.java

@@ -22,7 +22,8 @@ import lombok.Data;
 import lombok.experimental.Accessors;
 import org.apache.ibatis.reflection.MetaObject;
 
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -48,21 +49,33 @@ public class DynamicTableNameParser implements ISqlParser {
         // fix-issue:https://gitee.com/baomidou/mybatis-plus/issues/I1K7Q1
         // Assert.isFalse(CollectionUtils.isEmpty(tableNameHandlerMap), "tableNameHandlerMap is empty.");
         if (allowProcess(metaObject)) {
-            Collection<String> tables = new TableNameParser(sql).tables();
-
-            for (String table : tables) {
-                ITableNameHandler handler = tableNameHandlerMap.get(table);
-                if (null != handler) {
-                    sql = handler.process(metaObject, sql, table);
+            TableNameParser parser = new TableNameParser(sql);
+            List<TableNameParser.SqlToken> names = new ArrayList<>();
+            parser.accept(names::add);
+            StringBuilder builder = new StringBuilder();
+            int last = 0;
+            for (TableNameParser.SqlToken name : names) {
+                int start = name.getStart();
+                if (start != last) {
+                    builder.append(sql, last, start);
+                    String value = name.getValue();
+                    ITableNameHandler handler = tableNameHandlerMap.get(value);
+                    if (handler != null) {
+                        builder.append(handler.dynamicTableName(metaObject, sql, value));
+                    } else {
+                        builder.append(value);
+                    }
                 }
+                last = name.getEnd();
             }
-
-            return SqlInfo.of(sql);
+            if (last != sql.length()) {
+                builder.append(sql.substring(last));
+            }
+            return SqlInfo.of(builder.toString());
         }
         return null;
     }
 
-
     /**
      * 判断是否允许执行
      * <p>例如:逻辑删除只解析 delete , update 操作</p>

+ 2 - 19
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parsers/ITableNameHandler.java

@@ -26,25 +26,7 @@ import org.apache.ibatis.reflection.MetaObject;
 public interface ITableNameHandler {
 
     /**
-     * 表名 SQL 处理
-     *
-     * @param metaObject 元对象
-     * @param sql        当前执行 SQL
-     * @param tableName  表名
-     * @return 返回处理后的 SQL 语句
-     */
-    default String process(MetaObject metaObject, String sql, String tableName) {
-        String dynamicTableName = dynamicTableName(metaObject, sql, tableName);
-        if (null != dynamicTableName && !dynamicTableName.equalsIgnoreCase(tableName)) {
-            // 直接替换字符串对于 SQL 操作是不那么好做,这里修复只能尽可能的保证处理没问题
-            String regex = "(?<=\\b)\\Q" + tableName + "\\E(?=\\b)";
-            return sql.replaceAll(regex, dynamicTableName);
-        }
-        return sql;
-    }
-
-    /**
-     * 生成动态表名,无改变返回 NULL
+     * 生成动态表名
      *
      * @param metaObject 元对象
      * @param sql        当前执行 SQL
@@ -52,4 +34,5 @@ public interface ITableNameHandler {
      * @return String
      */
     String dynamicTableName(MetaObject metaObject, String sql, String tableName);
+
 }

+ 49 - 0
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/parsers/DynamicTableNameParserTest.java

@@ -0,0 +1,49 @@
+package com.baomidou.mybatisplus.extension.parsers;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Create by hcl at 2020/6/30
+ */
+class DynamicTableNameParserTest {
+
+    @Test
+    void parser() {
+        DynamicTableNameParser parser = new DynamicTableNameParser();
+        Map<String, ITableNameHandler> tableNameHandlerMap = new HashMap<>();
+        tableNameHandlerMap.put("t_user",
+                // https://github.com/baomidou/mybatis-plus/issues/2411
+                (metaObject, sql, tableName) -> {
+                    if ("t_user".equals(tableName)) {
+                        return "t_user_2019";
+                    }
+                    return tableName;
+                });
+        parser.setTableNameHandlerMap(tableNameHandlerMap);
+
+        String before = "select a.* from t_user a join t_userrole b on b.userid = a.gid";
+        String after = "select a.* from t_user_2019 a join t_userrole b on b.userid = a.gid";
+        assertEquals(after, parser.parser(null, before).getSql());
+
+        before = "select * from t_user";
+        after = "select * from t_user_2019";
+        assertEquals(after, parser.parser(null, before).getSql());
+
+        before = "insert into t_user(id,name) values('1','zhangsan')";
+        after = "insert into t_user_2019(id,name) values('1','zhangsan')";
+        assertEquals(after, parser.parser(null, before).getSql());
+        before = "select a.*,\n" +
+                "        (select count(1) from t_user) as cnt\n" +
+                "        from t_xxx a";
+        after = "select a.*,\n" +
+                "        (select count(1) from t_user_2019) as cnt\n" +
+                "        from t_xxx a";
+        assertEquals(after, parser.parser(null, before).getSql());
+    }
+
+}

+ 0 - 44
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/parsers/ITableNameHandlerTest.java

@@ -1,44 +0,0 @@
-package com.baomidou.mybatisplus.extension.parsers;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-/**
- * Create by hcl at 2020/6/24
- */
-class ITableNameHandlerTest {
-
-    /**
-     * 测试 process 方法
-     */
-    @Test
-    void process() {
-        // https://github.com/baomidou/mybatis-plus/issues/2411
-        ITableNameHandler handler = (metaObject, sql, tableName) -> {
-            if ("t_user".equals(tableName)) {
-                return "t_user_2019";
-            }
-            return null;
-        };
-        String before = "select a.* from t_user a join t_userrole b on b.userid = a.gid";
-        String after = "select a.* from t_user_2019 a join t_userrole b on b.userid = a.gid";
-        assertEquals(after, handler.process(null, before, "t_user"));
-
-        before = "select * from t_user";
-        after = "select * from t_user_2019";
-        assertEquals(after, handler.process(null, before, "t_user"));
-
-        before = "insert into t_user(id,name) values('1','zhangsan')";
-        after = "insert into t_user_2019(id,name) values('1','zhangsan')";
-        assertEquals(after, handler.process(null, before, "t_user"));
-        before = "select a.*,\n" +
-                "        (select count(1) from t_user) as cnt\n" +
-                "        from t_xxx a";
-        after = "select a.*,\n" +
-                "        (select count(1) from t_user_2019) as cnt\n" +
-                "        from t_xxx a";
-        assertEquals(after, handler.process(null, before, "t_user"));
-    }
-
-}