JPA使用Specification来进行条件查询

JPA使用Specification来进行条件查询

封装Specification查询条件,在2.0版本以后这个类会被剔除,可以直接使用 Specification 自身对象来操作where多条件连接。

建立一个SpecificationFactory类,用于连接SQL语句。

package com.insigma.zjps.util;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.Specifications;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * SQL拼接工具类
 * @authot 小懒虫
 * @date 2020 - 01 - 13  11:36
 */
public class SpecificationFactory {

    private Specifications specs;

    private SpecificationFactory(Specification specs) {
        this.specs = Specifications.where(specs);
    }

    public static SpecificationFactory wheres(Specification spec) {
        return new SpecificationFactory(spec);
    }

    public SpecificationFactory and(Specification other) {
        this.specs.and(other);
        return this;
    }

    public SpecificationFactory or(Specification other) {
        this.specs.or(other);
        return this;
    }

    public Specifications build() {
        return this.specs;
    }

    /**
     * 单where条件
     *
     * @param p
     * @return
     */
    public static Specification where(Predication p) {
        List<Predication> ps = new ArrayList<>();
        ps.add(p);
        return where(ps);
    }

    /**
     * 多where条件and连接
     *
     * @param ps
     * @param 
     * @return
     */
    public static <T> Specification<T> where(List<Predication> ps) {
        return (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) ->
                builder.and(getPredicateList(root, builder, ps));
    }

    /**
     * 多where条件or连接
     *
     * @param ps
     * @param 
     * @return
     */
    public static <T> Specification<T> or(List<Predication> ps) {
        return (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) ->
                builder.or(getPredicateList(root, builder, ps));
    }

    /**
     * 获取查询条件数组
     *
     * @param root
     * @param builder
     * @param ps
     * @return
     */
    private static Predicate[] getPredicateList(Root<?> root, CriteriaBuilder builder, List<Predication> ps) {
        List<Predicate> predicateList = new ArrayList<>();
        ps.forEach(p -> {
            Predicate predicate = buildPredicate(builder, root.get(p.getName()), p);
            predicateList.add(predicate);
        });
        return predicateList.toArray(new Predicate[predicateList.size()]);
    }

    /**
     * 选取查询方式
     *
     * @param cb
     * @param path
     * @param p
     * @return
     */
    private static Predicate buildPredicate(CriteriaBuilder cb, Path path, Predication p) {
        Predicate predicate;
        switch (p.getOperator()) {
            case LIKE:
                predicate = cb.like(path, p.getValue().toString());
                break;
            case EQ:
                predicate = cb.equal(path, p.getValue());
                break;
            case NOTEQ:
                predicate = cb.notEqual(path, p.getValue());
                break;
            case GT:
                predicate = cb.greaterThan(path, (Comparable) p.getValue());
                break;
            case GTEQ:
                predicate = cb.greaterThanOrEqualTo(path, (Comparable) p.getValue());
                break;
            case LT:
                predicate = cb.lessThan(path, (Comparable) p.getValue());
                break;
            case LTEQ:
                predicate = cb.lessThanOrEqualTo(path, (Comparable) p.getValue());
                break;
            case NULL:
                predicate = cb.isNull(path);
                break;
            case NOTNULL:
                predicate = cb.isNotNull(path);
                break;
            case IN:
                predicate = getIn(path, p.getValue());
                break;
            case NOTIN:
                predicate = getIn(path, p.getValue()).not();
                break;
            default:
                throw new IllegalArgumentException("非法的操作符");
        }
        return predicate;
    }

    /**
     * 创建in操作
     *
     * @param path
     * @param value
     * @param 
     * @return
     */
    private static <T> Predicate getIn(Path path, T value) {
        if (value instanceof Object[]) {
            return path.in((Object[]) value);
        } else if (value instanceof Collection) {
            return path.in((Collection) value);
        } else {
            throw new IllegalArgumentException("非法的IN操作");
        }
    }

    /***********************************************单where条件查询********************************************************/

    // like
    public static Specification like(String name, String value) {
        return (root, query, cb) ->
                cb.like(root.get(name), value);
    }

    // =
    public static Specification equal(String name, Object value) {
        return (root, query, cb) ->
                cb.equal(root.get(name), value);
    }

    // !=
    public static Specification notEqual(String name, Object value) {
        return (root, query, cb) ->
                cb.notEqual(root.get(name), value);
    }

    // >
    public static Specification gt(String name, Object value) {
        return (root, query, cb) ->
                cb.greaterThan(root.get(name), (Comparable) value);
    }

    // >=
    public static Specification gtEqual(String name, Object value) {
        return (root, query, cb) ->
                cb.greaterThanOrEqualTo(root.get(name), (Comparable) value);
    }

    // <
    public static Specification lt(String name, Object value) {
        return (root, query, cb) ->
                cb.lessThan(root.get(name), (Comparable) value);
    }

    // <=
    public static Specification ltEqual(String name, Object value) {
        return (root, query, cb) ->
                cb.lessThanOrEqualTo(root.get(name), (Comparable) value);
    }

    // is null
    public static Specification isNull(String name) {
        return (root, query, cb) ->
                cb.isNull(root.get(name));
    }

    // is not null
    public static Specification notNull(String name) {
        return (root, query, cb) ->
                cb.isNotNull(root.get(name));
    }

    // in
    public static Specification in(String name, Object value) {
        return (root, query, cb) ->
                root.get(name).in(value);
    }

    // not in
    public static Specification notIn(String name, Object value) {
        return (root, query, cb) ->
                root.get(name).in(value).not();
    }
}

创建Predication类:

package com.insigma.zjps.util;

