Browse Source

update jpa builder.

deason 6 năm trước cách đây
mục cha
commit
7bc75e9e5f

+ 0 - 70
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Order.java

@@ -1,70 +0,0 @@
-/*
- * *************************************************
- * Copyright (c) 2018 QMTH. All Rights Reserved.
- * Created by Deason on 2018-10-17 15:18:02.
- * *************************************************
- */
-
-package cn.com.qmth.examcloud.core.print.common.jpa;
-
-import org.springframework.data.domain.Sort;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 排序条件类
- *
- * @author: fengdesheng
- * @since: 2018/10/17
- */
-public class Order implements Serializable {
-    protected static final long serialVersionUID = -1L;
-    private String fieldName;
-    private Sort.Direction direction;
-
-    private List<Order> orders = new ArrayList<>();
-
-    public Order asc(String fieldName) {
-        orders.add(new Order(fieldName, Sort.Direction.ASC));
-        return this;
-    }
-
-    public Order desc(String fieldName) {
-        orders.add(new Order(fieldName, Sort.Direction.DESC));
-        return this;
-    }
-
-    public Sort build() {
-        if (orders.size() == 0) {
-            return null;
-        }
-        List<Sort.Order> list = new ArrayList<>();
-        for (Order order : orders) {
-            list.add(new Sort.Order(order.getDirection(), order.getFieldName()));
-        }
-        return new Sort(list);
-    }
-
-    private Order(String fieldName, Sort.Direction direction) {
-        if (fieldName == null || "".equals(fieldName.trim())) {
-            throw new IllegalArgumentException("FieldName must be not empty.");
-        }
-        this.fieldName = fieldName.trim();
-        this.direction = direction;
-    }
-
-    public Order() {
-
-    }
-
-    public String getFieldName() {
-        return fieldName;
-    }
-
-    public Sort.Direction getDirection() {
-        return direction;
-    }
-
-}

+ 68 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/OrderBuilder.java

@@ -0,0 +1,68 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-23 16:47:59.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.jpa;
+
+import org.springframework.data.domain.Sort;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/23
+ */
+public class OrderBuilder {
+    private List<Order> orders;
+
+    public OrderBuilder() {
+        orders = new ArrayList<>();
+    }
+
+    public OrderBuilder asc(String fieldName) {
+        orders.add(new Order(fieldName, Sort.Direction.ASC));
+        return this;
+    }
+
+    public OrderBuilder desc(String fieldName) {
+        orders.add(new Order(fieldName, Sort.Direction.DESC));
+        return this;
+    }
+
+    public Sort build() {
+        if (orders.size() == 0) {
+            return null;
+        }
+        List<Sort.Order> list = new ArrayList<>();
+        for (Order order : orders) {
+            list.add(new Sort.Order(order.getDirection(), order.getFieldName()));
+        }
+        return new Sort(list);
+    }
+
+    public static class Order {
+        private String fieldName;
+        private Sort.Direction direction;
+
+        private Order(String fieldName, Sort.Direction direction) {
+            if (fieldName == null || "".equals(fieldName.trim())) {
+                throw new IllegalArgumentException("FieldName must be not empty.");
+            }
+            this.fieldName = fieldName.trim();
+            this.direction = direction;
+        }
+
+        public String getFieldName() {
+            return fieldName;
+        }
+
+        public Sort.Direction getDirection() {
+            return direction;
+        }
+    }
+
+}

+ 213 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/SearchBuilder.java

