首页 > 其他分享 >JPA使用Specification构建动态查询

JPA使用Specification构建动态查询

时间:2023-02-16 16:23:15浏览次数:55  
标签:ps return name JPA cb Specification value 查询 root

封装Specification查询条件,在Spring Data JPA 2.0以前使用 Specifications 这个辅助类来操作where、not、and和or连接,在2.0版本以后这个类会被剔除,可以直接使用 Specification 自身对象来操作where多条件连接。(以下展示单表多条件查询)

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拼接工具类
 *
 * @author yanhu
 * @date 2018/8/9
 */
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 <T>
     * @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 <T>
     * @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 <T>
     * @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();
    }
}
import lombok.Data;

@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;
        }

    }
}
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
}

具体使用

        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);
springboot+各种框架

标签:ps,return,name,JPA,cb,Specification,value,查询,root
From: https://www.cnblogs.com/exmyth/p/17127171.html

相关文章

  • sql 查询表数据
    SELECTs.NameASSchemaName,t.NameASTableName,p.rowsASRowCounts--,--CAST(ROUND((SUM(a.used_pages)/128.00),2)ASNUMERIC(36,2))ASUsed_MB,--CAST(R......
  • 黑名单查询:前缀树
    引入我现在有一份黑名单数据,里面有10000条域名,现在需要编写一个算法,快速判断一个域名在不在这个黑名单里,怎么设计这个算法?字典树or前缀树前缀树是N叉树的一种根节点......
  • MybatisPlus查询条件设置详解
    select设置需要查询的字段例: 指定查询主键,名字,年龄字段select("id", "name", "age")例: 查询以test开头的属性select(i ‐> i.getProperty().startsWith("t......
  • 860~808 复杂条件查询分析,代码实现
    复杂条件查询分析:  代码实现packagecom.example.web.servlet;importcom.example.domain.PageBean;importcom.example.domain.User;importcom.example.servi......
  • 分页查询功能_代码实现_后台代码实现与分页查询功能_代码实现_前台代码实现
    分页查询功能_代码实现_后台代码实现packagehf.xueqiang.web.servlet;importhf.xueqiang.domain.PageBean;importhf.xueqiang.domain.User;importhf.xueqiang.se......
  • 多表查询
    --显示雇员名字、工资以及所在部门的名字--在默认情况下,当两个表查询时,规则:--1.从第一张表中,取出一行,与第二张表的每一条记录进行拼接--2.总返回记录数:第一张表记......
  • 多子句查询
    --多子句查询顺序SELECTcolumn1,column2,...FROMmytable GROUPBYcolumnx HAVINGconditionx ORDERBYcolumnx LIMITstartx,rowsx;--统计各个部门平均工......
  • 通用查询语言(GQL)
    在微服务开发中,经常遇到各种查询的需求,不同接口还有不同的查询方式,为了统一不同模型,不同筛选条件,动态筛选,复合条件筛选等各种场景查询方式,无需改代码支持不同场景下的查询......
  • (数据库系统概论|王珊)第三章关系数据库标准语言SQL-第四节:数据查询
    pdf下载:密码7281专栏目录首页:【专栏必读】(考研复试)数据库系统概论第五版(王珊)专栏学习笔记目录导航及课后习题答案详解关于数据库如何安装,表如何建立这里不再介绍,请......
  • MySQL中,把查询的结果拼接成一个字符串。
    用法:group_concat(待拼接对象)输出:用逗号进行拼接后的字符串selectgroup_concat(emp_no)asemployeesfromdept_emp;  /*结果:employees       ......