Jpa 列表 Specification 多条件查询

张芝山 本文由博客端 http://zhangzeshan.top 主动推送

前景

从 PHP 转 java,发现 JPA 的持久层有点类似自己接触的 PHP 的 ORM 写法,于是用这个持久层框架去写了一个统计后台,但是发现我错了,这个持久层我用的一点都不习惯,单纯局限在一些简单的增删改,之后在网上各种查询,发现需要多继承一个 Specification 就可以实现一些复杂的查询

实体类

也就是对应一个表的结构
这里的注解就不再去赘述,只要知道这个是一个表

package com.center.entity.admin;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

/**
 * 统计表实体类
 *
 * @author Administrator
 */
@Entity
@Table(name = "t_cashout_count")
@EntityListeners(AuditingEntityListener.class)
@Setter
@Getter
@ToString
public class CashoutCount implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @Column(name = "id", nullable = false, length = 11)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long id;//唯一id


    @Column(name = "cashoutcount")
    private Long cashoutCount;

    @Column(name = "cashoutsuccesscount")
    private Long cashoutSuccessCount;

    @Column(name = "cashoutfailcount")
    private Long cashoutFailCount;

    @Column(name = "cashoutprice", columnDefinition = "decimal(15,6)")
    private BigDecimal cashoutPrice;

    @Column(name = "cashoutsuccessprice", columnDefinition = "decimal(15,6)")
    private BigDecimal cashoutSuccessPrice;

    @Column(name = "cashoutfailprice", columnDefinition = "decimal(15,6)")
    private BigDecimal cashoutFailPrice;

    @Column(name = "type")
    private Byte type;

    @Column(name = "timetype")
    private Byte timeType;

    @Column(name = "source")
    private Byte source;

    @Column(name = "time")
    private Date createTime;

    @Column(name = "updatetime")
    private Date updateTime;

    @Transient
    private Date endTime;

    @Transient
    private String sourceName;
}
创建上述表对应的接口

这个接口就是我们文章的重点,继承基础的接口 JpaRepository 之外,
还要继承 JpaSpecificationExecutor

package com.center.dao.admin;

import com.center.entity.admin.CashoutCount;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;

@Repository
public interface CashoutCountDao extends JpaRepository<CashoutCount, Long>, JpaSpecificationExecutor<CashoutCount> {
}
创建 sevice 层,编写继承接口之后的代码

注释将写在代码上

package com.center.service.admin;

import com.center.bean.PageBean;
import com.center.common.enumtype.Constants;
import com.center.dao.admin.CashoutCountDao;
import com.center.entity.admin.CashoutCount;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class CashoutCountService {
    @Autowired
    private CashoutCountDao cashoutCountDao;

    /**
     * 日/月
     *
     * @param cashoutCount
     * @param pageBean  这个是分页 先不管
     * @return
     */
    public List<CashoutCount> findByDays(CashoutCount cashoutCount, PageBean<CashoutCount> pageBean) {
        //分页 每页7条 按照创建时间去做倒序
        Pageable pageable = PageRequest.of(pageBean.getCurrentPage() - 1, 7, Sort.Direction.DESC, "createTime");
        //这个就是主代码块
        Specification<CashoutCount> tvSpecification = (Specification<CashoutCount>) (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();
            //相当于 where source = ?
            if (cashoutCount.getSource() != null) {
                predicateList.add(cb.equal(root.get("source"), cashoutCount.getSource()));
            }
            //相当于 where timeType  = ?
            if (cashoutCount.getTimeType() != null) {
                predicateList.add(cb.equal(root.get("timeType"), cashoutCount.getTimeType()));
            }
            //相当于 where type = ?
            if (cashoutCount.getType() != null) {
                predicateList.add(cb.equal(root.get("type"), cashoutCount.getType()));
            }
            //相当于 where createtime <= ?  (createTime是实体那边的属性 不要和表字段混淆)
            if (cashoutCount.getCreateTime() != null) {
                predicateList.add(cb.lessThanOrEqualTo(root.get("createTime").as(Date.class), cashoutCount.getCreateTime()));
            }
            Predicate[] predicates = new Predicate[predicateList.size()];
            return query.where(predicateList.toArray(predicates)).getRestriction();
        };
        Page<CashoutCount> findAll = cashoutCountDao.findAll(tvSpecification, pageable);
        return findAll.getContent();
    }

这样就能实现列表页的一些查询了

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2809 引用 • 8041 回帖 • 749 关注

赞助商 我要投放

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • yuchen001

    当初玩过这玩意,后面发觉还不如直接上 JDBC

    1 回复
  • zhangzeshan
    作者

    对啊!,太坑了