@@ -0,0 +1,213 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-23 15:43:17.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.jpa;
+
+import org.springframework.data.jpa.domain.Specification;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/23
+ */
+public class SearchBuilder {
+    private List<Searcher> searchers;
+
+    public SearchBuilder() {
+        searchers = new ArrayList<>();
+    }
+
+    public List<Searcher> build() {
+        return searchers;
+    }
+
+    public <T> SearchBuilder eq(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.EQ));
+        return this;
+    }
+
+    public static <T> Specification EQ(String fieldName, T value) {
+        return (root, query, cb) -> cb.equal(root.get(fieldName), value);
+    }
+
+    public <T> SearchBuilder notEq(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.NOT_EQ));
+        return this;
+    }
+
+    public static <T> Specification NOT_EQ(String fieldName, T value) {
+        return (root, query, cb) -> cb.notEqual(root.get(fieldName), value);
+    }
+
+    public <T> SearchBuilder gt(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.GT));
+        return this;
+    }
+
+    public static <T> Specification GT(String fieldName, T value) {
+        return (root, query, cb) -> cb.greaterThan(root.get(fieldName), (Comparable) value);
+    }
+
+    public <T> SearchBuilder gte(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.GTE));
+        return this;
+    }
+
+    public static <T> Specification GTE(String fieldName, T value) {
+        return (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(fieldName), (Comparable) value);
+    }
+
+    public <T> SearchBuilder lt(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.LT));
+        return this;
+    }
+
+    public static <T> Specification LT(String fieldName, T value) {
+        return (root, query, cb) -> cb.lessThan(root.get(fieldName), (Comparable) value);
+    }
+
+    public <T> SearchBuilder lte(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.LTE));
+        return this;
+    }
+
+    public static <T> Specification LTE(String fieldName, T value) {
+        return (root, query, cb) -> cb.lessThanOrEqualTo(root.get(fieldName), (Comparable) value);
+    }
+
+    public <T> SearchBuilder like(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.LIKE));
+        return this;
+    }
+
+    public static <T> Specification LIKE(String fieldName, T value) {
+        return (root, query, cb) -> cb.like(root.get(fieldName), "%" + value + "%");
+    }
+
+    public <T> SearchBuilder leftLike(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.L_LIKE));
+        return this;
+    }
+
+    public static <T> Specification L_LIKE(String fieldName, T value) {
+        return (root, query, cb) -> cb.like(root.get(fieldName), "%" + value);
+    }
+
+    public <T> SearchBuilder rightLike(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.R_LIKE));
+        return this;
+    }
+
+    public static <T> Specification R_LIKE(String fieldName, T value) {
+        return (root, query, cb) -> cb.like(root.get(fieldName), value + "%");
+    }
+
+    public SearchBuilder in(String fieldName, Collection<?> values) {
+        if (values == null || values.size() == 0) {
+            throw new IllegalArgumentException("In Values must be not empty.");
+        }
+        if (values.size() == 1) {
+            searchers.add(new Searcher(fieldName, values.iterator().next(), Op.EQ));
+        } else {
+            searchers.add(new Searcher(fieldName, values.toArray(), Op.IN));
+        }
+        return this;
+    }
+
+    public static Specification IN(String fieldName, Collection<?> values) {
+        if (values == null || values.size() == 0) {
+            throw new IllegalArgumentException("In Values must be not empty.");
+        }
+        if (values.size() == 1) {
+            return (root, query, cb) -> cb.equal(root.get(fieldName), values.iterator().next());
+        }
+        return (root, query, cb) -> root.get(fieldName).in(values);
+    }
+
+    public SearchBuilder notIn(String fieldName, Collection<?> values) {
+        if (values == null || values.size() == 0) {
+            throw new IllegalArgumentException("In Values must be not empty.");
+        }
+        if (values.size() == 1) {
+            searchers.add(new Searcher(fieldName, values.iterator().next(), Op.NOT_EQ));
+        } else {
+            searchers.add(new Searcher(fieldName, values.toArray(), Op.NOT_IN));
+        }
+        return this;
+    }
+
+    public static Specification NOT_IN(String fieldName, Collection<?> values) {
+        if (values == null || values.size() == 0) {
+            throw new IllegalArgumentException("In Values must be not empty.");
+        }
+        if (values.size() == 1) {
+            return (root, query, cb) -> cb.notEqual(root.get(fieldName), values.iterator().next());
+        }
+        return (root, query, cb) -> root.get(fieldName).in(values).not();
+    }
+
+    public SearchBuilder isNull(String fieldName) {
+        searchers.add(new Searcher(fieldName, null, Op.IS_NULL));
+        return this;
+    }
+
+    public static Specification IS_NULL(String fieldName) {
+        return (root, query, cb) -> cb.isNull(root.get(fieldName));
+    }
+
+    public SearchBuilder notNull(String fieldName) {
+        searchers.add(new Searcher(fieldName, null, Op.NOT_NULL));
+        return this;
+    }
+
+    public static Specification NOT_NULL(String fieldName) {
+        return (root, query, cb) -> cb.isNotNull(root.get(fieldName));
+    }
+
+    public static class Searcher<T> {
+        /**
+         * 属性名
+         */
+        private String fieldName;
+        /**
+         * 属性值
+         */
+        private T value;
+        /**
+         * 操作的表达式
+         */
+        private Op op;
+
+        private Searcher(String fieldName, T value, Op op) {
+            if (fieldName == null || "".equals(fieldName.trim())) {
+                throw new IllegalArgumentException("FieldName must be not empty.");
+            }
+            if (op == null) {
+                throw new IllegalArgumentException("Operator must be not empty.");
+            }
+            this.fieldName = fieldName.trim();
+            this.value = value;
+            this.op = op;
+        }
+
+        public String getFieldName() {
+            return fieldName;
+        }
+
+        public T getValue() {
+            return value;
+        }
+
+        public Op getOp() {
+            return op;
+        }
+    }
+
+}

