Parâmetros opcionais nos repositórios de dados do Spring

Todos que usaram o Spring Data enfrentaram uma situação em que você tem um repositório para trabalhar com uma entidade e deseja escrever um método universal de busca para pesquisar por um conjunto de parâmetros que o usuário pode definir ou ignorar no formulário de pesquisa. A implementação básica dos métodos find no Spring Data localiza entidades apenas levando em consideração todos os parâmetros, não permitindo a pesquisa por um conjunto limitado. Encontrei uma maneira de resolver esse problema e criei uma biblioteca OpenSource para uso rápido em outros projetos.

Para entender os problemas, vamos imaginar que estamos criando um aplicativo de notebook simples, no qual definimos uma entidade - Pessoa com os campos id, firstName, lastName, phoneNumber.

Person.java
@Entity @Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(of = "id") public class Person { @Id private Long id; private String firstName; private String lastName; private String phoneNumber; } 


Suponha que devemos fornecer uma pesquisa por nome, sobrenome e parte do número de telefone ou por qualquer combinação desses parâmetros e que o método de pesquisa não leve em consideração parâmetros cujos valores são nulos. Para resolver esse problema, você pode seguir de várias maneiras:

  1. Trabalhe diretamente com o banco de dados através do SQL, crie um método no serviço que gerará dinamicamente a consulta SQL. Algo como

    Consulta dinâmica
      Iterable<Person> find(String firstName, String lastName, String phoneNumber) { List<String> where = new ArrayList(); List params = new ArrayList(); if(firstName != null) { params.add(firstName); where.add("first_name = ?"); } if(lastName != null) { params.add(lastName); where.add("last_name = ?"); } if(phoneNumber != null) { params.add(phoneNumber); where.add("phone_number = ?"); } String sql = "SELECT * FROM person " + (where.isEmpty() ? "" : " WHERE " + String.join(" AND ", where)); //  SQL  JDBCTemplate // ... } 

  2. Use a anotação de consulta para um método de pesquisa com verificação de parâmetro como nulo.

    @Query
      @Query("SELECT p FROM Person p " + "WHERE " + "(firstName = :firstName or :firstName is null) and " + "(lastName = :lastName or :lastName is null) and " + "(phoneNumber = :phoneNumber or :phoneNumber is null)" ) Iterable<Person> find( @Param("firstName") String firstName, @Param("lastName") String lastName, @Param("phoneNumber") String phoneNumber ); 


  3. Crie métodos de pesquisa para todas as combinações possíveis de parâmetros e chame o método desejado após verificar se os parâmetros são nulos.

    Muitos métodos de localização
      @Repository public interface PersonRepo extends PagingAndSortingRepository<Person, Long> { //       Iterable<Person> phoneNumberContains(String number); Iterable<Person> lastName(String lastName); Iterable<Person> lastNameAndPhoneNumberContains(String lastName, String number); Iterable<Person> firstName(String firstName); Iterable<Person> firstNameAndPhoneNumberContains(String firstName, String number); Iterable<Person> firstNameAndLastName(String firstName, String lastName); Iterable<Person> firstNameAndLastNameAndPhoneNumberContains(String firstName, String lastName, String number); //  ,      default Iterable<Person> findByFirstNameAndLastNameAndPhoneNumberContains(String firstName, String lastName, String number) { if(firstName == null) { if(lastName == null) { if(number == null) { return findAll(); } else { return phoneNumberContains(number); } } else { if(number == null) { return lastName(lastName); } else { return lastNameAndPhoneNumberContains(lastName, number); } } } else { if(lastName == null) { if(number == null) { return firstName(firstName); } else { return firstNameAndPhoneNumberContains(firstName, number); } } else { if(number == null) { return firstNameAndLastName(firstName, lastName); } else { return firstNameAndLastNameAndPhoneNumberContains(firstName, lastName, number); } } } } } 



Não analisarei as vantagens e desvantagens de cada método, elas são óbvias. Permitam-me apenas dizer que escolhi a terceira opção com a adição de métodos de pesquisa para cada variante da combinação de parâmetros e criei uma biblioteca OpenSource que usa o mecanismo Annotation Processor e, no estágio de compilação, faz todo o trabalho para você. Para usá-lo, você deve conectar a biblioteca (consulte a versão mais recente em https://github.com/ukman/kolobok ou https://mvnrepository.com/artifact/com.github.ukman/kolobok ).

 <dependency> <groupId>com.github.ukman</groupId> <artifactId>kolobok</artifactId> <version>0.1.2</version> <scope>compile</scope> </dependency> 

Então você precisa marcar o método, que deve funcionar de uma nova maneira com a anotação @FindWithOptionalParams.

 @Repository public interface PersonRepo extends PagingAndSortingRepository<Person, Long> { @FindWithOptionalParams Iterable<Person> findByFirstNameAndLastNameAndPhoneNumberContains(String firstName, String lastName, String number); } 

A própria biblioteca irá gerar todos os métodos de pesquisa e a implementação padrão, verificando os parâmetros para null e chamando o método necessário.

PS: escreva nos comentários o que outras anotações podem simplificar seu trabalho com o Spring, talvez eu as adicione também.

Source: https://habr.com/ru/post/pt483796/


All Articles