Как сделать расширенный поиск с помощью Spring Data REST?
Моя задача - сделать расширенный поиск с помощью Spring Data REST.
Как его реализовать?
Мне удалось создать способ для простого поиска, например:
public interface ExampleRepository extends CrudRepository<Example, UUID>{
@RestResource(path="searchByName", rel="searchByName")
Example findByExampleName(@Param("example") String exampleName);
}
Этот пример отлично работает, если мне нужно просто перейти к URL-адресу:
.../api/examples/search/searchByName?example=myExample
Но что мне делать, если есть несколько полей для поиска?
Например, если мой класс класса имеет 5 полей, какую реализацию следует выполнить для расширенного поиска со всеми возможными файлами?
Рассмотрим это:
.../api/examples/search/searchByName?filed1=value1&field2=value2&field4=value4
и этот:
.../api/examples/search/searchByName?filed1=value1&field3=value3
Что мне нужно сделать, чтобы реализовать этот поиск соответствующим образом?
Спасибо.
Ответы
Ответ 1
Реализация методов запросов широко документирована в справочной документации Spring и тоннах технических блогов, хотя многие из них устарели.
Поскольку ваш вопрос, вероятно, "Как я могу выполнить многопараметрический поиск по любой комбинации полей, не объявляя при этом огромное количество методов findBy *?", Ответ - Querydsl, который поддерживается Spring.
Ответ 2
Spring Data Rest также интегрировал QueryDSL с веб-поддержкой, которую вы можете использовать для расширенного поиска. Вам нужно изменить свой репозиторий для реализации QueryDslPredicateExecutor
и все будет работать из коробки.
Вот пример из статьи в блоге об этой функции:
$ 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
}
}
Ответ 3
Я нашел рабочее решение для этой задачи.
@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);
}
С этим решением, используя этот базовый URL:
http://localhost:8080/api/examples/search/advancedSearch
Мы можем сделать расширенный поиск со всеми полями, которые нам нужны.
Некоторые примеры:
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"
Ответ 4
Я думаю, вы можете попробовать следующее:
List<Person> findDistinctPeopleByLastnameOrFirstname(@Param("lastName")String lastname, @Param("firstName")String firstname);
и examples/search/searchByLastnameOrFirstname?firstName=value1&lastName=value2
Отъезд: http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
Ответ 5
Мне удалось реализовать это с помощью Query by Example.
Допустим, у вас есть следующие модели:
@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;
}
И хранилище:
@RepositoryRestResource
public interface CompanyRepository extends JpaRepository<Company, Long> {
}
(Обратите внимание, что JpaRepository реализует QueryByExampleExecutor).
Теперь вы реализуете собственный контроллер:
@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));
}
}
И тогда вы можете делать запросы, как:
localhost:8080/companies/filter?name=google&address=NY
Вы даже можете запросить вложенные объекты, такие как:
localhost:8080/companies/filter?name=google&department.name=finances
Для краткости я опустил некоторые детали, но создал рабочий пример на Github.