1. 程式人生 > >SpringDataJPA學習記錄(三)--複雜查詢的封裝

SpringDataJPA學習記錄(三)--複雜查詢的封裝

SpringDataJPA學習記錄(三)–複雜查詢的封裝

標籤(空格分隔): springJPA

1.使用CriteriaBuilder構建JPQL

在UserRepositoryImpl中使用CriteriaBuilder實現根據id查詢,下面是程式碼:

    public void findById(Integer id){
        //select u from User u where u.id = 1

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> cq = cb.createQuery
(User.class); Root<User> root = cq.from(User.class); //from User cq.select(root); //select * from User javax.persistence.criteria.Predicate pre = cb.equal(root.get("id").as(Integer.class),id);//id=1 cq.where(pre);//where id=1 Query query = entityManager.createQuery
(cq);//select u from User u where u.id = 1 System.out.println(query.getResultList()); }

缺點:
1. 程式碼量多
2. 不易維護
3. 條件複雜的話,則會顯得很混亂.

個人認為,CriteriaQuery不適合用來複雜sql的查詢實現,不過可以使用其對一些通用的sql查詢封裝到BaseDao中.具體封裝接著往下看.

2.使用JpaSpecificationExecutor查詢

該介面有如下方法,裡面傳入條件都是Specification,該介面會返回一個Predicate條件集合,因此就可以在這裡封裝.

public interface JpaSpecificationExecutor<T> {

    T findOne(Specification<T> spec);

    List<T> findAll(Specification<T> spec);

    Page<T> findAll(Specification<T> spec, Pageable pageable);

    List<T> findAll(Specification<T> spec, Sort sort);

    long count(Specification<T> spec);
}

1.構造過濾條件集合

寫法學習自shop++專案.
Operator列舉類裡面的operator屬性為了構建原生sql使用

/**
 * @author Niu Li
 * @date 2016/11/17
 */

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

import java.io.Serializable;

/**
 * 篩選
 * copy from shopXX
 */
public class Filter implements Serializable {

    private static final long serialVersionUID = -8712382358441065075L;

    /**
     * 運算子
     */
    public enum Operator {

        /** 等於 */
        eq(" = "),

        /** 不等於 */
        ne(" != "),

        /** 大於 */
        gt(" > "),

        /** 小於 */
        lt(" < "),

        /** 大於等於 */
        ge(" >= "),

        /** 小於等於 */
        le(" <= "),

        /** 類似 */
        like(" like "),

        /** 包含 */
        in(" in "),

        /** 為Null */
        isNull(" is NULL "),

        /** 不為Null */
        isNotNull(" is not NULL ");
        Operator(String operator) {
            this.operator = operator;
        }

        private String operator;

        public String getOperator() {
            return operator;
        }

        public void setOperator(String operator) {
            this.operator = operator;
        }
    }

    /** 預設是否忽略大小寫 */
    private static final boolean DEFAULT_IGNORE_CASE = false;

    /** 屬性 */
    private String property;

    /** 運算子 */
    private Filter.Operator operator;

    /** 值 */
    private Object value;

    /** 是否忽略大小寫 */
    private Boolean ignoreCase = DEFAULT_IGNORE_CASE;

    /**
     * 構造方法
     */
    public Filter() {
    }

    /**
     * 構造方法
     *
     * @param property
     *            屬性
     * @param operator
     *            運算子
     * @param value
     *            值
     */
    public Filter(String property, Filter.Operator operator, Object value) {
        this.property = property;
        this.operator = operator;
        this.value = value;
    }

    /**
     * 構造方法
     *
     * @param property
     *            屬性
     * @param operator
     *            運算子
     * @param value
     *            值
     * @param ignoreCase
     *            忽略大小寫
     */
    public Filter(String property, Filter.Operator operator, Object value, boolean ignoreCase) {
        this.property = property;
        this.operator = operator;
        this.value = value;
        this.ignoreCase = ignoreCase;
    }

    /**
     * 返回等於篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @return 等於篩選
     */
    public static Filter eq(String property, Object value) {
        return new Filter(property, Filter.Operator.eq, value);
    }

    /**
     * 返回等於篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @param ignoreCase
     *            忽略大小寫
     * @return 等於篩選
     */
    public static Filter eq(String property, Object value, boolean ignoreCase) {
        return new Filter(property, Filter.Operator.eq, value, ignoreCase);
    }

    /**
     * 返回不等於篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @return 不等於篩選
     */
    public static Filter ne(String property, Object value) {
        return new Filter(property, Filter.Operator.ne, value);
    }

    /**
     * 返回不等於篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @param ignoreCase
     *            忽略大小寫
     * @return 不等於篩選
     */
    public static Filter ne(String property, Object value, boolean ignoreCase) {
        return new Filter(property, Filter.Operator.ne, value, ignoreCase);
    }

    /**
     * 返回大於篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @return 大於篩選
     */
    public static Filter gt(String property, Object value) {
        return new Filter(property, Filter.Operator.gt, value);
    }

    /**
     * 返回小於篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @return 小於篩選
     */
    public static Filter lt(String property, Object value) {
        return new Filter(property, Filter.Operator.lt, value);
    }

    /**
     * 返回大於等於篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @return 大於等於篩選
     */
    public static Filter ge(String property, Object value) {
        return new Filter(property, Filter.Operator.ge, value);
    }

    /**
     * 返回小於等於篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @return 小於等於篩選
     */
    public static Filter le(String property, Object value) {
        return new Filter(property, Filter.Operator.le, value);
    }

    /**
     * 返回相似篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @return 相似篩選
     */
    public static Filter like(String property, Object value) {
        return new Filter(property, Filter.Operator.like, value);
    }

    /**
     * 返回包含篩選
     *
     * @param property
     *            屬性
     * @param value
     *            值
     * @return 包含篩選
     */
    public static Filter in(String property, Object value) {
        return new Filter(property, Filter.Operator.in, value);
    }

    /**
     * 返回為Null篩選
     *
     * @param property
     *            屬性
     * @return 為Null篩選
     */
    public static Filter isNull(String property) {
        return new Filter(property, Filter.Operator.isNull, null);
    }

    /**
     * 返回不為Null篩選
     *
     * @param property
     *            屬性
     * @return 不為Null篩選
     */
    public static Filter isNotNull(String property) {
        return new Filter(property, Filter.Operator.isNotNull, null);
    }

    /**
     * 返回忽略大小寫篩選
     *
     * @return 忽略大小寫篩選
     */
    public Filter ignoreCase() {
        this.ignoreCase = true;
        return this;
    }

    /**
     * 獲取屬性
     *
     * @return 屬性
     */
    public String getProperty() {
        return property;
    }

    /**
     * 設定屬性
     *
     * @param property
     *            屬性
     */
    public void setProperty(String property) {
        this.property = property;
    }

    /**
     * 獲取運算子
     *
     * @return 運算子
     */
    public Filter.Operator getOperator() {
        return operator;
    }

    /**
     * 設定運算子
     *
     * @param operator
     *            運算子
     */
    public void setOperator(Filter.Operator operator) {
        this.operator = operator;
    }

    /**
     * 獲取值
     *
     * @return 值
     */
    public Object getValue() {
        return value;
    }

    /**
     * 設定值
     *
     * @param value
     *            值
     */
    public void setValue(Object value) {
        this.value = value;
    }

    /**
     * 獲取是否忽略大小寫
     *
     * @return 是否忽略大小寫
     */
    public Boolean getIgnoreCase() {
        return ignoreCase;
    }

    /**
     * 設定是否忽略大小寫
     *
     * @param ignoreCase
     *            是否忽略大小寫
     */
    public void setIgnoreCase(Boolean ignoreCase) {
        this.ignoreCase = ignoreCase;
    }

    /**
     * 重寫equals方法
     *
     * @param obj
     *            物件
     * @return 是否相等
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        Filter other = (Filter) obj;
        return new EqualsBuilder().append(getProperty(), other.getProperty()).append(getOperator(), other.getOperator()).append(getValue(), other.getValue()).isEquals();
    }

    /**
     * 重寫hashCode方法
     *
     * @return HashCode
     */
    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37).append(getProperty()).append(getOperator()).append(getValue()).toHashCode();
    }

}

