瀏覽代碼

refactor(order): 修复排序字段优先级问题(https://gitee.com/baomidou/mybatis-plus/issues/IX1QO)

hanchunlin@aliyun.com 6 年之前
父節點
當前提交
0f274eab2a

+ 11 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/IPage.java

@@ -34,7 +34,9 @@ public interface IPage<T> extends Serializable {
      * 降序字段数组
      *
      * @return order by desc 的字段数组
+     * @see #orders()
      */
+    @Deprecated
     default String[] descs() {
         return null;
     }
@@ -43,11 +45,20 @@ public interface IPage<T> extends Serializable {
      * 升序字段数组
      *
      * @return order by asc 的字段数组
+     * @see #orders()
      */
+    @Deprecated
     default String[] ascs() {
         return null;
     }
 
+    /**
+     * 获取排序信息,排序的字段和正反序
+     *
+     * @return 排序信息
+     */
+    List<OrderItem> orders();
+
     /**
      * KEY/VALUE 条件
      *

+ 38 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/OrderItem.java

@@ -0,0 +1,38 @@
+package com.baomidou.mybatisplus.core.metadata;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 排序元素载体
+ *
+ * @author HCL
+ * Create at 2019/5/27
+ */
+@Getter
+@Setter
+@ToString
+public class OrderItem {
+
+    /**
+     * 需要进行排序的字段
+     */
+    private String column;
+
+    /**
+     * 是否正序排列,默认 true
+     */
+    private boolean asc = true;
+
+    public static OrderItem asc(String column) {
+        return build(column, true);
+    }
+
+    public static OrderItem build(String column, boolean asc) {
+        OrderItem item = new OrderItem();
+        item.setColumn(column);
+        item.setAsc(asc);
+        return item;
+    }
+}

+ 7 - 28
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/PaginationInterceptor.java

@@ -42,8 +42,6 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.util.*;
 
-import static java.util.stream.Collectors.joining;
-
 /**
  * 分页拦截器
  *
@@ -85,34 +83,14 @@ public class PaginationInterceptor extends AbstractSqlParserHandler implements I
      * @return ignore
      */
     public static String concatOrderBy(String originalSql, IPage<?> page, boolean orderBy) {
-        if (orderBy && (ArrayUtils.isNotEmpty(page.ascs())
-            || ArrayUtils.isNotEmpty(page.descs()))) {
-            StringBuilder buildSql = new StringBuilder(originalSql);
-            String ascStr = concatOrderBuilder(page.ascs(), " ASC");
-            String descStr = concatOrderBuilder(page.descs(), " DESC");
-            if (StringUtils.isNotEmpty(ascStr) && StringUtils.isNotEmpty(descStr)) {
-                ascStr += ", ";
-            }
-            if (StringUtils.isNotEmpty(ascStr) || StringUtils.isNotEmpty(descStr)) {
-                buildSql.append(" ORDER BY ").append(ascStr).append(descStr);
-            }
-            return buildSql.toString();
-        }
-        return originalSql;
-    }
+        if (orderBy && CollectionUtils.isNotEmpty(page.orders())) {
+
+            StringJoiner joiner = new StringJoiner(StringPool.COMMA);
+            page.orders().forEach(order -> joiner.add(order.getColumn() + (order.isAsc() ? " ASC" : " DESC")));
+            return originalSql + " ORDER BY " + joiner;
 
-    /**
-     * 拼接多个排序方法
-     *
-     * @param columns   ignore
-     * @param orderWord ignore
-     */
-    private static String concatOrderBuilder(String[] columns, String orderWord) {
-        if (ArrayUtils.isNotEmpty(columns)) {
-            return Arrays.stream(columns).filter(StringUtils::isNotEmpty)
-                .map(i -> i + orderWord).collect(joining(StringPool.COMMA));
         }
-        return StringUtils.EMPTY;
+        return originalSql;
     }
 
     /**
@@ -243,4 +221,5 @@ public class PaginationInterceptor extends AbstractSqlParserHandler implements I
             this.dialectClazz = dialectClazz;
         }
     }
+
 }

+ 120 - 16
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/pagination/Page.java

@@ -16,10 +16,15 @@
 package com.baomidou.mybatisplus.extension.plugins.pagination;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import org.jetbrains.annotations.Nullable;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * 简单分页模型
@@ -35,6 +40,7 @@ public class Page<T> implements IPage<T> {
      * 查询数据列表
      */
     private List<T> records = Collections.emptyList();
+
     /**
      * 总数
      */
@@ -43,18 +49,17 @@ public class Page<T> implements IPage<T> {
      * 每页显示条数,默认 10
      */
     private long size = 10;
+
     /**
      * 当前页
      */
     private long current = 1;
+
     /**
-     * SQL 排序 ASC 数组
-     */
-    private String[] ascs;
-    /**
-     * SQL 排序 DESC 数组
+     * 排序字段信息
      */
-    private String[] descs;
+    private List<OrderItem> orders = new ArrayList<>();
+
     /**
      * 自动优化 COUNT SQL
      */
@@ -65,7 +70,6 @@ public class Page<T> implements IPage<T> {
     private boolean isSearchCount = true;
 
     public Page() {
-        // to do nothing
     }
 
     /**
@@ -157,51 +161,150 @@ public class Page<T> implements IPage<T> {
         return this;
     }
 
+    /**
+     * 获取当前正序排列的字段集合
+     * <p>
+     * 为了兼容,将在不久后废弃
+     *
+     * @return 正序排列的字段集合
+     * @see #getOrders()
+     * @deprecated 3.1.2.2-SNAPSHOT
+     */
     @Override
+    @Nullable
+    @Deprecated
     public String[] ascs() {
-        return ascs;
+        return CollectionUtils.isNotEmpty(orders) ? mapOrderToArray(OrderItem::isAsc) : null;
     }
 
-    public Page<T> setAscs(List<String> ascs) {
-        if (CollectionUtils.isNotEmpty(ascs)) {
-            this.ascs = ascs.toArray(new String[0]);
+    /**
+     * 查找 order 中正序排序的字段数组
+     *
+     * @param filter 过滤器
+     * @return 返回正序排列的字段数组
+     */
+    private String[] mapOrderToArray(Predicate<OrderItem> filter) {
+        List<String> columns = new ArrayList<>(orders.size());
+        orders.forEach(i -> {
+            if (filter.test(i)) columns.add(i.getColumn());
+        });
+        return columns.toArray(new String[0]);
+    }
+
+    /**
+     * 移除符合条件的条件
+     *
+     * @param filter 条件判断
+     */
+    private void removeOrder(Predicate<OrderItem> filter) {
+        for (int i = orders.size() - 1; i >= 0; i--) {
+            if (filter.test(orders.get(i))) orders.remove(i);
         }
+    }
+
+    /**
+     * 添加新的排序条件,构造条件可以使用工厂:{@link OrderItem#build(String, boolean)}
+     *
+     * @param items 条件
+     * @return 返回分页参数本身
+     */
+    public Page<T> addOrder(OrderItem... items) {
+        orders.addAll(Arrays.asList(items));
         return this;
     }
 
+    /**
+     * 设置需要进行正序排序的字段
+     * <p>
+     * Replaced:{@link #addOrder(OrderItem...)}
+     *
+     * @param ascs 字段
+     * @return 返回自身
+     * @deprecated 3.1.2.2-SNAPSHOT
+     */
+    @Deprecated
+    public Page<T> setAscs(List<String> ascs) {
+        return CollectionUtils.isNotEmpty(ascs) ? setAsc(ascs.toArray(new String[0])) : this;
+    }
 
     /**
      * 升序
+     * <p>
+     * Replaced:{@link #addOrder(OrderItem...)}
      *
      * @param ascs 多个升序字段
+     * @deprecated 3.1.2.2-SNAPSHOT
      */
+    @Deprecated
     public Page<T> setAsc(String... ascs) {
-        this.ascs = ascs;
+        // 保证原来方法 set 的语意
+        removeOrder(OrderItem::isAsc);
+        for (String s : ascs) {
+            addOrder(OrderItem.asc(s));
+        }
         return this;
     }
 
+    /**
+     * 获取需简要倒序排列的字段数组
+     * <p>
+     *
+     * @return 倒序排列的字段数组
+     * @see #getOrders()
+     * @deprecated 3.1.2.2-SNAPSHOT
+     */
     @Override
+    @Deprecated
     public String[] descs() {
-        return descs;
+        return mapOrderToArray(i -> !i.isAsc());
     }
 
+    /**
+     * Replaced:{@link #addOrder(OrderItem...)}
+     *
+     * @param descs 需要倒序排列的字段
+     * @return 自身
+     * @deprecated 3.1.2.2-SNAPSHOT
+     */
+    @Deprecated
     public Page<T> setDescs(List<String> descs) {
+        // 保证原来方法 set 的语意
         if (CollectionUtils.isNotEmpty(descs)) {
-            this.descs = descs.toArray(new String[0]);
+            removeOrder(item -> !item.isAsc());
+            for (String s : descs) {
+                addOrder(OrderItem.build(s, false));
+            }
         }
         return this;
     }
 
     /**
-     * 降序
+     * 降序,这方法名不知道是谁起的
+     * <p>
+     * Replaced:{@link #addOrder(OrderItem...)}
      *
      * @param descs 多个降序字段
+     * @deprecated 3.1.2.2-SNAPSHOT
      */
+    @Deprecated
     public Page<T> setDesc(String... descs) {
-        this.descs = descs;
+        setDescs(Arrays.asList(descs));
         return this;
     }
 
+    @Override
+    public List<OrderItem> orders() {
+        return getOrders();
+    }
+
+    public List<OrderItem> getOrders() {
+        return orders;
+    }
+
+    public void setOrders(List<OrderItem> orders) {
+        this.orders = orders;
+    }
+
     @Override
     public boolean optimizeCountSql() {
         return optimizeCountSql;
@@ -224,4 +327,5 @@ public class Page<T> implements IPage<T> {
         this.optimizeCountSql = optimizeCountSql;
         return this;
     }
+
 }

+ 3 - 0
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/plugins/pagination/dialects/DB2DialectTest.java

@@ -24,6 +24,9 @@ import org.junit.jupiter.api.Test;
  */
 class DB2DialectTest {
 
+    /**
+     * TODO 需要修复的单元测试
+     */
     @Test
     void m1() {
         Page<?> page = new Page<>(2, 10);