فهرست منبع

修复动态节点处理错误.

https://github.com/baomidou/mybatis-plus/issues/6661
nieqiurong 6 ماه پیش
والد
کامیت
ec394ea8aa

+ 20 - 2
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisXMLScriptBuilder.java

@@ -45,6 +45,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.WeakHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * <p>试验性功能,解决mybatis堆内存过大的问题(看后期mybatis官方会不会解决堆内存占用问题)</p>
@@ -126,17 +128,33 @@ public class MybatisXMLScriptBuilder extends BaseBuilder {
 
     private static final StaticTextSqlNode SPACE_SQL_NODE = new StaticTextSqlNode(StringPool.SPACE);
 
+    private static final Pattern PATTERN = Pattern.compile("^\\s+|\\s+$");
+
+    /**
+     * 将前后空白符替换成空格
+     *
+     * @param str 字符串 (非空)
+     * @return 处理后文本
+     * @since 3.5.10.1
+     */
+    public static String replaceLeadingAndTrailingWhitespace(String str) {
+        Matcher matcher = PATTERN.matcher(str);
+        return matcher.replaceAll(StringPool.SPACE);
+    }
+
     protected MixedSqlNode parseDynamicTags(XNode node) {
         List<SqlNode> contents = new ArrayList<>();
         NodeList children = node.getNode().getChildNodes();
         for (int i = 0; i < children.getLength(); i++) {
             XNode child = node.newXNode(children.item(i));
             if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
-                String text = cacheStr(child.getStringBody("")).trim();
-                if (text.isEmpty()) {
+                String text = cacheStr(child.getStringBody(""));
+                String trimText = text.trim();
+                if (trimText.isEmpty()) {
                     contents.add(SPACE_SQL_NODE);
                     continue;
                 }
+                text = replaceLeadingAndTrailingWhitespace(text);
                 TextSqlNode textSqlNode = new TextSqlNode(text);
                 if (textSqlNode.isDynamic()) {
                     contents.add(textSqlNode);

+ 341 - 0
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/MybatisXMLLanguageDriverTest.java

@@ -0,0 +1,341 @@
+package com.baomidou.mybatisplus.core;
+
+import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MybatisXMLLanguageDriverTest {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MybatisXMLLanguageDriver.class);
+
+    @Test
+    void test1() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                                <if test="true">
+                                    1=1
+                                </if>
+                                and 2=2
+                                <if test="true">
+                                    and 3=3
+                                </if>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE 1=1  and 2=2  and 3=3");
+    }
+
+    @Test
+    void test2() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                                <if test="false">
+                                    1=1
+                                </if>
+                                and 2=2
+                                <if test="true">
+                                    and 3=3
+                                </if>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE  2=2  and 3=3");
+    }
+
+    @Test
+    void test3() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                                <if test="false">
+                                    1=1
+                                </if>
+                                and 2=2
+                                <if test="true">
+                                    and 3=3
+                                </if>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE  2=2  and 3=3");
+    }
+
+    @Test
+    void test4() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                                <if test="true">1=1</if>and 2=2<if test="true">and 3=3</if>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE 1=1and 2=2and 3=3");
+
+    }
+
+    @Test
+    void test5() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            where 1=1
+                            <if test="1==1">and id is not null</if>
+                            <if test="1==1">and name is not null</if>
+                        </script>
+            """, "select * from `user`\n" +
+            "                where 1=1  and id is not null   and name is not null");
+    }
+
+    @Test
+    void test6() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            where 1=1
+                            <if test="1==1">and id is not null</if><if test="1==1">and name is not null</if>
+                        </script>
+            """, "select * from `user`\n" +
+            "                where 1=1  and id is not null and name is not null");
+    }
+
+    @Test
+    void test7() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                            <if test="1==1">and id is not null</if><if test="1==1">and name is not null</if>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE  id is not nulland name is not null");
+    }
+
+    @Test
+    void test8() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                            <if test="1==1">and id is not null</if>
+                            <if test="1==1">and name is not null</if>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE  id is not null and name is not null");
+    }
+
+    @Test
+    void test9() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                            <if test="1==1">and id is not null</if>
+                            <if test="1==1">and name is not null</if>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE  id is not null and name is not null");
+    }
+
+    @Test
+    void test10() {
+        assertSql("""
+            <script>
+                            select * from `user` where 1 = 1
+                            <if test="1==1">and id is not null</if><if test="1==1">and name is not null</if>
+                        </script>
+            """, "select * from `user` where 1 = 1  and id is not null and name is not null");
+    }
+
+    @Test
+    void test11() {
+        assertSql("""
+            <script>
+                            select * from `user` where 1 = 1
+                            <if test="1==1">and id is not null</if>
+                            <if test="1==1">and name is not null</if>
+                        </script>
+            """, "select * from `user` where 1 = 1  and id is not null   and name is not null");
+    }
+
+    @Test
+    void test12() {
+        assertSql("""
+            <script>
+                            select * from `user` where 1 = 1 and id in
+                            <foreach collection='@java.util.Arrays@asList(1,2,3,4,5)' item='item' separator=',' open='(' close=')'>
+                                #{item}
+                            </foreach>
+                        </script>
+            """, "select * from `user` where 1 = 1 and id in  (   ?  ,  ?  ,  ?  ,  ?  ,  ?  )");
+    }
+
+    @Test
+    void test13() {
+        assertSql("""
+            <script>
+                            select * from `user` where 1 = 1 and
+                            <foreach collection='@java.util.Arrays@asList(1,2,3,4,5)' item='item' separator='and'>
+                                <if test="item == 1">id is not null</if>
+                                <if test="item == 2">name is not null</if>
+                                <if test="item == 3">age is not null</if>
+                            </foreach>
+                        </script>
+            """, "select * from `user` where 1 = 1 and     id is not null           and name is not null           and age is not null");
+    }
+
+    @Test
+    void test14() {
+        assertSql("""
+            <script>
+                   update user
+                   <set>
+                         <if test="true">username=#{username},</if>
+                         <if test="false">password=#{password},</if>
+                         <if test="true">email=#{email},</if>
+                         <if test="true">bio=#{bio},</if>
+                       </set>
+                     where id=#{id}
+            </script>
+            """, "update user  SET username=?,  email=?, bio=?  where id=?");
+    }
+
+    @Test
+    void test15() {
+        assertSql("""
+            <script>
+                   update user
+                   <!--这是一条更新语句-->
+                   <set>
+                         <if test="true">username=#{username},</if>
+                         <if test="false">password=#{password},</if>
+                         <if test="true">email=#{email},</if>
+                         <if test="true">bio=#{bio},</if>
+                       </set>
+                     where id=#{id}
+            </script>
+            """, "update user  SET username=?,  email=?, bio=?  where id=?");
+    }
+
+    @Test
+    void test16() {
+        assertSql("""
+            <script>
+                   update user
+                   <!--这是一条更新语句-->
+                   <bind name="name" value="test" />
+                   <set>
+                         <if test="true">username=#{username},</if>
+                         <if test="false">password=#{password},</if>
+                         <if test="true">email=#{email},</if>
+                         <if test="true">bio=#{bio},</if>
+                       </set>
+                     where id=#{id}
+            </script>
+            """, "update user    SET username=?,  email=?, bio=?  where id=?");
+    }
+
+    @Test
+    void test17() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                            <!--
+                                 查了点东西啊
+                                 12345
+                                 789
+                            -->
+                                <if test="true">1=1</if>and 2=2<if test="true">and 3=3</if>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE 1=1and 2=2and 3=3");
+    }
+
+    @Test
+    void test18() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                                <choose>
+                                    <when test="false">
+                                        and age > #{age}
+                                    </when>
+                                    <when test="false">
+                                        and name like concat(#{name},'%')
+                                    </when>
+                                    <otherwise>
+                                        and sex = '男'
+                                    </otherwise>
+                                </choose>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE  sex = '男'");
+    }
+
+    @Test
+    void test19() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                                <choose>
+                                    <when test="false">
+                                        and age > #{age}
+                                    </when>
+                                    <when test="true">
+                                        and name like concat(#{name},'%')
+                                    </when>
+                                    <otherwise>
+                                        and sex = '男'
+                                    </otherwise>
+                                </choose>
+                            </where>
+                        </script>
+            """, "select * from `user`  WHERE  name like concat(?,'%')");
+    }
+
+    @Test
+    void test20() {
+        assertSql("""
+            <script>
+                            select * from `user`
+                            <where>
+                                <choose>
+                                    <when test="false">
+                                        and age > #{age}
+                                    </when>
+                                    <when test="true">and name like concat(#{name},'%')</when>
+                                    <otherwise>
+                                        and sex = '男'
+                                    </otherwise>
+                                </choose>
+                            </where>
+                            and 1=1
+                        </script>
+            """, "select * from `user`  WHERE  name like concat(?,'%')  and 1=1");
+    }
+
+
+
+    void runMybatis(String script, String sql) {
+        var languageDriver = new XMLLanguageDriver();
+        var sqlSource = languageDriver.createSqlSource(new MybatisConfiguration(), script, Object.class);
+        LOGGER.info("mybatis parse :{}", sqlSource.getBoundSql(null).getSql());
+    }
+
+
+    void assertSql(String script, String sql) {
+        var languageDriver = new MybatisXMLLanguageDriver();
+        var sqlSource = languageDriver.createSqlSource(new MybatisConfiguration(), script, Object.class);
+        runMybatis(script, sql);
+        var boundSql = sqlSource.getBoundSql(null).getSql();
+        LOGGER.info("mybatis-plus parse :{}", boundSql);
+        Assertions.assertEquals(sql, boundSql);
+    }
+
+}

+ 19 - 0
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/MybatisXMLScriptBuilderTest.java

@@ -0,0 +1,19 @@
+package com.baomidou.mybatisplus.core;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import static com.baomidou.mybatisplus.core.MybatisXMLScriptBuilder.replaceLeadingAndTrailingWhitespace;
+
+public class MybatisXMLScriptBuilderTest {
+
+    @Test
+    void testReplaceLeadingAndTrailingWhitespace() {
+        Assertions.assertEquals(" 1=1 ", replaceLeadingAndTrailingWhitespace("\n    1=1 \n \n\n"));
+        Assertions.assertEquals(" 1=1 ", replaceLeadingAndTrailingWhitespace("\t\t1=1 \n \n\n"));
+        Assertions.assertEquals(" 1=1 ", replaceLeadingAndTrailingWhitespace("    1=1 \n \n\n"));
+        Assertions.assertEquals("1=1 ", replaceLeadingAndTrailingWhitespace("1=1 \n \n\n"));
+        Assertions.assertEquals(" 1\n=1 ", replaceLeadingAndTrailingWhitespace("\n    1\n=1 \n \n\n"));
+        Assertions.assertEquals("1\n=1 ", replaceLeadingAndTrailingWhitespace("1\n=1 \n \n\n"));
+    }
+
+}