Ma tâche consiste à effectuer une recherche avancée avec Spring Data REST . Comment puis-je l'implémenter?
J'ai réussi à faire une méthode pour faire une recherche simple, comme celle-ci:
public interface ExampleRepository extends CrudRepository<Example, UUID>{
@RestResource(path="searchByName", rel="searchByName")
Example findByExampleName(@Param("example") String exampleName);
}
Cet exemple fonctionne parfaitement si je dois simplement aller à l'URL:
.../api/examples/search/searchByName?example=myExample
Mais qu'est-ce que je dois faire s'il y a plus d'un champ à rechercher?
Par exemple, si ma classe Example comporte 5 champs, quelle implémentation dois-je avoir pour effectuer une recherche avancée avec tous les champs possibles?
Considérons celui-ci:
.../api/examples/search/searchByName?filed1=value1&field2=value2&field4=value4
et celui-là:
.../api/examples/search/searchByName?filed1=value1&field3=value3
Que dois-je faire pour mettre en œuvre cette recherche de manière appropriée?
Merci.
Spring Data Rest a intégré QueryDSL avec une assistance Web que vous pouvez utiliser pour vos besoins de recherche avancée. Vous devez modifier votre référentiel pour implémenter QueryDslPredicateExecutor
et tout fonctionnera immédiatement.
Voici un exemple de l'article blog concernant la fonctionnalité:
$ 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
}
}
La mise en œuvre de méthodes de requête est largement documentée dans Springréférencedocumentation et des tonnes de blogs techniques, bien que bon nombre d’entre eux soient dépassés.
Puisque votre question est probablement "Comment puis-je effectuer une recherche multi-paramètres avec toute combinaison de champs sans déclarer énormément de méthodes findBy *?", La réponse est Querydsl , pris en charge par Spring .
J'ai trouvé une solution de travail pour cette tâche.
@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);
}
Avec cette solution, en utilisant cette URL de base:
http://localhost:8080/api/examples/search/advancedSearch
Nous pouvons effectuer des recherches avancées avec tous les champs dont nous avons besoin.
Quelques exemples:
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"
J'ai réussi à implémenter ceci en utilisant Requête par Exemple .
Disons que vous avez les modèles suivants:
@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;
}
Et le référentiel:
@RepositoryRestResource
public interface CompanyRepository extends JpaRepository<Company, Long> {
}
(Notez que JpaRepository implements QueryByExampleExecutor ).
Maintenant, vous implémentez un contrôleur personnalisé:
@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));
}
}
Et puis vous pouvez faire des requêtes comme:
localhost:8080/companies/filter?name=google&address=NY
Vous pouvez même interroger des entités imbriquées comme:
localhost:8080/companies/filter?name=google&department.name=finances
J'ai omis quelques détails par souci de brièveté, mais j'ai créé un exemple de travail sur Github.