+ 0 - 146
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Searcher.java

@@ -1,146 +0,0 @@
-/*
- * *************************************************
- * Copyright (c) 2018 QMTH. All Rights Reserved.
- * Created by Deason on 2018-10-17 15:18:02.
- * *************************************************
- */
-
-package cn.com.qmth.examcloud.core.print.common.jpa;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * 查询条件类
- *
- * @author: fengdesheng
- * @since: 2018/10/17
- */
-public class Searcher implements Serializable {
-    protected static final long serialVersionUID = -1L;
-    /**
-     * 属性名
-     */
-    private String fieldName;
-    /**
-     * 属性值
-     */
-    private Object value;
-    /**
-     * 操作的表达式
-     */
-    private Op op;
-
-    private List<Searcher> searchers = new ArrayList<>();
-
-    public <T> Searcher eq(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.EQ));
-        return this;
-    }
-
-    public <T> Searcher notEq(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.NOT_EQ));
-        return this;
-    }
-
-    public <T> Searcher gt(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.GT));
-        return this;
-    }
-
-    public <T> Searcher gte(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.GTE));
-        return this;
-    }
-
-    public <T> Searcher lt(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.LT));
-        return this;
-    }
-
-    public <T> Searcher lte(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.LTE));
-        return this;
-    }
-
-    public <T> Searcher like(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.LIKE));
-        return this;
-    }
-
-    public <T> Searcher leftLike(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.L_LIKE));
-        return this;
-    }
-
-    public <T> Searcher rightLike(String fieldName, T value) {
-        searchers.add(new Searcher(fieldName, value, Op.R_LIKE));
-        return this;
-    }
-
-    public Searcher in(String fieldName, Collection<?> values) {
-        if (values == null || values.size() == 0) {
-            throw new IllegalArgumentException("Values must be not empty.");
-        }
-        if (values.size() == 1) {
-            searchers.add(new Searcher(fieldName, values.iterator().next(), Op.EQ));
-        } else {
-            searchers.add(new Searcher(fieldName, values.toArray(), Op.IN));
-        }
-        return this;
-    }
-
-    public Searcher notIn(String fieldName, Collection<?> values) {
-        if (values == null || values.size() == 0) {
-            throw new IllegalArgumentException("Values must be not empty.");
-        }
-        if (values.size() == 1) {
-            searchers.add(new Searcher(fieldName, values.iterator().next(), Op.NOT_EQ));
-        } else {
-            searchers.add(new Searcher(fieldName, values.toArray(), Op.NOT_IN));
-        }
-        return this;
-    }
-
-    public Searcher isNull(String fieldName) {
-        searchers.add(new Searcher(fieldName, null, Op.IS_NULL));
-        return this;
-    }
-
-    public Searcher notNull(String fieldName) {
-        searchers.add(new Searcher(fieldName, null, Op.NOT_NULL));
-        return this;
-    }
-
-    public List<Searcher> build() {
-        return searchers;
-    }
-
-    private Searcher(String fieldName, Object value, Op op) {
-        if (fieldName == null || "".equals(fieldName.trim())) {
-            throw new IllegalArgumentException("FieldName must be not empty.");
-        }
-        this.fieldName = fieldName.trim();
-        this.value = value;
-        this.op = op;
-    }
-
-    public Searcher() {
-
-    }
-
-    public String getFieldName() {
-        return fieldName;
-    }
-
-    public Object getValue() {
-        return value;
-    }
-
-    public Op getOp() {
-        return op;
-    }
-
-}

