web-dev-qa-db-fra.com

Comment faire une recherche avancée avec Spring Data REST?

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.

11
Alessandro C

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
    }
}
7
Faisal Feroz

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 .

6
Marc Tarin

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"
2
Alessandro C

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.

0
Jefferson Lima