Springboot+jpa之 Specification复杂查询1:搜索功能

Specification: jpa的条件构造器

实现复杂查询,使用Repository,需要实现JpaSpecificationExecutor接口       

public interface UserDao extends JpaRepository,JpaSpecificationExecutor {
}
userDao.findAll(new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) { }
        });

Root查询结果的一个实体对象,也就是查询结果返回的主要对象

CriteriaQuery(javax.persistence.criteria.CriteriaQuery):

这个是JPA标准,用于构建查询条件,里面的方法为各种查询方式,如:distinct、select、where、groupby、having、orderby等

CriteriaBuilder(javax.persistence.criteria.CriteriaBuilder):

用来进行函数操作,此接口很多都是返回Predicate接口的,其中包含:between(范围之间)、gt(大于),lt(小于),not(非)等操作.

JPA标准中Hibernate的两个实现方法

   1.and(org.hibernate.ejb.criteria.CriteriaBuilderImpl.and(Predicate...)) :将各个条件作为and来拼接,进行查询;
    2.or (org.hibernate.ejb.criteria.CriteriaBuilderImpl.or(Predicate...)):将各条件作为or来拼接,进行查询。

这两个方法都有一个关键的接口:Predicate(javax.persistence.criteria.Predicate);是Expression(javax.persistence.criteria.Expression)的子接口。这个接口作为关联各种Predicate的核心操作接口。

 

1.定义一个Predicate数组,和一个临时Predicate数组,

List predicates = new ArrayList<>();
List temp = new ArrayList<>();

2.将查询条件添加到临时Predicate数组当中

temp.add(criteriaBuilder.like(userName,"%"+ user.getUserName()+"%"));
temp.add(criteriaBuilder.equal(phone,user.getPhone()));

3.再将临时数组用or或者and将查询条件拼接起来放到Predicate数组当中

predicates.add(criteriaBuilder.or(temp.toArray(new Predicate[temp.size()])));

4.最后将list转为数组执行查询

query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();

简单来说:

Root:查询的实体类(user实体类)
CriteriaQuery:构建查询条件,查询哪些字段,排序是什么
CriteriaBuilder:字段之间是什么关系,如何生成一个查询条件,进行函数操作;
Predicate(Expression):单独每一条查询条件的详细描述。(条件)

 

实际例子:User表按条件查询

实体类

package com.association.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.persistence.*;
import java.util.Date;

/**
 * 用户表
 */
@Entity
@Data
@Table(name="user")
public class User extends BaseEntity {

    /** 用户ID */
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id
    private Long userId;

    /** 用户名 */
    private String userName;

    /** 手机*/
    private String phone;

    /** 状态 1:停用 0:正常*/
    private String status;

    /** 开始时间 */
    @JsonIgnore
    private String beginTime;

    /** 结束时间 */
    @JsonIgnore
     private String endTime;

}

Dao层

@Repository
public interface UserDao extends JpaRepository,JpaSpecificationExecutor {

}

Controller层

@RestController
@RequestMapping("/api/user")
public class UserController extends BaseController {

 @Autowired
    UserService userService;

  //region  获取用户列表
    /**
     * 获取用户列表
     */
    @GetMapping("/list")
    public TableDataInfo listUser(User user)
    {
        startPage();

        List list = userService.selectUserList(user);

        //表格分页数据
        return getDataTable(list);
    }
    //endregion

}

service层

/**
 * 用户 业务层
 */
public interface UserService
{
    /**
     * 根据条件分页查询用户列表
     * 
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    public List selectUserList(User user);

    /**
     * 根据搜索条件查询用户列表
     * 
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    List findByDynamicCases(User user);

}

serviceImpl(service实现层)

/**
 * 用户 业务层处理
 *
 * @author baozi
 */
@Service
public class UserServiceImpl implements UserService {

   //日志
  private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

  @Autowired
  private UserDao userDao;

    //region 根据条件分页查询用户列表

    /**
     * 根据条件分页查询用户列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public List selectUserList(User user) {

        //查询条件:1.用户姓名 2.用户电话 3.用户状态 4.创建时间范围

        //如果条件都为null则查询全部
        if (StringUtils.isNull(user.getUserName()) && StringUtils.isNull(user.getStatus())
                && StringUtils.isNull(user.getPhone())
                && StringUtils.isEmpty(user.getBeginTime())
                && StringUtils.isEmpty(user.getEndTime())) {
            return userDao.findAll();
        } else {
            return findByDynamicCases(user);
        }
    }
    //endregion

    //region 查询:按条件进行动态查询

    /**
     * 按条件进行动态查询
     * 查询条件:1.用户姓名
     * 2.用户手机
     * 3.用户状态
     * 4.用户创建时间范围
     * @return
     */
    public List findByDynamicCases(User user) {
        return  userDao.findAll(new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {

                Path userName = root.get("userName");
                Path phone = root.get("phone");
                Path status = root.get("status");
                Path createTime = root.get("createTime");

                List predicates = new ArrayList<>();
                List temp = new ArrayList<>();

                if (user.getUserName() != null) {
                    temp.add(criteriaBuilder.like(userName,"%"+ user.getUserName()+"%"));
                }
                if (user.getPhone() != null) {
                    temp.add(criteriaBuilder.equal(phone,user.getPhone()));
                }
                if (user.getStatus() != null) {
                    temp.add(criteriaBuilder.equal(status,user.getStatus()));
                }
                if (user.getBeginTime() != null
                        && user.getEndTime()!= null
                        &&StringUtils.isNotEmpty(user.getBeginTime())
                        &&StringUtils.isNotEmpty(user.getEndTime())){
                    temp.add(criteriaBuilder.between(createTime, DateUtils.parseDate(user.getBeginTime()), DateUtils.parseDate(user.getEndTime())));
                }

                predicates.add(criteriaBuilder.or(temp.toArray(new Predicate[temp.size()])));
                return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        });
    }
    //endregion


}

表格分页


@Data
public class TableDataInfo implements Serializable
{
    private static final long serialVersionUID = 1L;

    /** 总记录数 */
    private long total;

    /** 列表数据 */
    private List rows;

    /** 消息状态码 */
    private int code;

    /** 消息内容 */
    private int msg;

    /**
     * 表格数据对象
     */
    public TableDataInfo()
    {
    }

    /**
     * 分页
     * 
     * @param list 列表数据
     * @param total 总记录数
     */
    public TableDataInfo(List list, int total)
    {
        this.rows = list;
        this.total = total;
    }


}

 

你可能感兴趣的:(Springboot+jpa之 Specification复杂查询1:搜索功能)