import lombok.Data;

/**
 * @authot 小懒虫
 * @date 2020 - 01 - 13  11:13
 */
@Data
public class Predication<T> {

    private OP operator;
    private String name;
    private T value;

    private Predication() {
    }

    public static <T> Predication<T> get(OP operator, String name, T value) {
        return new Builder().operator(operator)
                .name(name).value(value).build();
    }

    public static class Builder<T> {
        private Predication p;

        public Builder() {
            this.p = new Predication();
        }

        public Builder operator(OP op) {
            this.p.operator = op;
            return this;
        }

        public Builder name(String name) {
            this.p.name = name;
            return this;
        }

        public Builder value(T value) {
            this.p.value = value;
            return this;
        }

        public <T> Predication<T> build() {
            return this.p;
        }

    }
}

建立OP类:

package com.insigma.zjps.util;

/**
 * @authot 小懒虫
 * @date 2020 - 01 - 13  11:32
 */
public enum OP {
    // like
    LIKE,
    // =
    EQ,
    // !=
    NOTEQ,
    // >
    GT,
    // >=
    GTEQ,
    // <
    LT,
    // <=
    LTEQ,
    // is null
    NULL,
    // is not null
    NOTNULL,
    // in
    IN,
    // not in
    NOTIN,

    AND,

    OR,

    NOT
}

下面是使用的方式:
必须在***Repository中继承JpaSpecificationExecutor,代码如下(其中ReviewPlan是实体类):

@Repository
public interface ReviewPlanRepository  extends JpaRepository<ReviewPlan, String> , JpaSpecificationExecutor<ReviewPlan> {

    @Query(value = "SELECT * FROM TYPS_REVIEW_PLAN WHERE planname=?1", nativeQuery = true)
    List<ReviewPlan> checkName(String name);

    @Query(value = "SELECT * FROM TYPS_REVIEW_PLAN WHERE id!=?1 and planname=?2", nativeQuery = true)
    List<ReviewPlan> checkName(String id,String name);
}

在***ServiceImp中的使用:

public Page<ReviewPlan> queryPlanList(JSONObject jsonObject, Pageable pageable) {
        String workDeptId=settingIndexCS.findUserExcatCode();
        String planName = jsonObject.getString("name");
        String createuser = jsonObject.getString("createuser");
        String status = jsonObject.getString("status");
        String startTime = jsonObject.getString("startTime");
        String endTime = jsonObject.getString("endTime");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdfmat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<Predication> ps = new ArrayList<>();
        //ps.add(Predication.get(OP.EQ, "workDeptId", workDeptId));
        if(StringUtils.isNotBlank(workDeptId)){
            ps.add(Predication.get(OP.EQ, "workDeptId", workDeptId));
        }
        if(StringUtils.isNotBlank(planName)){
            ps.add(Predication.get(OP.LIKE,"planName","%"+planName+"%"));
        }
        if(StringUtils.isNotBlank(createuser)){
            ps.add(Predication.get(OP.LIKE,"createuser","%"+createuser+"%"));
        }
        if(StringUtils.isNotBlank(status)){
            ps.add(Predication.get(OP.EQ,"status",status));
        }
        try {
            if(StringUtils.isNotBlank(startTime)){
                ps.add(Predication.get(OP.GTEQ,"startTime",sdfmat.parse(sdfmat.format(sdf.parse(startTime).getTime()))));
            }
            if(StringUtils.isNotBlank(endTime)){
                ps.add(Predication.get(OP.LTEQ,"endTime",sdfmat.parse(sdfmat.format(sdf.parse(endTime).getTime()))));
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Specification spec;
        spec=Specification.where(SpecificationFactory.where(ps));
        return reviewPlanRepository.findAll(spec, pageable);

    }

具体还有以下几种方式的实现:

 		Sort sort = new Sort(Sort.Direction.DESC, "id");
        Pageable pageable = new PageRequest(number, size, sort);

        Specification spec;
        /***********************单条件查询*************************/
        // 方式1
        Predication p = Predication.get(OP.EQ, "name", name);
        spec = SpecificationFactory.where(p);
        // 方式2
        spec = SpecificationFactory.equal("name", name);
        /***********************多条件查询*************************/
        List<Predication> ps = new ArrayList<>();
        ps.add(Predication.get(OP.LIKE, "name", name));
        ps.add(Predication.get(OP.EQ, "age", age));
        // 全and连接
        spec = SpecificationFactory.where(ps);
        // 全or连接
        spec = SpecificationFactory.or(ps);
        // and和or混合连接
        
        // where name like ?1 and age = ?2
        // and name like ?3 and age = ?4
        // or name like ?5 or age = ?6
        // 工具类实现
        spec = SpecificationFactory.wheres(SpecificationFactory.where(ps))
                .and(SpecificationFactory.where(ps))
                .or(SpecificationFactory.or(ps))
                .build();
        // JPA API辅助类实现
        spec = Specifications.where(SpecificationFactory.where(ps))
                .and(SpecificationFactory.where(ps))
                .or(SpecificationFactory.where(ps));
        
        // where name like ?1 and age = ?2
        // and ( name like ?3 or age = ?4 )
        // 工具类实现
        spec = SpecificationFactory.wheres(SpecificationFactory.where(ps))
                .and(SpecificationFactory.or(ps))
                .build();
        // JPA API辅助类实现
        spec = Specifications.where(SpecificationFactory.where(ps))
                .and(SpecificationFactory.or(ps));

        Page<ConsultChat> chatPage = consultChatDao.findAll(spec, pageable);

你可能感兴趣的:(JPA使用Specification来进行条件查询)