Java 如何使用 Spring Data REST 进行高级搜索?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36222830/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make an advanced search with Spring Data REST?
提问by Alessandro C
My task is to make an advanced search with Spring Data REST. How can I implement it?
我的任务是使用 Spring Data REST 进行高级搜索。我该如何实施?
I managed to make a method to do a simple search, like this one:
我设法制作了一种方法来进行简单的搜索,如下所示:
public interface ExampleRepository extends CrudRepository<Example, UUID>{
@RestResource(path="searchByName", rel="searchByName")
Example findByExampleName(@Param("example") String exampleName);
}
This example works perfectly if I have to go simply to the url:
如果我必须简单地转到 url,则此示例非常有效:
.../api/examples/search/searchByName?example=myExample
But what I have to do if there are more than one field to search?
但是如果要搜索的字段不止一个,我该怎么办?
For example, if my Example class has 5 fields, what implementation should I have to make an advanced search with all possibiles fileds?
例如,如果我的 Example 类有 5 个字段,我应该使用什么实现来对所有可能的文件进行高级搜索?
Consider this one:
考虑这个:
.../api/examples/search/searchByName?filed1=value1&field2=value2&field4=value4
and this one:
和这个:
.../api/examples/search/searchByName?filed1=value1&field3=value3
What I have to do to implement this search in appropriate way?
我必须做什么才能以适当的方式实施此搜索?
Thanks.
谢谢。
回答by Marc Tarin
The implementation of query methods is widely documented in Springreferencedocumentationand tons of technical blogs, though quite a bunch are outdated.
查询方法的实现广泛记录在Spring参考文档和大量技术博客中,尽管很多已经过时了。
Since your question is probably "How can I perform a multi-parameter search with any combination of fields without declaring an awful lot of findBy* methods?", the answer is Querydsl, which is supported by Spring.
由于您的问题可能是“如何在不声明大量 findBy* 方法的情况下对任意字段组合执行多参数搜索?”,因此答案是Querydsl,它由Spring支持。
回答by alexei-grigoriev
I guess You can try following:
我想您可以尝试以下操作:
List<Person> findDistinctPeopleByLastnameOrFirstname(@Param("lastName")String lastname, @Param("firstName")String firstname);
List<Person> findDistinctPeopleByLastnameOrFirstname(@Param("lastName")String lastname, @Param("firstName")String firstname);
and examples/search/searchByLastnameOrFirstname?firstName=value1&lastName=value2
和 examples/search/searchByLastnameOrFirstname?firstName=value1&lastName=value2
查看:http: //docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
回答by Alessandro C
I have found a working solution for this task.
我为这项任务找到了一个可行的解决方案。
@RepositoryRestResource(excerptProjection=MyProjection.class)
public interface MyRepository extends Repository<Entity, UUID> {
@Query("select e from Entity e "
+ "where (:field1='' or e.field1=:field1) "
+ "and (:field2='' or e.field2=:field2) "
// ...
+ "and (:fieldN='' or e.fieldN=:fieldN)"
Page<Entity> advancedSearch(@Param("field1") String field1,
@Param("field2") String field2,
@Param("fieldN") String fieldN,
Pageable page);
}
With this solution, using this base url:
使用此解决方案,使用此基本网址:
http://localhost:8080/api/examples/search/advancedSearch
We can make advanced searches with all the fields that we need.
我们可以使用我们需要的所有字段进行高级搜索。
Some examples:
一些例子:
http://localhost:8080/api/examples/search/advancedSearch?field1=example
// filters only for the field1 valorized to "example"
http://localhost:8080/api/examples/search/advancedSearch?field1=name&field2=surname
// filters for all records with field1 valorized to "name" and with field2 valorized to "surname"
回答by Faisal Feroz
Spring Data Rest has integrated QueryDSL with web support as well which you can use for your advanced search requirement. You need to change your repository to implement QueryDslPredicateExecutor
and things will work out of the box.
Spring Data Rest 也将 QueryDSL 与 Web 支持集成在一起,您可以将其用于高级搜索需求。您需要更改您的存储库来实施QueryDslPredicateExecutor
,一切都会开箱即用。
Here is a sample from the blogarticle about the feature:
以下是有关该功能的博客文章中的示例:
$ http :8080/api/stores?address.city=York
{
"_embedded": {
"stores": [
{
"_links": {
…
},
"address": {
"city": "New York",
"location": { "x": -73.938421, "y": 40.851 },
"street": "803 W 181st St",
"zip": "10033-4516"
},
"name": "Washington Hgts/181st St"
},
{
"_links": {
…
},
"address": {
"city": "New York",
"location": { "x": -73.939822, "y": 40.84135 },
"street": "4001 Broadway",
"zip": "10032-1508"
},
"name": "168th & Broadway"
},
…
]
},
"_links": {
…
},
"page": {
"number": 0,
"size": 20,
"totalElements": 209,
"totalPages": 11
}
}
回答by Jefferson Lima
I managed to implement this using Query by Example.
我设法使用Query by Example实现了这一点。
Let's say you have the following models:
假设您有以下模型:
@Entity
public class Company {
@Id
@GeneratedValue
Long id;
String name;
String address;
@ManyToOne
Department department;
}
@Entity
public class Department {
@Id
@GeneratedValue
Long id;
String name;
}
And the repository:
和存储库:
@RepositoryRestResource
public interface CompanyRepository extends JpaRepository<Company, Long> {
}
(Note that JpaRepositoryimplements QueryByExampleExecutor).
(注意JpaRepository实现了QueryByExampleExecutor)。
Now you implement a custom controller:
现在你实现一个自定义控制器:
@RepositoryRestController
@RequiredArgsConstructor
public class CompanyCustomController {
private final CompanyRepository repository;
@GetMapping("/companies/filter")
public ResponseEntity<?> filter(
Company company,
Pageable page,
PagedResourcesAssembler assembler,
PersistentEntityResourceAssembler entityAssembler
){
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnoreCase()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);
Example example = Example.of(company, matcher);
Page<?> result = this.repository.findAll(example, page);
return ResponseEntity.ok(assembler.toResource(result, entityAssembler));
}
}
And then you can make queries like:
然后您可以进行如下查询:
localhost:8080/companies/filter?name=google&address=NY
You can even query nested entities like:
您甚至可以查询嵌套实体,例如:
localhost:8080/companies/filter?name=google&department.name=finances
I omitted some details for brevity, but I created a working exampleon Github.
为简洁起见,我省略了一些细节,但我在 Github 上创建了一个工作示例。