为了简化这个问题:我们有一个类/表Wine(表“ wines”),它具有以下属性:
...其中Origin是另一个具有just region: String
和的类(带有表“ origins”)country: String
。
我想做的是在我的存储库中使用一种搜索方法供RestController使用。
RestController中的方法声明是这样的:
@GetMapping("/search")
public Wine searchProduct(
@RequestParam Optional<String> searchTerm,
@RequestParam Optional<Origin> origin) {
// ???
}
我现在要执行的操作如下:为使用searchTerm的数据库创建查询(如果给定的话),与origin相同。并且它应该是可分页的。例:
SELECT * FROM wines JOIN origins ON wines.origin_id = origins.id
WHERE (name LIKE $searchTerm OR description LIKE $searchTerm) AND (/*origin check*/)
如果没有给出搜索词,则整个“()AND”部分都不应出现在查询中。如果没有给出原产地,您就会得到它。
我尝试过的事情:
(天真)建设我的仓库(实现CrudRepository)一个巨大的查询关键词,比如这里。
Page<Wine> findWinesByNameLikeOrDescriptionLikeAndOriginEquals(..., Pageable pageable);
使用spring.io 在此处建议的“ Specifications and Querydsl” 。
同样,这只是我从2013年发现的一个示例,我什至不大体上理解,但有点像它非常合适。
所以我实际上找到了解决方案!对于好奇的人,这是我的做法:
ProductController.java
@GetMapping("search")
public Page<Wine> searchProducts(
@RequestParam(name = "text", required = false) String searchTerm,
@RequestParam(required = false) Origin origin,
@RequestParam(required = false) Integer page) {
// generate PageRequest based on Integer page if given:
Pageable pageRequest = PageRequest.of(page != null ? page : 0, 10);
if(Objects.isNull(searchTerm) && Objects.isNull(origin)) {
return wineService.findAll(pageRequest);
}
return wineService.searchWines(
searchTerm,
origin,
pageRequest
);
}
WineService.java
public Page<Wine> searchWines(String searchTerm, Origin origin, Pageable pageable) {
List<Specification<Wine>> specifications = new LinkedList<>();
if (searchTerm != null) {
specifications.add(ProductSpecification.hasSearchStringInNameOrDescription(searchTerm));
}
if (origin != null) {
specifications.add(ProductSpecification.hasOrigin(origin));
}
if (specifications.isEmpty()) {
return wineRepository.findAll(pageable);
} else {
Specification<Wine> query = Specification.where(specifications.remove(0));
for (Specification<Wine> wineSpecification : specifications) {
query = query.and(wineSpecification);
}
return wineRepository.findAll(query, pageable);
}
}
例如,这是名称/描述字符串的规范:
产品规格书
public static Specification<Wine> hasSearchStringInNameOrDescription(String input) {
final String searchTerm = input.toLowerCase();
return (root, criteriaQuery, criteriaBuilder) -> {
log.info("SearchTerm: " + searchTerm);
Predicate pName = criteriaBuilder.like(
criteriaBuilder.lower(root.get(Wine_.NAME)),
"%" + searchTerm + "%"
);
Predicate pDescription = criteriaBuilder.like(
criteriaBuilder.lower(root.get(Wine_.DESCRIPTION)),
"%" + searchTerm + "%"
);
return criteriaBuilder.or(pName, pDescription);
};
}
那些Wine_类的生成是通过Maven插件自动完成的。看到这个。此外,为了将请求正文转换为诸如Origin之类的复杂对象,您需要包括一个类似here的转换器类。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句