2.構造排序欄位

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.io.Serializable;
/**
 * 排序
 *
 * @author copy from shopxx
 */
public class Order implements Serializable {

    private static final long serialVersionUID = -3078342809727773232L;

    /**
     * 方向
     */
    public enum Direction {

        /** 遞增 */
        asc,

        /** 遞減 */
        desc
    }

    /** 預設方向 */
    private static final Order.Direction DEFAULT_DIRECTION = Order.Direction.desc;

    /** 屬性 */
    private String property;

    /** 方向 */
    private Order.Direction direction = DEFAULT_DIRECTION;

    @Override
    public String toString() {
        return property+" " + direction.name();
    }

    /**
     * 構造方法
     */
    public Order() {
    }

    /**
     * 構造方法
     *
     * @param property
     *            屬性
     * @param direction
     *            方向
     */
    public Order(String property, Order.Direction direction) {
        this.property = property;
        this.direction = direction;
    }

    /**
     * 返回遞增排序
     *
     * @param property
     *            屬性
     * @return 遞增排序
     */
    public static Order asc(String property) {
        return new Order(property, Order.Direction.asc);
    }

    /**
     * 返回遞減排序
     *
     * @param property
     *            屬性
     * @return 遞減排序
     */
    public static Order desc(String property) {
        return new Order(property, Order.Direction.desc);
    }

