miemie 4 years ago
parent
commit
970cd04abf
17 changed files with 240 additions and 69 deletions
  1. 26 0
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisXMLLanguageDriver.java
  2. 7 0
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/config/GlobalConfig.java
  3. 1 0
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/incrementer/ImadcnIdentifierGenerator.java
  4. 2 2
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/TableFieldInfo.java
  5. 1 1
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/TableInfo.java
  6. 6 0
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/Constants.java
  7. 4 0
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/GlobalConfigUtils.java
  8. 0 21
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/PluginUtils.java
  9. 1 1
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/SerializationUtils.java
  10. 2 5
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlScriptUtils.java
  11. 85 5
      mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlUtils.java
  12. 44 0
      mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlUtilsTest.java
  13. 47 0
      mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/ReplacePlaceholderInnerInterceptor.java
  14. 0 22
      mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/plugins/inner/ReplaceSelectBodyInnerInterceptorTest.java
  15. 1 1
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceplaceholder/Entity.java
  16. 1 1
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceplaceholder/EntityMapper.java
  17. 12 10
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceplaceholder/ReplacePlaceholderTest.java

+ 26 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisXMLLanguageDriver.java

@@ -15,10 +15,20 @@
  */
 package com.baomidou.mybatisplus.core;
 
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
+import com.baomidou.mybatisplus.core.toolkit.sql.SqlUtils;
+import org.apache.ibatis.builder.IncompleteElementException;
 import org.apache.ibatis.executor.parameter.ParameterHandler;
 import org.apache.ibatis.mapping.BoundSql;
 import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlSource;
 import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
+import org.apache.ibatis.session.Configuration;
+
+import java.util.List;
 
 /**
  * 继承 {@link XMLLanguageDriver} 重装构造函数, 使用自己的 MybatisParameterHandler
@@ -34,4 +44,20 @@ public class MybatisXMLLanguageDriver extends XMLLanguageDriver {
         // TODO 使用 MybatisParameterHandler 而不是 ParameterHandler
         return new MybatisParameterHandler(mappedStatement, parameterObject, boundSql);
     }
+
+    @Override
+    public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
+        GlobalConfig.DbConfig config = GlobalConfigUtils.getDbConfig(configuration);
+        if (config.isReplacePlaceholder()) {
+            List<String> find = SqlUtils.findPlaceholder(script);
+            if (CollectionUtils.isNotEmpty(find)) {
+                try {
+                    script = SqlUtils.replaceSqlPlaceholder(script, find, config.getPropertyFormat());
+                } catch (MybatisPlusException e) {
+                    throw new IncompleteElementException();
+                }
+            }
+        }
+        return super.createSqlSource(configuration, script, parameterType);
+    }
 }

+ 7 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/config/GlobalConfig.java

@@ -128,6 +128,13 @@ public class GlobalConfig implements Serializable {
          * @since 3.3.0
          */
         private String propertyFormat;
+        /**
+         * 实验性功能,占位符替换,等同于 {@link com.baomidou.mybatisplus.extension.plugins.inner.ReplacePlaceholderInnerInterceptor},
+         * 只是这个属于启动时替换,用得地方多会启动慢一点点,不适用于其他的 {@link org.apache.ibatis.scripting.LanguageDriver}
+         *
+         * @since 3.4.2
+         */
+        private boolean replacePlaceholder;
         /**
          * 表名是否使用驼峰转下划线命名,只对表名生效
          */

+ 1 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/incrementer/ImadcnIdentifierGenerator.java

@@ -14,6 +14,7 @@ import java.io.IOException;
  * 用 https://github.com/imadcn/idworker 的实现
  *
  * @author miemie
+ * @since 3.4.0
  * @since 2020-08-11
  */
 public class ImadcnIdentifierGenerator implements IdentifierGenerator, Closeable {

+ 2 - 2
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/TableFieldInfo.java

@@ -234,7 +234,7 @@ public class TableFieldInfo implements Constants {
             if (StringUtils.isNotBlank(propertyFormat)) {
                 asProperty = String.format(propertyFormat, this.property);
             }
-            this.sqlSelect += (" AS " + asProperty);
+            this.sqlSelect += (AS + asProperty);
         }
 
         this.insertStrategy = this.chooseFieldStrategy(tableField.insertStrategy(), dbConfig.getInsertStrategy());
@@ -300,7 +300,7 @@ public class TableFieldInfo implements Constants {
             if (StringUtils.isNotBlank(propertyFormat)) {
                 asProperty = String.format(propertyFormat, this.property);
             }
-            this.sqlSelect += (" AS " + asProperty);
+            this.sqlSelect += (AS + asProperty);
         }
     }
 

