springboot项目,orm框架选用的是jpa,开发过程中有一个搜索的功能,就用了Specification对象来完成多条件的动态查询。具体实现:
首先定义接口并继承 JpaRepository<X,X>,JpaSpecificationExecutor
因为要分页所以还加了个Pageable参数,方便后期分页
public interface GoodsRepository extends JpaRepository<Goods, Long>, JpaSpecificationExecutor<Goods> {
Page<Goods> findAll(Specification spec, Pageable page);
}
因为公司是DDD架构模式,所以没有service层接口,而是applicationService代替service,有兴趣的也可以去了解一下DDD领域设计
@Service
public class GoodsAppService {
private final GoodsRepository goodsRepository;
public GoodsAppService(GoodsRepository goodsRepository) {
this.goodsRepository = goodsRepository;
}
/**
* 规则查询
* @param spec 规则类
* @param page
* @return
*/
public Page<GoodsDto> findAll(Specification spec, Pageable page) {
Pageable pageAll = PageRequest.of(page.getPageNumber(),page.getPageSize());
// map方法是因为DDD架构需要转化实体,如果是普通的三层架构不需要.map
return goodsRepository.findAll(spec,pageAll).map(GoodsDto::of);
}
}
再将Specification条件查询封装为一个静态方法,方便调用且减少代码污染
public class GoodsSpecification {
public static Specification<Goods> accordingToFields(String search, String orderName, String sortName) {
Specification<Goods> spec = (Specification<Goods>) (root, query, criteriaBuilder) -> {
// 设置组合条件
List<Predicate> list = new ArrayList<>();
// 设置搜索输入框的匹配条件 支持模糊匹配参数名、参数值
if (StringUtils.isNotBlank(search)) {
// 后续可能还有字段需要模糊匹配
Predicate p1 = criteriaBuilder.like(root.get("name"), "%" + search + "%");
list.add(criteriaBuilder.or(p1));
}
Predicate[] predicates = new Predicate[list.size()];
query.where(criteriaBuilder.and(list.toArray(predicates)));
// 设置排序 前面已经设置了
if ("ASC".equalsIgnoreCase(orderName)) {
query.orderBy(criteriaBuilder.asc(root.get(sortName)));
} else {
query.orderBy(criteriaBuilder.desc(root.get(sortName)));
}
return query.getRestriction();
};
return spec;
}
}
最后是控制层
@ResponseBody
@RequestMapping("search")
public BootstrapTableResultPage<GoodsVo> search(
@RequestParam(required = false) String search,
@RequestParam(defaultValue = "1") Integer pageNumber, // 当前页
@RequestParam(defaultValue = "20") Integer pageSize, // 每页条数
@RequestParam(required = false) String sort, // 排序字段名
@RequestParam(defaultValue = "ASC") String sortOrder // 排序顺序
) throws Exception {
Pageable page = PageRequest.of(pageNumber-1, pageSize);
// 默认按照修改日期的倒序排序,一定要重新设置order的值,bootstrap table组件的order默认会送asc
final String sortName,orderName;
if (StringUtils.isBlank(sort)) {
sortName = "lastModDateTime";
orderName = "desc";
} else {
sortName = sort;
orderName = sortOrder;
}
// 设置组合查询条件
Specification<Goods> spec = GoodsSpecification.accordingToFields(search, orderName, sortName);
// 分页获取数据
Page<GoodsDto> all = goodsAppService.findAll(spec, page);
// 返回数据
BootstrapTableResultPage<GoodsVo> rp = new BootstrapTableResultPage<>();
rp.setTotal("" + all.getTotalElements()); // 总记录条数
rp.setRows(GoodsVo.convert(all.toList(),cas));
return rp;
}
一个多条件动态查询就ok了
一篇其他博主总结的SpringDataJpa Specification接口用法文章讲的挺好的,附上链接:https://blog.csdn.net/bird_tp/article/details/83654789