    /**
     * 獲取屬性
     *
     * @return 屬性
     */
    public String getProperty() {
        return property;
    }

    /**
     * 設定屬性
     *
     * @param property
     *            屬性
     */
    public void setProperty(String property) {
        this.property = property;
    }

    /**
     * 獲取方向
     *
     * @return 方向
     */
    public Order.Direction getDirection() {
        return direction;
    }

    /**
     * 設定方向
     *
     * @param direction
     *            方向
     */
    public void setDirection(Order.Direction direction) {
        this.direction = direction;
    }

    /**
     * 重寫equals方法
     *
     * @param obj
     *            物件
     * @return 是否相等
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        Order other = (Order) obj;
        return new EqualsBuilder().append(getProperty(), other.getProperty()).append(getDirection(), other.getDirection()).isEquals();
    }

    /**
     * 重寫hashCode方法
     *
     * @return HashCode
     */
    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37).append(getProperty()).append(getDirection()).toHashCode();
    }

}

3.查詢語句生成

3.1基本框架
/**
 * 封裝查詢條件的實體
 * @author Niu Li
 * @date 2016/11/17
 */
public class QueryParams<T> implements Specification<T> {

    /** 屬性分隔符 */
    private static final String PROPERTY_SEPARATOR = ".";
    /**
     * and條件
     */
    private List<Filter> andFilters = new ArrayList<>();
    /**
     * or條件
     */
    private List<Filter> orFilters = new ArrayList<>();
    /**
     * 排序屬性
     */
    private List<Order> orders = new ArrayList<>();
        /**
     * 獲取Path
     *
     * @param path
     *            Path
     * @param propertyPath
     *            屬性路徑
     * @return Path
     */
    @SuppressWarnings("unchecked")
    private <X> Path<X> getPath(Path<?> path, String propertyPath) {
        if (path == null || StringUtils.isEmpty(propertyPath)) {
            return (Path<X>) path;
        }
        String property = StringUtils.substringBefore(propertyPath, PROPERTY_SEPARATOR);
        return getPath(path.get(property), StringUtils.substringAfter(propertyPath, PROPERTY_SEPARATOR));
    }
}
3.2分析and條件:


    /**
     * 轉換為Predicate
     *
     * @param root
     *            Root
     * @return Predicate
     */
    @SuppressWarnings("unchecked")
    private Predicate toAndPredicate(Root<T> root,CriteriaBuilder criteriaBuilder) {
        Predicate restrictions = criteriaBuilder.conjunction();
        if (root == null || CollectionUtils.isEmpty(andFilters)) {
            return restrictions;
        }
        for (Filter filter : andFilters) {
            if (filter == null) {
                continue;
            }
            String property = filter.getProperty();
            Filter.Operator operator = filter.getOperator();
            Object value = filter.getValue();
            Boolean ignoreCase = filter.getIgnoreCase();
            Path<?> path = getPath(root, property);
            if (path == null) {
                continue;
            }
            //根據運算子生成相應條件
            switch (operator) {
                case eq:
                    if (value != null) {
                        if (BooleanUtils.isTrue(ignoreCase) && String.class.isAssignableFrom(path.getJavaType()) && value instanceof String) {
                            restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.equal(criteriaBuilder.lower((Path<String>) path), ((String) value).toLowerCase()));
                        } else {
                            restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.equal(path, value));
                        }
                    } else {
                        restrictions = criteriaBuilder.and(restrictions, path.isNull());
                    }
                    break;
                case ne:
                    if (value != null) {
                        if (BooleanUtils.isTrue(ignoreCase) && String.class.isAssignableFrom(path.getJavaType()) && value instanceof String) {
                            restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.notEqual(criteriaBuilder.lower((Path<String>) path), ((String) value).toLowerCase()));
                        } else {
                            restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.notEqual(path, value));
                        }
                    } else {
                        restrictions = criteriaBuilder.and(restrictions, path.isNotNull());
                    }
                    break;
                case gt:
                    if (Number.class.isAssignableFrom(path.getJavaType()) && value instanceof Number) {
                        restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.gt((Path<Number>) path, (Number) value));
                    }
                    break;
                case lt:
                    if (Number.class.isAssignableFrom(path.getJavaType()) && value instanceof Number) {
                        restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.lt((Path<Number>) path, (Number) value));
                    }
                    break;
                case ge:
                    if (Number.class.isAssignableFrom(path.getJavaType()) && value instanceof Number) {
                        restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.ge((Path<Number>) path, (Number) value));
                    }
                    break;
                case le:
                    if (Number.class.isAssignableFrom(path.getJavaType()) && value instanceof Number) {
                        restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.le((Path<Number>) path, (Number) value));
                    }
                    break;
                case like:
                    if (String.class.isAssignableFrom(path.getJavaType()) && value instanceof String) {
                        if (BooleanUtils.isTrue(ignoreCase)) {
                            restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.like(criteriaBuilder.lower((Path<String>) path), ((String) value).toLowerCase()));
                        } else {
                            restrictions = criteriaBuilder.and(restrictions, criteriaBuilder.like((Path<String>) path, (String) value));
                        }
                    }
                    break;
                case in:
                    restrictions = criteriaBuilder.and(restrictions, path.in(value));
                    break;
                case isNull:
                    restrictions = criteriaBuilder.and(restrictions, path.isNull());
                    break;
                case isNotNull:
                    restrictions = criteriaBuilder.and(restrictions, path.isNotNull());
                    break;
            }
        }
        return restrictions;
    }