+ 66 - 66
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/SpecUtils.java

@@ -13,7 +13,8 @@ import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.data.jpa.domain.Specifications;
 
-import javax.persistence.criteria.*;
+import javax.persistence.criteria.Path;
+import javax.persistence.criteria.Predicate;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -47,80 +48,77 @@ public class SpecUtils {
         return new PageRequest(pageNo - 1, pageSize, sort);
     }
 
-    public static <T> Specification<T> buildSearchers(final Class<T> clazz, final List<Searcher> searchers) {
+    public static <T> Specification<T> buildSearchers(final Class<T> clazz, final List<SearchBuilder.Searcher> searchers) {
         return buildSearchers(clazz, searchers, false);
     }
 
-    public static <T> Specification<T> buildSearchers(final Class<T> clazz, final List<Searcher> searchers, final boolean isOR) {
+    public static <T> Specification<T> buildSearchers(final Class<T> clazz, final List<SearchBuilder.Searcher> searchers, final boolean isOR) {
         if (searchers == null || searchers.size() == 0) {
             return null;
         }
-        return new Specification<T>() {
-            @Override
-            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
-                List<Predicate> predicates = new ArrayList<>();
-                for (Searcher filter : searchers) {
-                    if (filter.getFieldName() == null || "".equals(filter.getFieldName())) {
-                        continue;
-                    }
-                    String[] names = filter.getFieldName().split("\\.");
-                    Path expression = root.get(names[0]);
-                    for (int i = 1; i < names.length; i++) {
-                        expression = expression.get(names[i]);
-                    }
-                    switch (filter.getOp()) {
-                        case EQ:
-                            predicates.add(builder.equal(expression, filter.getValue()));
-                            break;
-                        case NOT_EQ:
-                            predicates.add(builder.notEqual(expression, filter.getValue()));
-                            break;
-                        case GT:
-                            predicates.add(builder.greaterThan(expression, (Comparable) filter.getValue()));
-                            break;
-                        case GTE:
-                            predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.getValue()));
-                            break;
-                        case LT:
-                            predicates.add(builder.lessThan(expression, (Comparable) filter.getValue()));
-                            break;
-                        case LTE:
-                            predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.getValue()));
-                            break;
-                        case LIKE:
-                            predicates.add(builder.like(expression, "%" + filter.getValue() + "%"));
-                            break;
-                        case L_LIKE:
-                            predicates.add(builder.like(expression, "%" + filter.getValue()));
-                            break;
-                        case R_LIKE:
-                            predicates.add(builder.like(expression, filter.getValue() + "%"));
-                            break;
-                        case IS_NULL:
-                            predicates.add(builder.isNull(expression));
-                            break;
-                        case NOT_NULL:
-                            predicates.add(builder.isNotNull(expression));
-                            break;
-                        case IN:
-                            predicates.add(expression.in((Object[]) filter.getValue()));
-                            break;
-                        case NOT_IN:
-                            predicates.add(expression.in((Object[]) filter.getValue()).not());
-                            break;
-                    }
+        return (root, query, builder) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            for (SearchBuilder.Searcher filter : searchers) {
+                if (filter.getFieldName() == null || "".equals(filter.getFieldName())) {
+                    continue;
                 }
-                if (!predicates.isEmpty()) {
-                    if (isOR) {
-                        //将所有条件用 or 联合起来
-                        return builder.or(predicates.toArray(new Predicate[predicates.size()]));
-                    } else {
-                        //将所有条件用 and 联合起来
-                        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
-                    }
+                String[] names = filter.getFieldName().split("\\.");
+                Path expression = root.get(names[0]);
+                for (int i = 1; i < names.length; i++) {
+                    expression = expression.get(names[i]);
+                }
+                switch (filter.getOp()) {
+                    case EQ:
+                        predicates.add(builder.equal(expression, filter.getValue()));
+                        break;
+                    case NOT_EQ:
+                        predicates.add(builder.notEqual(expression, filter.getValue()));
+                        break;
+                    case GT:
+                        predicates.add(builder.greaterThan(expression, (Comparable) filter.getValue()));
+                        break;
+                    case GTE:
+                        predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.getValue()));
+                        break;
+                    case LT:
+                        predicates.add(builder.lessThan(expression, (Comparable) filter.getValue()));
+                        break;
+                    case LTE:
+                        predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.getValue()));
+                        break;
+                    case LIKE:
+                        predicates.add(builder.like(expression, "%" + filter.getValue() + "%"));
+                        break;
+                    case L_LIKE:
+                        predicates.add(builder.like(expression, "%" + filter.getValue()));
+                        break;
+                    case R_LIKE:
+                        predicates.add(builder.like(expression, filter.getValue() + "%"));
+                        break;
+                    case IS_NULL:
+                        predicates.add(builder.isNull(expression));
+                        break;
+                    case NOT_NULL:
+                        predicates.add(builder.isNotNull(expression));
+                        break;
+                    case IN:
+                        predicates.add(expression.in((Object[]) filter.getValue()));
+                        break;
+                    case NOT_IN:
+                        predicates.add(expression.in((Object[]) filter.getValue()).not());
+                        break;
+                }
+            }
+            if (!predicates.isEmpty()) {
+                if (isOR) {
+                    //将所有条件用 or 联合起来
+                    return builder.or(predicates.toArray(new Predicate[predicates.size()]));
+                } else {
+                    //将所有条件用 and 联合起来
+                    return builder.and(predicates.toArray(new Predicate[predicates.size()]));
                 }
-                return builder.conjunction();
             }
