Repositórios reativos de dados de primavera com Couchbase
1. Visão geral
Neste tutorial, aprenderemos como configurar e implementar operações de banco de dados de forma reativa emCouchbase using Spring Data Repositórios.
Cobriremos os usos básicos deReactiveCrudRepository areiaReactiveSortingRepository. Além disso, configuraremos nosso aplicativo de teste comAbstractReactiveCouchbaseConfiguration.
2. Dependências do Maven
Em primeiro lugar, vamos adicionar as dependências necessárias:
io.projectreactor
reactor-core
org.springframework.boot
spring-boot-starter-data-couchbase-reactive
A dependênciaspring-boot-starter-data-couchbase-reactive contém tudo o que precisamos para operar no Couchbase usando API reativa.
Também incluiremos a dependênciareactor-core para usar a API do Project Reactor.
3. Configuração
A seguir, vamos definir as configurações de conexão entre o Couchbase e nosso aplicativo.
Vamos começar criando uma classe que conterá nossas propriedades:
@Configuration
public class CouchbaseProperties {
private List bootstrapHosts;
private String bucketName;
private String bucketPassword;
private int port;
public CouchbaseProperties(
@Value("${spring.couchbase.bootstrap-hosts}") List bootstrapHosts,
@Value("${spring.couchbase.bucket.name}") String bucketName,
@Value("${spring.couchbase.bucket.password}") String bucketPassword,
@Value("${spring.couchbase.port}") int port) {
this.bootstrapHosts = Collections.unmodifiableList(bootstrapHosts);
this.bucketName = bucketName;
this.bucketPassword = bucketPassword;
this.port = port;
}
// getters
}
Para usar o suporte reativo, devemos criar a classe de configuração que estenderáAbstractReactiveCouchbaseConfiguration:
@Configuration
@EnableReactiveCouchbaseRepositories("com.example.couchbase.domain.repository")
public class ReactiveCouchbaseConfiguration extends AbstractReactiveCouchbaseConfiguration {
private CouchbaseProperties couchbaseProperties;
public ReactiveCouchbaseConfiguration(CouchbaseProperties couchbaseProperties) {
this.couchbaseProperties = couchbaseProperties;
}
@Override
protected List getBootstrapHosts() {
return couchbaseProperties.getBootstrapHosts();
}
@Override
protected String getBucketName() {
return couchbaseProperties.getBucketName();
}
@Override
protected String getBucketPassword() {
return couchbaseProperties.getBucketPassword();
}
@Override
public CouchbaseEnvironment couchbaseEnvironment() {
return DefaultCouchbaseEnvironment
.builder()
.bootstrapHttpDirectPort(couchbaseProperties.getPort())
.build();
}
}
Além disso, usamos@EnableReactiveCouchbaseRepositories para habilitar nossos repositórios reativos que estarão no pacote especificado.
Além disso, substituímoscouchbaseEnvironment() para passar a porta de conexão Couchbase.
4. Repositórios
Nesta seção, aprenderemos como criar e usar o repositório reativo. By default, the “all” view is backing most CRUD operations. The custom repository methods are backed by N1QL. Se o cluster não suportar N1QL, oUnsupportedCouchbaseFeatureException será lançado durante a inicialização.
Em primeiro lugar, vamos criar a classe POJO com a qual nossos repositórios trabalharão:
@Document
public class Person {
@Id private UUID id;
private String firstName;
//getters and setters
}
4.1. Repositório com base em exibição
Agora, vamos criar um repositório paraPerson:
@Repository
@ViewIndexed(designDoc = ViewPersonRepository.DESIGN_DOCUMENT)
public interface ViewPersonRepository extends ReactiveCrudRepository {
String DESIGN_DOCUMENT = "person";
}
O repositório estende a interfaceReactiveCrudRepository para usar a API do Reactor para interagir com o Couchbase.
Além disso, podemos adicionar um método personalizado e usar a anotação@View para torná-lo baseado em visualização:
@View(designDocument = ViewPersonRepository.DESIGN_DOCUMENT)
Flux findByFirstName(String firstName);
Por padrão, a consulta procurará uma visualização chamadabyFirstName. Se quisermos fornecer um nome de visualização personalizado, teremos que usar o argumentoviewName.
Por último, vamos criar um teste CRUD simples com a ajuda de um assinante de teste:
@Test
public void shouldSavePerson_findById_thenDeleteIt() {
final UUID id = UUID.randomUUID();
final Person person = new Person(id, "John");
personRepository
.save(person)
.subscribe();
final Mono byId = personRepository.findById(id);
StepVerifier
.create(byId)
.expectNextMatches(result -> result
.getId()
.equals(id))
.expectComplete()
.verify();
personRepository
.delete(person)
.subscribe();
}
4.2. N1QL/View-Based Repository
Agora, vamos criar o repositório reativo paraPerson que usará as consultas N1QL:
@Repository
@N1qlPrimaryIndexed
public interface N1QLPersonRepository extends ReactiveCrudRepository {
Flux findAllByFirstName(String firstName);
}
O repositório estende oReactiveCrudRepository para usar a API do Reactor também. Além disso, adicionamos um métodofindAllByFirstName personalizado, que cria a consulta baseada em N1QL.
Depois disso, vamos adicionar o teste para o métodofindAllByFirstName:
@Test
public void shouldFindAll_byLastName() {
final String firstName = "John";
final Person matchingPerson = new Person(UUID.randomUUID(), firstName);
final Person nonMatchingPerson = new Person(UUID.randomUUID(), "NotJohn");
personRepository
.save(matchingPerson)
.subscribe();
personRepository
.save(nonMatchingPerson)
.subscribe();
final Flux allByFirstName = personRepository.findAllByFirstName(firstName);
StepVerifier
.create(allByFirstName)
.expectNext(matchingPerson)
.verifyComplete();
}
Além disso, vamos criar um repositório que nos permite recuperar pessoas usando a abstração de classificação:
@Repository
public interface N1QLSortingPersonRepository extends ReactiveSortingRepository {
Flux findAllByFirstName(String firstName, Sort sort);
}
Por último, vamos escrever um teste para verificar se os dados estão realmente classificados:
@Test
public void shouldFindAll_sortedByFirstName() {
final Person firstPerson = new Person(UUID.randomUUID(), "John");
final Person secondPerson = new Person(UUID.randomUUID(), "Mikki");
personRepository
.save(firstPerson)
.subscribe();
personRepository
.save(secondPerson)
.subscribe();
final Flux allByFirstName = personRepository
.findAll(Sort.by(Sort.Direction.DESC, "firstName"));
StepVerifier
.create(allByFirstName)
.expectNextMatches(person -> person
.getFirstName()
.equals(secondPerson.getFirstName()))
.expectNextMatches(person -> person
.getFirstName()
.equals(firstPerson.getFirstName()))
.verifyComplete();
}
5. Conclusão
Neste artigo, aprendemos como usar repositórios usando programação reativa com Couchbase e estrutura Spring Data Reactive.
Como sempre, o código para esses exemplos está disponívelover on Github.