3.3分析or條件:

把and中的and改為or即可

 /**
     * 轉換為Predicate
     *
     * @param root
     *            Root
     * @return Predicate
     */
    @SuppressWarnings("unchecked")
    private Predicate toOrPredicate(Root<T> root,CriteriaBuilder criteriaBuilder) {
        Predicate restrictions = criteriaBuilder.disjunction();
        if (root == null || CollectionUtils.isEmpty(andFilters)) {
            return restrictions;
        }
        for (Filter filter : orFilters) {
            if (filter == null) {
                continue;
            }
            String property = filter.getProperty();
            Filter.Operator operator = filter.getOperator();
            Object value = filter.getValue();
            Boolean ignoreCase = filter.getIgnoreCase();
            Path<?> path = getPath(root, property);
            if (path == null) {
                continue;
            }
            switch (operator) {
                case eq:
                    if (value != null) {
                        if (BooleanUtils.isTrue(ignoreCase) && String.class.isAssignableFrom(path.getJavaType()) && value instanceof String) {
                            restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.equal(criteriaBuilder.lower((Path<String>) path), ((String) value).toLowerCase()));
                        } else {
                            restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.equal(path, value));
                        }
                    } else {
                        restrictions = criteriaBuilder.or(restrictions, path.isNull());
                    }
                    break;
                case ne:
                    if (value != null) {
                        if (BooleanUtils.isTrue(ignoreCase) && String.class.isAssignableFrom(path.getJavaType()) && value instanceof String) {
                            restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.notEqual(criteriaBuilder.lower((Path<String>) path), ((String) value).toLowerCase()));
                        } else {
                            restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.notEqual(path, value));
                        }
                    } else {
                        restrictions = criteriaBuilder.or(restrictions, path.isNotNull());
                    }
                    break;
                case gt:
                    if (Number.class.isAssignableFrom(path.getJavaType()) && value instanceof Number) {
                        restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.gt((Path<Number>) path, (Number) value));
                    }
                    break;
                case lt:
                    if (Number.class.isAssignableFrom(path.getJavaType()) && value instanceof Number) {
                        restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.lt((Path<Number>) path, (Number) value));
                    }
                    break;
                case ge:
                    if (Number.class.isAssignableFrom(path.getJavaType()) && value instanceof Number) {
                        restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.ge((Path<Number>) path, (Number) value));
                    }
                    break;
                case le:
                    if (Number.class.isAssignableFrom(path.getJavaType()) && value instanceof Number) {
                        restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.le((Path<Number>) path, (Number) value));
                    }
                    break;
                case like:
                    if (String.class.isAssignableFrom(path.getJavaType()) && value instanceof String) {
                        if (BooleanUtils.isTrue(ignoreCase)) {
                            restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.like(criteriaBuilder.lower((Path<String>) path), ((String) value).toLowerCase()));
                        } else {
                            restrictions = criteriaBuilder.or(restrictions, criteriaBuilder.like((Path<String>) path, (String) value));
                        }
                    }
                    break;
                case in:
                    restrictions = criteriaBuilder.or(restrictions, path.in(value));
                    break;
                case isNull:
                    restrictions = criteriaBuilder.or(restrictions, path.isNull());
                    break;
                case isNotNull:
                    restrictions = criteriaBuilder.or(restrictions, path.isNotNull());
                    break;
            }
        }
        return restrictions;
    }