+            return builder.conjunction();
         };
     }
 
@@ -129,6 +127,8 @@ public class SpecUtils {
     }
 
     public static Specification orMerge(Specification target1, Specification target2) {
+        // 注:SQL中AND优先级高于OR
+        // 示例:... t.name='' or t.age=1 and t.gender=1 等于 ... t.name='' or (t.age=1 and t.gender=1)
         return Specifications.where(target1).or(target2);
     }
 

+ 27 - 1
examcloud-core-print-starter/src/test/java/cn/com/qmth/examcloud/core/print/test/PrintingProjectServiceTest.java

@@ -8,13 +8,22 @@
 package cn.com.qmth.examcloud.core.print.test;
 
 import cn.com.qmth.examcloud.core.print.PrintApplication;
+import cn.com.qmth.examcloud.core.print.common.jpa.OrderBuilder;
+import cn.com.qmth.examcloud.core.print.common.jpa.SearchBuilder;
+import cn.com.qmth.examcloud.core.print.common.jpa.SpecUtils;
+import cn.com.qmth.examcloud.core.print.common.utils.JsonMapper;
+import cn.com.qmth.examcloud.core.print.entity.PrintingProject;
+import cn.com.qmth.examcloud.core.print.repository.PrintingProjectRepository;
 import cn.com.qmth.examcloud.core.print.service.PrintingProjectService;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.jpa.domain.Specification;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.util.List;
+
 /**
  * @author: fengdesheng
  * @since: 2018/10/17
@@ -24,10 +33,27 @@ import org.springframework.test.context.junit4.SpringRunner;
 public class PrintingProjectServiceTest {
     @Autowired
     private PrintingProjectService printingProjectService;
+    @Autowired
+    private PrintingProjectRepository printingProjectRepository;
 
     @Test
     public void demoTest() throws Exception {
-        System.out.println("...");
+        //查询条件1
+        SearchBuilder searchBuilder1 = new SearchBuilder().eq("orgName", "abc");
+        Specification<PrintingProject> spec1 = SpecUtils.buildSearchers(PrintingProject.class, searchBuilder1.build());
+
+        //查询条件2
+        SearchBuilder searchBuilder2 = new SearchBuilder().eq("orgId", 1L).eq("examId", 1L);
+        Specification<PrintingProject> spec2 = SpecUtils.buildSearchers(PrintingProject.class, searchBuilder2.build(), true);
+
+        //合并查询条件
+        //Specification<PrintingProject> spec = SpecUtils.orMerge(spec1, spec2);
+        //Specification<PrintingProject> spec = SpecUtils.andMerge(spec1, spec2);
+        Specification<PrintingProject> spec = SearchBuilder.EQ("orgId", 1L);
+
+        OrderBuilder orderBuilder = new OrderBuilder().desc("id");
+        List<PrintingProject> list = printingProjectRepository.findAll(spec, orderBuilder.build());
+        System.out.println(new JsonMapper().toJson(list));
     }
 
 }