JPA Specification 自定义查询

1,469 阅读1分钟

Specification 自定义查询

在使用JPA遇到较复杂的或需要更加灵活的查询场景时,可以使用Specification拼接查询。

Demo

实体类:

@Data
public class Task{
    
    private Integer id;

    private String title;
    
    private Integer type;
    
    private String content;
    
    private Date createTime;
    
    private Integer version;
    
}

查询条件(SearchForm):

@Data
public class SearchForm{
    
    private Integer id;
    
    // title 和 content 的查询关键字
    private String keyword;
    
    private List<Integer> types;
    
    private String orderByCreate = "DESC";
    
    private Integer version;
}

拼接复杂查询的方法:

@Autowired
private TaskRepository taskRepository;

public List<Task> findAll(SearchForm form) {
    List<Task> taskList = taskRepository.findAll(this.getSpecificationForTask(form));
    return taskList;
}

private Specification<Task> getSpecificationForTask(SearchForm form) {
    // dynamite sql
    return (root, query, builder) -> {
        // for params
        List<Predicate> predicates = new ArrayList<>();
        // 精准匹配
        if (form.getId() != null) {
            predicates.add(builder.equal(root.get("id"), form.getId()));
        }
        // 模糊查询 + or条件
        if (!StringUtils.isEmpty(form.getKeyword())) {
            predicates.add(builder.or(like(root.get("title"), "%" + form.getKeyword() + "%"), like(root.get("content"), "%" + form.getKeyword() + "%")));
        }
        // 大于等于
        if (form.getVersion() != null) {
            predicates.add(builder.greaterThanOrEqualTo(root.get("version"), form.getVersion()));
        }
        // in范围查询
        if (!CollectionUtils.isEmpty(form.getTypes())) {
            CriteriaBuilder.In<Object> taskType = builder.in(root.get("type"));
            form.getTypes().forEach(vendNoIn::value);
            predicates.add(taskType);
        }
        // 排序
        List<Order> orderList = new ArrayList<>();
        if(form.getOrderByCreate().equals("DESC")) {
            orderList.add(builder.desc(root.get("createTime")))
        } else {
            orderList.add(builder.asc(root.get("createTime")))
        }
        // 支持多重排序
        orderList.add(builder.asc(root.get("id")))
        return  query.orderBy(orderList).where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
    };
}

repository:

public interface TaskRepository extends JpaSpecificationExecutor<Task> {

}

tips

  • Root<T> root:获取实体类的属性
  • CriteriaQuery<?> query:通过query实现查询
  • CriteriaBuilder builder:拼接查询条件