+ 1 - 1
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/TableInfo.java

@@ -219,7 +219,7 @@ public class TableInfo implements Constants {
         if (havePK()) {
             sqlSelect = keyColumn;
             if (resultMap == null && keyRelated) {
-                sqlSelect += (" AS " + keyProperty);
+                sqlSelect += (AS + keyProperty);
             }
         } else {
             sqlSelect = EMPTY;

+ 6 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/Constants.java

@@ -42,6 +42,12 @@ public interface Constants extends StringPool, Serializable {
      * AES 算法
      */
     String AES_CBC_CIPHER = "AES/CBC/PKCS5Padding";
+    /**
+     * as
+     */
+    String AS = " AS ";
+
+
     /**
      * 实体类
      */

+ 4 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/GlobalConfigUtils.java

@@ -95,6 +95,10 @@ public class GlobalConfigUtils {
         return getGlobalConfig(configuration).getDbConfig().getIdType();
     }
 
+    public static GlobalConfig.DbConfig getDbConfig(Configuration configuration) {
+        return getGlobalConfig(configuration).getDbConfig();
+    }
+
     public static ISqlInjector getSqlInjector(Configuration configuration) {
         return getGlobalConfig(configuration).getSqlInjector();
     }

+ 0 - 21
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/PluginUtils.java

@@ -21,7 +21,6 @@ import org.apache.ibatis.executor.statement.StatementHandler;
 import org.apache.ibatis.mapping.BoundSql;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.mapping.ParameterMapping;
-import org.apache.ibatis.mapping.SqlSource;
 import org.apache.ibatis.reflection.MetaObject;
 import org.apache.ibatis.reflection.SystemMetaObject;
 import org.apache.ibatis.session.Configuration;
@@ -67,10 +66,6 @@ public abstract class PluginUtils {
         return new MPBoundSql(boundSql);
     }
 
-    public static MpSqlSource mpSqlSource(SqlSource sqlSource) {
-        return new MpSqlSource(sqlSource);
-    }
-
     public static MPStatementHandler mpStatementHandler(StatementHandler statementHandler) {
         statementHandler = realTarget(statementHandler);
         MetaObject object = SystemMetaObject.forObject(statementHandler);
@@ -159,20 +154,4 @@ public abstract class PluginUtils {
             return (T) boundSql.getValue(property);
         }
     }
-
-    public static class MpSqlSource {
-        private final MetaObject sqlSource;
-
-        public MpSqlSource(SqlSource sqlSource) {
-            this.sqlSource = SystemMetaObject.forObject(sqlSource);
-        }
-
-        public String sql() {
-            return (String) sqlSource.getValue("sqlSource.sql");
-        }
-
-        public void sql(String sql) {
-            sqlSource.setValue("sqlSource.sql", sql);
-        }
-    }
 }

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

@@ -19,7 +19,7 @@ import java.io.*;
 
 
 /**
- * <p> copy from spring-core#org.springframework.util.SerializationUtils version 5.2.2 </p>
+ * <p> copy from spring-core#org.springframework.util.SerializationUtils version 5.2.8 </p>
  *
  * @since 1.0
  */

+ 2 - 5
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlScriptUtils.java

@@ -26,11 +26,8 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
  * @author miemie
  * @since 2018-08-15
  */
-public final class SqlScriptUtils implements Constants {
-
-    private SqlScriptUtils() {
-        // ignore
-    }
+@SuppressWarnings("serial")
+public abstract class SqlScriptUtils implements Constants {
 
     /**
      * <p>

+ 85 - 5
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlUtils.java

@@ -16,15 +16,28 @@
 package com.baomidou.mybatisplus.core.toolkit.sql;
 
 import com.baomidou.mybatisplus.core.enums.SqlLike;
-import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
+import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * SqlUtils工具类
+ * !!! 本工具不适用于本框架外的类使用 !!!
  *
  * @author Caratacus
  * @since 2016-11-13
  */
-public class SqlUtils {
+@SuppressWarnings("serial")
+public abstract class SqlUtils implements Constants {
+
+    private static final Pattern pattern = Pattern.compile("\\{@((\\w+?)|(\\w+?:\\w+?)|(\\w+?:\\w+?:\\w+?))}");
 
     /**
      * 用%连接like
@@ -35,11 +48,78 @@ public class SqlUtils {
     public static String concatLike(Object str, SqlLike type) {
         switch (type) {
             case LEFT:
-                return StringPool.PERCENT + str;
+                return PERCENT + str;
             case RIGHT:
-                return str + StringPool.PERCENT;
+                return str + PERCENT;
             default:
-                return StringPool.PERCENT + str + StringPool.PERCENT;
+                return PERCENT + str + PERCENT;
+        }
+    }
+
+    public static List<String> findPlaceholder(String sql) {
+        Matcher matcher = pattern.matcher(sql);
+        List<String> list = new ArrayList<>();
+        while (matcher.find()) {
+            list.add(matcher.group());
+        }
+        return list;
+    }
+
+    public static String replaceSqlPlaceholder(String sql, List<String> placeHolder, String asFormat) {
+        for (String s : placeHolder) {
+            String s1 = s.substring(2, s.length() - 1);
+            int i1 = s1.indexOf(COLON);
+            String tableName;
+            String alisa = null;
+            String asAlisa = null;
+            if (i1 < 0) {
+                tableName = s1;
+            } else {
+                tableName = s1.substring(0, i1);
+                s1 = s1.substring(i1 + 1);
+                i1 = s1.indexOf(COLON);
+                if (i1 < 0) {
+                    alisa = s1;
+                } else {
+                    alisa = s1.substring(0, i1);
+                    asAlisa = s1.substring(i1 + 1);
+                }
+            }
+            sql = sql.replace(s, getSelectBody(tableName, alisa, asAlisa, asFormat));
+        }
+        return sql;
+    }
+
+    public static String getSelectBody(String tableName, String alisa, String asAlisa, String asFormat) {
+        TableInfo tableInfo = TableInfoHelper.getTableInfo(tableName);
+        Assert.notNull(tableInfo, "can not find TableInfo Cache by \"%s\"", tableName);
+        String s = tableInfo.chooseSelect(TableFieldInfo::isSelect);
+        if (alisa == null) {
+            return s;
+        }
+        return getNewSelectBody(s, alisa, asAlisa, asFormat);
+    }
+
+    public static String getNewSelectBody(String selectBody, String alisa, String asAlisa, String asFormat) {
+        String[] split = selectBody.split(COMMA);
+        StringBuilder sb = new StringBuilder();
+        boolean asA = asAlisa != null;
+        for (String body : split) {
+            final String sa = alisa.concat(DOT);
+            if (asA) {
+                int as = body.indexOf(AS);
+                if (as < 0) {
+                    sb.append(sa).append(body).append(AS).append(String.format(asFormat, asAlisa.concat(DOT).concat(body)));
+                } else {
+                    // todo
+                    String s1 = body.substring(0, as);
+                    sb.append(s1);
+                }
+            } else {
+                sb.append(sa).append(body);
+            }
+            sb.append(COMMA);
         }
+        return sb.deleteCharAt(sb.length() - 1).toString();
     }
 }

+ 44 - 0
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlUtilsTest.java

@@ -0,0 +1,44 @@
+package com.baomidou.mybatisplus.core.toolkit.sql;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author miemie
+ * @since 2020-11-19
+ */
+class SqlUtilsTest {
+
+    @Test
+    void m1() {
+        List<String> list = SqlUtils.findPlaceholder("select {@table},{@table:t},{@table:t:r} from table");
+        assertThat(list).contains("{@table}", "{@table:t}", "{@table:t:r}");
+    }
+
+    @Test
+    void getNewSelectBody() {
+        String s = SqlUtils.getNewSelectBody("id,name", "d", null, null);
+        assertThat(s).isEqualTo("d.id,d.name");
+
+        s = SqlUtils.getNewSelectBody("`id`,`name`", "d", null, null);
+        assertThat(s).isEqualTo("d.`id`,d.`name`");
+
+        s = SqlUtils.getNewSelectBody("id,name", "d", "pp", "`%s`");
+        assertThat(s).isEqualTo("d.id AS `pp.id`,d.name AS `pp.name`");
+
+        s = SqlUtils.getNewSelectBody("id AS t_id,name AS t_name", "d", null, null);
+        assertThat(s).isEqualTo("d.id AS t_id,d.name AS t_name");
+
+        s = SqlUtils.getNewSelectBody("`id` AS t_id,`name` AS t_name", "d", null, null);
+        assertThat(s).isEqualTo("d.`id` AS t_id,d.`name` AS t_name");
+
+        s = SqlUtils.getNewSelectBody("id AS `t_id`,name AS `t_name`", "d", "pp", "`%s`");
+        assertThat(s).isEqualTo("d.id AS `pp.t_id`,d.name AS `pp.t_name`");
+
+        s = SqlUtils.getNewSelectBody("`id` AS `t_id`,`name` AS `t_name`", "d", "pp", "`%s`");
+        assertThat(s).isEqualTo("d.`id` AS `pp.t_id`,d.`name` AS `pp.t_name`");
+    }
+}

+ 47 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/ReplacePlaceholderInnerInterceptor.java

@@ -0,0 +1,47 @@
+package com.baomidou.mybatisplus.extension.plugins.inner;
+
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
+import com.baomidou.mybatisplus.core.toolkit.sql.SqlUtils;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * 功能类似于 {@link GlobalConfig.DbConfig#replacePlaceholder},
+ * 只是这个是在运行时实时替换,适用范围更广
+ *
+ * @author miemie
+ * @since 2020-11-19
+ */
+public class ReplacePlaceholderInnerInterceptor implements InnerInterceptor {
+
+    protected final Log logger = LogFactory.getLog(this.getClass());
+
+    private String asFormat;
+
+    public ReplacePlaceholderInnerInterceptor() {
+    }
+
+    public ReplacePlaceholderInnerInterceptor(String asFormat) {
+        this.asFormat = asFormat;
+    }
+
+    @Override
+    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
+        String sql = boundSql.getSql();
+        List<String> find = SqlUtils.findPlaceholder(sql);
+        if (CollectionUtils.isNotEmpty(find)) {
+            sql = SqlUtils.replaceSqlPlaceholder(sql, find, asFormat);
+            PluginUtils.mpBoundSql(boundSql).sql(sql);
+        }
+    }
+}

+ 0 - 22
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/plugins/inner/ReplaceSelectBodyInnerInterceptorTest.java

@@ -1,22 +0,0 @@
-package com.baomidou.mybatisplus.extension.plugins.inner;
-
-import org.junit.jupiter.api.Test;
-
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * @author miemie
- * @since 2020-11-19
- */
-class ReplaceSelectBodyInnerInterceptorTest {
-
-    private final ReplaceSelectBodyInnerInterceptor innerInterceptor = new ReplaceSelectBodyInnerInterceptor();
-
-    @Test
-    void find() {
-        List<String> list = innerInterceptor.find("select {@table},{@table:t},{@table:t:r} from table");
-        assertThat(list).contains("{@table}", "{@table:t}", "{@table:t:r}");
-    }
-}

+ 1 - 1
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceselectbody/Entity.java → mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceplaceholder/Entity.java

@@ -1,4 +1,4 @@
-package com.baomidou.mybatisplus.test.replaceselectbody;
+package com.baomidou.mybatisplus.test.replaceplaceholder;
 
 import lombok.Data;
 

+ 1 - 1
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceselectbody/EntityMapper.java → mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceplaceholder/EntityMapper.java

@@ -1,4 +1,4 @@
-package com.baomidou.mybatisplus.test.replaceselectbody;
+package com.baomidou.mybatisplus.test.replaceplaceholder;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Select;

+ 12 - 10
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceselectbody/ReplaceSelectBodyTest.java → mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/replaceplaceholder/ReplacePlaceholderTest.java

@@ -1,7 +1,8 @@
-package com.baomidou.mybatisplus.test.replaceselectbody;
+package com.baomidou.mybatisplus.test.replaceplaceholder;
 
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.inner.ReplaceSelectBodyInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.ReplacePlaceholderInnerInterceptor;
 import com.baomidou.mybatisplus.test.BaseDbTest;
 import org.apache.ibatis.plugin.Interceptor;
 import org.junit.jupiter.api.Test;
@@ -14,18 +15,12 @@ import java.util.List;
  * @author miemie
  * @since 2020-06-23
  */
-public class ReplaceSelectBodyTest extends BaseDbTest<EntityMapper> {
+public class ReplacePlaceholderTest extends BaseDbTest<EntityMapper> {
 
     @Test
     void replace() {
         doTest(i -> {
             i.selectAll();
-            i.selectAll();
-            i.selectAll();
-            i.selectAll();
-            i.selectAll2();
-            i.selectAll2();
-            i.selectAll2();
             i.selectAll2();
         });
     }
@@ -33,10 +28,17 @@ public class ReplaceSelectBodyTest extends BaseDbTest<EntityMapper> {
     @Override
     protected List<Interceptor> interceptors() {
         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
-        interceptor.addInnerInterceptor(new ReplaceSelectBodyInnerInterceptor());
+        interceptor.addInnerInterceptor(new ReplacePlaceholderInnerInterceptor());
         return Collections.singletonList(interceptor);
     }
 
+    @Override
+    protected GlobalConfig globalConfig() {
+        GlobalConfig config = super.globalConfig();
+        config.getDbConfig().setReplacePlaceholder(true);
+        return config;
+    }
+
     @Override
     protected String tableDataSql() {
         return "insert into entity(id,name) values(1,'1'),(2,'2');";