How to make an advanced search with Spring Data REST?

Viewed 41427

My task is to make an advanced search with Spring Data REST. How can I implement it?

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:

.../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?

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.

5 Answers

I managed to implement this using 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 JpaRepository implements 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 example on Github.

Related