Repositórios reativos de dados da primavera com o MongoDB
1. Introdução
Neste tutorial, veremos como configurar e implementar operações de banco de dados usando programação reativa por meio de repositórios reativos Spring Data com MongoDB.
Veremos os usos básicos deReactiveCrudRepository,ReactiveMongoRepository,, bem comoReactiveMongoTemplate.
Mesmo que essas implementações usemreactive programming, esse não é o foco principal deste tutorial.
2. Meio Ambiente
Para usar o MongoDB reativo, precisamos adicionar a dependência ao nossopom.xml.
Também adicionaremos um MongoDB incorporado para teste:
// ...
org.springframework.boot
spring-boot-starter-data-mongodb-reactive
de.flapdoodle.embed
de.flapdoodle.embed.mongo
test
3. Configuração
Para ativar o suporte reativo, precisamos usar@EnableReactiveMongoRepositories juntamente com alguma configuração de infraestrutura:
@EnableReactiveMongoRepositories
public class MongoReactiveApplication
extends AbstractReactiveMongoConfiguration {
@Bean
public MongoClient mongoClient() {
return MongoClients.create();
}
@Override
protected String getDatabaseName() {
return "reactive";
}
}
Observe que o acima seria necessário se estivéssemos usando a instalação independente do MongoDB. Mas, como estamos usando Spring Boot com MongoDB incorporado em nosso exemplo, a configuração acima não é necessária.
4. Criando umDocument
Para os exemplos abaixo, vamos criar uma classeAccount e anotar com@Document para usá-la nas operações do banco de dados:
@Document
public class Account {
@Id
private String id;
private String owner;
private Double value;
// getters and setters
}
5. Usando Repositórios Reativos
Já estamos familiarizados com orepositories programming model, com os métodos CRUD já definidos, além do suporte para algumas outras coisas comuns também.
Agora, com o modelo reativo, obtemos o mesmo conjunto de métodos e especificações, exceto que lidaremos com os resultados e parâmetros de uma forma reativa.
5.1. ReactiveCrudRepository
Podemos usar este repositório da mesma forma que o bloqueioCrudRepository:
@Repository
public interface AccountCrudRepository
extends ReactiveCrudRepository {
Flux findAllByValue(String value);
Mono findFirstByOwner(Mono owner);
}
Podemos passar diferentes tipos de argumentos como simples (String), empacotados (Optional,Stream) ou reativos (Mono,Flux), conforme podemos veja no métodofindFirstByOwner().
5.2. ReactiveMongoRepository
Há também a interfaceReactiveMongoRepository, que herda deReactiveCrudRepository e adiciona alguns novos métodos de consulta:
@Repository
public interface AccountReactiveRepository
extends ReactiveMongoRepository { }
UsandoReactiveMongoRepository, podemos consultar por exemplo:
Flux accountFlux = repository
.findAll(Example.of(new Account(null, "owner", null)));
Como resultado, obteremos cadaAccount igual ao exemplo passado.
Com nossos repositórios criados, eles já definiram métodos para realizar algumas operações de banco de dados que não precisamos implementar:
Mono accountMono
= repository.save(new Account(null, "owner", 12.3));
Mono accountMono2 = repository
.findById("123456");
5.3. RxJava2CrudRepository
ComRxJava2CrudRepository,, temos o mesmo comportamento queReactiveCrudRepository,, mas com os resultados e tipos de parâmetro deRxJava:
@Repository
public interface AccountRxJavaRepository
extends RxJava2CrudRepository {
Observable findAllByValue(Double value);
Single findFirstByOwner(Single owner);
}
5.4. Testando Nossas Operações Básicas
Para testar nossos métodos de repositório, usaremos o assinante de teste:
@Test
public void givenValue_whenFindAllByValue_thenFindAccount() {
repository.save(new Account(null, "Bill", 12.3)).block();
Flux accountFlux = repository.findAllByValue(12.3);
StepVerifier
.create(accountFlux)
.assertNext(account -> {
assertEquals("Bill", account.getOwner());
assertEquals(Double.valueOf(12.3) , account.getValue());
assertNotNull(account.getId());
})
.expectComplete()
.verify();
}
@Test
public void givenOwner_whenFindFirstByOwner_thenFindAccount() {
repository.save(new Account(null, "Bill", 12.3)).block();
Mono accountMono = repository
.findFirstByOwner(Mono.just("Bill"));
StepVerifier
.create(accountMono)
.assertNext(account -> {
assertEquals("Bill", account.getOwner());
assertEquals(Double.valueOf(12.3) , account.getValue());
assertNotNull(account.getId());
})
.expectComplete()
.verify();
}
@Test
public void givenAccount_whenSave_thenSaveAccount() {
Mono accountMono = repository.save(new Account(null, "Bill", 12.3));
StepVerifier
.create(accountMono)
.assertNext(account -> assertNotNull(account.getId()))
.expectComplete()
.verify();
}
6. ReactiveMongoTemplate
Além da abordagem de repositórios, temos oReactiveMongoTemplate.
Em primeiro lugar, precisamos registrarReactiveMongoTemplate como um bean:
@Configuration
public class ReactiveMongoConfig {
@Autowired
MongoClient mongoClient;
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate() {
return new ReactiveMongoTemplate(mongoClient, "test");
}
}
E então, podemos injetar esse bean em nosso serviço para executar as operações do banco de dados:
@Service
public class AccountTemplateOperations {
@Autowired
ReactiveMongoTemplate template;
public Mono findById(String id) {
return template.findById(id, Account.class);
}
public Flux findAll() {
return template.findAll(Account.class);
}
public Mono save(Mono account) {
return template.save(account);
}
}
ReactiveMongoTemplate também tem uma série de métodos que não se relacionam ao domínio que temos, você pode verificá-los emdocumentation.
7. Conclusão
Neste breve tutorial, cobrimos o uso de repositórios e modelos usando programação reativa com MongoDB com estrutura Spring Data Reactive Repositories.
O código-fonte completo dos exemplos está disponívelover on GitHub.