3.4分析排序條件:
/**
     * 轉換為Order
     *
     * @param root
     *            Root
     * @return Order
     */
    private List<javax.persistence.criteria.Order> toOrders(Root<T> root,CriteriaBuilder criteriaBuilder) {
        List<javax.persistence.criteria.Order> orderList = new ArrayList<javax.persistence.criteria.Order>();
        if (root == null || CollectionUtils.isEmpty(orders)) {
            return orderList;
        }
        for (Order order : orders) {
            if (order == null) {
                continue;
            }
            String property = order.getProperty();
            Order.Direction direction = order.getDirection();
            Path<?> path = getPath(root, property);
            if (path == null || direction == null) {
                continue;
            }
            switch (direction) {
                case asc:
                    orderList.add(criteriaBuilder.asc(path));
                    break;
                case desc:
                    orderList.add(criteriaBuilder.desc(path));
                    break;
            }
        }
        return orderList;
    }

最後在toPredicate方法中構造最終條件

    /**
     * 生成條件的
     * @param root 該物件的封裝
     * @param query 查詢構建器
     * @param cb 構建器
     * @return 條件集合
     */
    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        Predicate restrictions = cb.and(toAndPredicate(root,cb));
        restrictions = cb.and(restrictions,toOrPredicate(root,cb));
        query.orderBy(toOrders(root,cb));
        return restrictions;
    }

加上方便的鏈式呼叫方法

    /**
     * 新增一個and條件
     * @param filter 該條件
     * @return 鏈式呼叫
     */
    public  QueryParams and(Filter filter){
        this.andFilters.add(filter);
        return this;
    }
    /**
     * 新增多個and條件
     * @param filter 該條件
     * @return 鏈式呼叫
     */
    public  QueryParams and(Filter ...filter){
        this.andFilters.addAll(Arrays.asList(filter));
        return this;
    }
    /**
     * 新增一個or條件
     * @param filter 該條件
     * @return 鏈式呼叫
     */
    public  QueryParams or(Filter filter){
        this.orFilters.add(filter);
        return this;
    }
    /**
     * 新增多個or條件
     * @param filter 該條件
     * @return 鏈式呼叫
     */
    public  QueryParams or(Filter ...filter){
        this.orFilters.addAll(Arrays.asList(filter));
        return this;
    }
    /**
     * 升序欄位
     * @param property 該欄位對應變數名
     * @return 鏈式呼叫
     */
    public  QueryParams orderASC(String property){
        this.orders.add(Order.asc(property));
        return this;
    }
    /**
     * 降序欄位
     * @param property 該欄位對應變數名
     * @return 鏈式呼叫
     */
    public  QueryParams orderDESC(String property){
        this.orders.add(Order.desc(property));
        return this;
    }

    /**
     * 清除所有條件
     * @return 該例項
     */
    public QueryParams clearAll(){
        if (!this.andFilters.isEmpty()) this.andFilters.clear();
        if (!this.orFilters.isEmpty()) this.orFilters.clear();
        if (!this.orders.isEmpty()) this.orders.clear();
        return this;
    }
    /**
     * 清除and條件
     * @return 該例項
     */
    public QueryParams clearAnd(){
        if (!this.andFilters.isEmpty()) this.andFilters.clear();
        return this;
    }
    /**
     * 清除or條件
     * @return 該例項
     */
    public QueryParams clearOr(){
        if (!this.orFilters.isEmpty()) this.andFilters.clear();
        return this;
    }
    /**
     * 清除order條件
     * @return 該例項
     */
    public QueryParams clearOrder(){
        if (!this.orders.isEmpty()) this.orders.clear();
        return this;
    }
    //省略get和set方法
3.5測試:

