java—在spring中处理带有许多可选查询参数的RESTAPI请求

xtfmy6hx  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(387)

为了简单起见,假设我有一个 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 作为存储库,如果这可能是任何帮助。

6qqygrtg

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 基于jpa CriteriaQuery 对于每种方法,您只需实现一种方法:

Predicate toPredicate (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder);

存储库接口只需要扩展 JpaSpecificationExecutor<YourClass> 当您有一组 predicate 时,您可以-例如-

repository.findAll(Specification.where(spec1).and(spec2));

一开始可能看起来很复杂或困难,但事实并非如此。最大的优势是 Specification 您几乎可以通过编程来做任何事情,而不是操纵jpql查询。

相关问题