为了简单起见,假设我有一个 Document
对象有七个字段(但想象一下,它可以有更多字段)。此对象类似于:
@Getter
@Setter
public class Document {
private String fileName;
private String fileType;
private String createdBy;
private Date createdAt;
private Date lastModifiedAt;
private List<String> modifiers;
private Long timesModified;
}
我想创建一个端点,它可以接收任意数量的 @RequestParam
返回一个 List<Document>
与给定查询匹配的所有文档。例如:返回所有文档 fileType == doc
,创建于 createdAt == 01/01/2021 && createdAt 31/01/2021
,已修改 timesModified == 5
次数和 modifiers.contains("Alex")
. 这样做的原因是我想允许用户根据用户想要的字段组合来查询文档。最初为了处理这个问题,我们创建了如下端点:
@GetMapping(value = {RestApi.LIST})
public ResponseEntity<List<Document>> getDocuments (@RequestParam Map<String, Object> optionalFilters) {
List<Document> documents = documentService.getListOfDocuments(optionalFilters);
if (documents != null) {
return new ResponseEntity<>(documents, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
问题是因为我们使用 optionalFilters
作为 Map<String, Object>
这需要我们在代码中执行大量的强制转换,总体来说,这使得我们的代码非常繁琐,因为我们必须遍历整个Map并根据传递的字段创建自定义查询。为了尝试和改善这一点,我创建了一个 OptionalFilters
对象:
@Getter
@Setter
@NoArgsConstructor
public class OptionalFilters {
private String fileName;
private String fileType;
private String createdBy;
private Date createdAt;
private Date lastModifiedAt;
private List<String> modifiers;
private Long timesModified;
}
并将端点修改为:
@GetMapping(value = {RestApi.LIST})
public ResponseEntity<List<Document>> getDocuments (@Valid OptionalFilters optionalFilters) {
List<Document> documents = documentService.getListOfDocuments(optionalFilters);
if (documents != null) {
return new ResponseEntity<>(documents, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
然而,尽管这简化了我们接收参数并从中提取值的方式,我们仍然需要遍历所有参数并创建一个自定义查询。有什么方法可以提升和利用 Spring-Data
(或任何其他解决方案),以便我不必根据传递的每个查询参数创建自定义查询?我正在使用 Solr
作为存储库,如果这可能是任何帮助。
1条答案
按热度按时间6qqygrtg1#
使用示例查询是最简单的选择之一,但也有其局限性。以上链接摘录:
局限性
与所有事情一样,示例查询api也有一些限制。例如:
不支持嵌套和分组语句,例如:(firstname=?0和lastname=?1)或seatnumber=?2
字符串匹配只包括exact、不区分大小写、start、ends、contains和regex除字符串以外的所有类型都是exact匹配
如果您的筛选过程不太复杂,那么通过示例查询是合适的选择。但是,当上述restirictions击中您的cpu风扇时,您可以选择使用规范来构造查询。
还有一个很大的区别是,使用queryby example时,需要通过getter和setter显式地填充示例。有了规范,您就可以用一种通用的方式(使用java泛型),只使用字段名
在您的例子中,您可以将Map传递给泛型方法,并通过循环和添加来创建过滤
and
(请注意,链接的示例大部分都是静态的,但不一定是静态的,您只需要字段名/条件对以通用方式循环它)有了规范,你可以做任何可以通过示例查询的事情,也可以做任何其他事情。熟悉规范的开销可能会更大,但使用规范的好处是值得的。
简而言之:
Spring
interface Specification
基于jpaCriteriaQuery
对于每种方法,您只需实现一种方法:存储库接口只需要扩展
JpaSpecificationExecutor<YourClass>
当您有一组 predicate 时,您可以-例如-一开始可能看起来很复杂或困难,但事实并非如此。最大的优势是
Specification
您几乎可以通过编程来做任何事情,而不是操纵jpql查询。