首先讓PcardOrderRepository介面繼承加上JpaSpecificationExecutor

public interface PcardOrderRepository extends JpaRepository<PcardOrder,String>
        ,PcardOrderRepositoryCustom,JpaSpecificationExecutor<PcardOrder> {

}

編寫測試程式碼,這個使用的是CriteriaBuilder構建查詢的,所以查詢欄位都是JPQL欄位,並不是原生sql

     QueryParams<PcardOrder> queryParams = new QueryParams<>();
        //使用Specification條件查詢,使用JPQL欄位查詢
        queryParams
                .and(Filter.eq("acctId","0014779934917371041"),Filter.ne("orderAmt",0L),
                        Filter.eq("orderRespCd","00"))
                .or(Filter.eq("orderTypeId","A003"),Filter.eq("orderTypeId","A007"),
                        Filter.eq("orderTypeId","A021"),Filter.eq("orderTypeId","A018"))
                .orderDESC("createTime");

        Page<PcardOrder> JPQLlist = pcardOrderRepository.findAll(queryParams,new PageRequest(0,2));

        //構造出來的條件
        where
        1=1 
        and pcardorder0_.acct_id=? 
        and pcardorder0_.order_amt<>0 
        and pcardorder0_.order_resp_cd=? 
        and (
            0=1 
            or pcardorder0_.order_type_id=? 
            or pcardorder0_.order_type_id=? 
            or pcardorder0_.order_type_id=? 
            or pcardorder0_.order_type_id=?
        ) 
    order by
        pcardorder0_.create_time desc limit ?

3.原生sql查詢

還是利用上面的Filter,具體還是遍歷+拼接,示例中我解除安裝了公共方法中,需要使用的Impl直接extends即可.

1.解析條件

解析條件實際上就是拼接sql,程式碼很簡單.

/**
 * 公共方法的repository
 * @author Niu Li
 * @date 2016/11/17
 */
@NoRepositoryBean
public class BaseRepository {

    private static Logger logger = LoggerFactory.getLogger(BaseRepository.class);

    /**
     * 分析查詢引數,並且合併到sql語句中
     * @param sql JPQL查詢語句
     * @param params 查詢引數
     * @return 引數對應的value
     */
    @SuppressWarnings("Unchecked")
    protected List<Object> analysisQueryParams(StringBuilder sql, QueryParams<?> params){
        List<String> strList = new ArrayList<>();
        List<Object> valueList = new ArrayList<>();
        int i = 1;
        //分析or條件
        for (Filter filter : params.getOrFilters()) {
            if (filter.getValue() != null){
                strList.add(filter.getProperty()+" " + filter.getOperator().getOperator()+" ?" + (i++));
                valueList.add(filter.getValue());
            }else {
                strList.add(filter.getProperty()+" " + filter.getOperator().getOperator()+" ");
            }
        }
        if (!strList.isEmpty()){
            sql.append(" and ").append("( ").append(StringUtils.join(strList," or ")).append(" )");
        }
        strList.clear();
        //分析and條件
        for (Filter filter : params.getAndFilters()) {
            if (filter.getValue() != null){
                strList.add(filter.getProperty()+" " + filter.getOperator().getOperator()+" ?" + (i++));
                valueList.add(filter.getValue());
            }else {
                strList.add(filter.getProperty()+" " + filter.getOperator().getOperator()+" ");
            }
        }
        sql.append(" and ").append(StringUtils.join(strList," and "));
        //分析排序欄位
        if (!params.getOrders().isEmpty()){
            sql.append(" order by ");
            sql.append(StringUtils.join(params.getOrders(),","));
        }
        logger.debug("解析後的sql:"+sql.toString());
        logger.debug("對應的值為:"+valueList);
        return valueList;
    }

}

2.測試

在自定義介面中加入方法

/**
 * @author Niu Li
 * @date 2016/11/17
 */
public interface PcardOrderRepositoryCustom {

    List findByQueryParam(QueryParams queryParams, Pageable pageable);
}

然後實現類中需要寫部分sql

/**
 * @author Niu Li
 * @date 2016/11/18
 */
@NoRepositoryBean
public class PcardOrderRepositoryImpl extends BaseRepository implements PcardOrderRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;
    @Override
    public List findByQueryParam(QueryParams queryParams, Pageable pageable) {
        StringBuilder sql = new StringBuilder("select * from tbl_pcard_order where 1=1 ");
        List values = analysisQueryParams(sql,queryParams);
        Query query = entityManager.